summaryrefslogtreecommitdiffstats
path: root/docs/events/Conferences/OSCON/index.rst
blob: a3a9cdbc6b488ff8c10d00acb9cc72a91baf6d7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
.. _OSCON:

.. toctree::

################
May 2017 - OSCON
################

.. toctree::
    :maxdepth: 1

    2017_05_11_40gbpsipsec.rst
    
*/ .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ .highlight .kr { color: #66d9ef } /* Keyword.Reserved */ .highlight .kt { color: #66d9ef } /* Keyword.Type */ .highlight .ld { color: #e6db74 } /* Literal.Date */ .highlight .m { color: #ae81ff } /* Literal.Number */ .highlight .s { color: #e6db74 } /* Literal.String */ .highlight .na { color: #a6e22e } /* Name.Attribute */ .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ .highlight .nc { color: #a6e22e } /* Name.Class */ .highlight .no { color: #66d9ef } /* Name.Constant */ .highlight .nd { color: #a6e22e } /* Name.Decorator */ .highlight .ni { color: #f8f8f2 } /* Name.Entity */ .highlight .ne { color: #a6e22e } /* Name.Exception */ .highlight .nf { color: #a6e22e } /* Name.Function */ .highlight .nl { color: #f8f8f2 } /* Name.Label */ .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ .highlight .nx { color: #a6e22e } /* Name.Other */ .highlight .py { color: #f8f8f2 } /* Name.Property */ .highlight .nt { color: #f92672 } /* Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
# Copyright (c) 2018 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

*** Settings ***
| Library | resources.libraries.python.IPv4Util.IPv4Util
| Library | resources.libraries.python.InterfaceUtil
| Library | resources.libraries.python.tcp.TCPUtils
| Resource | resources/libraries/robot/ip/ip4.robot
| ...
| Documentation | L2 keywords to set up VPP to test tcp.

*** Keywords ***
| Create base startup configuration of VPP for TCP tests on all DUTs
| | [Documentation] | Create base startup configuration of VPP for TCP related
| | ... | tests to all DUTs.
| | ...
| | ${duts}= | Get Matches | ${nodes} | DUT*
| | :FOR | ${dut} | IN | @{duts}
| | | Import Library | resources.libraries.python.VppConfigGenerator
| | | ... | WITH NAME | ${dut}
| | | Run keyword | ${dut}.Set Node |  ${nodes['${dut}']}
| | | Run keyword | ${dut}.Add Unix Log
| | | Run keyword | ${dut}.Add Unix CLI Listen
| | | Run keyword | ${dut}.Add Unix Nodaemon
| | | Run keyword | ${dut}.Add DPDK Socketmem | 4096,4096
| | | Run keyword | ${dut}.Add DPDK Log Level | debug
| | | Run keyword | ${dut}.Add DPDK Uio Driver | ${uio_driver}
| | | Run keyword | ${dut}.Add Heapsize | 4G
| | | Run keyword | ${dut}.Add Plugin | disable | default
| | | Run keyword | ${dut}.Add Plugin | enable | @{plugins_to_enable}
| | | Run keyword | ${dut}.Add IP6 Hash Buckets | 2000000
| | | Run keyword | ${dut}.Add IP6 Heap Size | 4G
| | | Run keyword | ${dut}.Add IP Heap Size | 4G

| Set up HTTP server with paramters on the VPP node
| | [Documentation]
| | ... | Configure IP address on the port, set it up and start HTTP server on
| | ... | the VPP.
| | ...
| | ... | *Arguments:*
| | ... | - ${prealloc_fifos} - Max number of connections you expect to handle
| | ... | at one time. Type: string
| | ... | - ${fifo_size} - FIFO size in kB. Type: string
| | ... | - ${private_segment_size} - Private segment size. Number + unit.
| | ... | Type: string
| | ...
| | ... | *Example:*
| | ...
| | ... | \| Set up HTTP server with paramters on the VPP node \| 400 \| 4096\
| | ... | \| 2g \|
| | ...
| | [Arguments] | ${prealloc_fifos} | ${fifo_size} | ${private_segment_size}
| | ...
| | Set Interface State | ${dut1} | ${dut1_if1} | up
| | Set Interface Address | ${dut1} | ${dut1_if1} | 192.168.10.2 | 24
| | Set Interface Address | ${dut1} | ${dut1_if1} | 192.168.20.2 | 24
| | Set Interface Address | ${dut1} | ${dut1_if1} | 192.168.30.2 | 24
| | Set Interface Address | ${dut1} | ${dut1_if1} | 192.168.40.2 | 24
| | Set Interface Address | ${dut1} | ${dut1_if1} | 192.168.50.2 | 24
| | Set Interface Address | ${dut1} | ${dut1_if1} | 192.168.60.2 | 24
| | Set Interface Address | ${dut1} | ${dut1_if1} | 192.168.70.2 | 24
| | Set Interface Address | ${dut1} | ${dut1_if1} | 192.168.80.2 | 24
| | Vpp Node Interfaces Ready Wait | ${dut1}
| | Start HTTP server params | ${dut1} | ${prealloc_fifos} | ${fifo_size}
| | ... | ${private_segment_size}
| | Sleep | 30
g */ }
/*
  Copyright (c) 2013 Cisco and/or its affiliates.

  * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

#include <vppinfra/pfhash.h>
#include <vppinfra/format.h>

/* This is incredibly handy when debugging */
u32 vl (void *v) __attribute__ ((weak));
u32
vl (void *v)
{
  return vec_len (v);
}

#if defined(CLIB_HAVE_VEC128) && ! defined (__ALTIVEC__)

typedef struct
{
  u8 *key[16];
  u64 value;
} pfhash_show_t;

static int
sh_compare (pfhash_show_t * sh0, pfhash_show_t * sh1)
{
  return ((i32) (sh0->value) - ((i32) sh1->value));
}

u8 *
format_pfhash (u8 * s, va_list * args)
{
  pfhash_t *p = va_arg (*args, pfhash_t *);
  int verbose = va_arg (*args, int);

  if (p == 0 || p->overflow_hash == 0 || p->buckets == 0)
    {
      s = format (s, "*** uninitialized ***");
      return s;
    }

  s = format (s, "Prefetch hash '%s'\n", p->name);
  s =
    format (s, " %d buckets, %u bucket overflows, %.1f%% bucket overflow \n",
	    vec_len (p->buckets), p->overflow_count,
	    100.0 * ((f64) p->overflow_count) / ((f64) vec_len (p->buckets)));
  if (p->nitems)
    s =
      format (s,
	      "  %u items, %u items in overflow, %.1f%% items in overflow\n",
	      p->nitems, p->nitems_in_overflow,
	      100.0 * ((f64) p->nitems_in_overflow) / ((f64) p->nitems));

  if (verbose)
    {
      pfhash_show_t *shs = 0, *sh;
      hash_pair_t *hp;
      int i, j;

      for (i = 0; i < vec_len (p->buckets); i++)
	{
	  pfhash_kv_t *kv;
	  pfhash_kv_16_t *kv16;
	  pfhash_kv_8_t *kv8;
	  pfhash_kv_8v8_t *kv8v8;
	  pfhash_kv_4_t *kv4;

	  if (p->buckets[i] == 0 || p->buckets[i] == PFHASH_BUCKET_OVERFLOW)
	    continue;

	  kv = pool_elt_at_index (p->kvp, p->buckets[i]);

	  switch (p->key_size)
	    {
	    case 16:
	      kv16 = &kv->kv16;
	      for (j = 0; j < 3; j++)
		{
		  if (kv16->values[j] != (u32) ~ 0)
		    {
		      vec_add2 (shs, sh, 1);
		      clib_memcpy (sh->key, &kv16->kb.k_u32x4[j],
				   p->key_size);
		      sh->value = kv16->values[j];
		    }
		}
	      break;
	    case 8:
	      if (p->value_size == 4)
		{
		  kv8 = &kv->kv8;
		  for (j = 0; j < 5; j++)
		    {
		      if (kv8->values[j] != (u32) ~ 0)
			{
			  vec_add2 (shs, sh, 1);
			  clib_memcpy (sh->key, &kv8->kb.k_u64[j],
				       p->key_size);
			  sh->value = kv8->values[j];
			}
		    }
		}
	      else
		{
		  kv8v8 = &kv->kv8v8;
		  for (j = 0; j < 4; j++)
		    {
		      if (kv8v8->values[j] != (u64) ~ 0)
			{
			  vec_add2 (shs, sh, 1);
			  clib_memcpy (sh->key, &kv8v8->kb.k_u64[j],
				       p->key_size);
			  sh->value = kv8v8->values[j];
			}
		    }

		}
	      break;
	    case 4:
	      kv4 = &kv->kv4;
	      for (j = 0; j < 8; j++)
		{
		  if (kv4->values[j] != (u32) ~ 0)
		    {
		      vec_add2 (shs, sh, 1);
		      clib_memcpy (sh->key, &kv4->kb.kb[j], p->key_size);
		      sh->value = kv4->values[j];
		    }
		}
	      break;
	    }
	}

      /* *INDENT-OFF* */
      hash_foreach_pair (hp, p->overflow_hash,
      ({
        vec_add2 (shs, sh, 1);
        clib_memcpy (sh->key, (u8 *)hp->key, p->key_size);
        sh->value = hp->value[0];
      }));
      /* *INDENT-ON* */

      vec_sort_with_function (shs, sh_compare);

      for (i = 0; i < vec_len (shs); i++)
	{
	  sh = vec_elt_at_index (shs, i);
	  s = format (s, " %U value %u\n", format_hex_bytes, sh->key,
		      p->key_size, sh->value);
	}
      vec_free (shs);
    }
  return s;
}


void abort (void);

void
pfhash_init (pfhash_t * p, char *name, u32 key_size, u32 value_size,
	     u32 nbuckets)
{
  pfhash_kv_t *kv;
  memset (p, 0, sizeof (*p));
  u32 key_bytes;

  switch (key_size)
    {
    case 4:
      key_bytes = 4;
      break;
    case 8:
      key_bytes = 8;
      break;
    case 16:
      key_bytes = 16;
      break;
    default:
      ASSERT (0);
      abort ();
    }

  switch (value_size)
    {
    case 4:
    case 8:
      break;
    default:
      ASSERT (0);
      abort ();
    }


  p->name = format (0, "%s", name);
  vec_add1 (p->name, 0);
  p->overflow_hash = hash_create_mem (0, key_bytes, sizeof (uword));

  nbuckets = 1 << (max_log2 (nbuckets));

  /* This sets the entire bucket array to zero */
  vec_validate (p->buckets, nbuckets - 1);
  p->key_size = key_size;
  p->value_size = value_size;

  /*
   * Unset buckets implicitly point at the 0th pool elt.
   * All search routines will return ~0 if they go there.
   */
  pool_get_aligned (p->kvp, kv, 16);
  memset (kv, 0xff, sizeof (*kv));
}

static pfhash_kv_16_t *
pfhash_get_kv_16 (pfhash_t * p, u32 bucket_contents,
		  u32x4 * key, u32 * match_index)
{
  u32x4 diff[3];
  u32 is_equal[3];
  pfhash_kv_16_t *kv = 0;

  *match_index = (u32) ~ 0;

  kv = &p->kvp[bucket_contents].kv16;

  diff[0] = u32x4_sub (kv->kb.k_u32x4[0], key[0]);
  diff[1] = u32x4_sub (kv->kb.k_u32x4[1], key[0]);
  diff[2] = u32x4_sub (kv->kb.k_u32x4[2], key[0]);

  is_equal[0] = u32x4_zero_byte_mask (diff[0]) == 0xffff;
  is_equal[1] = u32x4_zero_byte_mask (diff[1]) == 0xffff;
  is_equal[2] = u32x4_zero_byte_mask (diff[2]) == 0xffff;

  if (is_equal[0])
    *match_index = 0;
  if (is_equal[1])
    *match_index = 1;
  if (is_equal[2])
    *match_index = 2;

  return kv;
}

static pfhash_kv_8_t *
pfhash_get_kv_8 (pfhash_t * p, u32 bucket_contents,
		 u64 * key, u32 * match_index)
{
  pfhash_kv_8_t *kv;

  *match_index = (u32) ~ 0;

  kv = &p->kvp[bucket_contents].kv8;

  if (kv->kb.k_u64[0] == key[0])
    *match_index = 0;
  if (kv->kb.k_u64[1] == key[0])
    *match_index = 1;
  if (kv->kb.k_u64[2] == key[0])
    *match_index = 2;
  if (kv->kb.k_u64[3] == key[0])
    *match_index = 3;
  if (kv->kb.k_u64[4] == key[0])
    *match_index = 4;

  return kv;
}

static pfhash_kv_8v8_t *
pfhash_get_kv_8v8 (pfhash_t * p,
		   u32 bucket_contents, u64 * key, u32 * match_index)
{
  pfhash_kv_8v8_t *kv;

  *match_index = (u32) ~ 0;

  kv = &p->kvp[bucket_contents].kv8v8;

  if (kv->kb.k_u64[0] == key[0])
    *match_index = 0;
  if (kv->kb.k_u64[1] == key[0])
    *match_index = 1;
  if (kv->kb.k_u64[2] == key[0])
    *match_index = 2;
  if (kv->kb.k_u64[3] == key[0])
    *match_index = 3;

  return kv;
}

static pfhash_kv_4_t *
pfhash_get_kv_4 (pfhash_t * p, u32 bucket_contents,
		 u32 * key, u32 * match_index)
{
  u32x4 vector_key;
  u32x4 is_equal[2];
  u32 zbm[2], winner_index;
  pfhash_kv_4_t *kv;

  *match_index = (u32) ~ 0;

  kv = &p->kvp[bucket_contents].kv4;

  vector_key = u32x4_splat (key[0]);

  is_equal[0] = u32x4_is_equal (kv->kb.k_u32x4[0], vector_key);
  is_equal[1] = u32x4_is_equal (kv->kb.k_u32x4[1], vector_key);
  zbm[0] = ~u32x4_zero_byte_mask (is_equal[0]) & 0xFFFF;
  zbm[1] = ~u32x4_zero_byte_mask (is_equal[1]) & 0xFFFF;

  if (PREDICT_FALSE ((zbm[0] == 0) && (zbm[1] == 0)))
    return kv;

  winner_index = min_log2 (zbm[0]) >> 2;
  winner_index = zbm[1] ? (4 + (min_log2 (zbm[1]) >> 2)) : winner_index;

  *match_index = winner_index;
  return kv;
}

static pfhash_kv_t *
pfhash_get_internal (pfhash_t * p, u32 bucket_contents,
		     void *key, u32 * match_index)
{
  pfhash_kv_t *kv = 0;

  switch (p->key_size)
    {
    case 16:
      kv =
	(pfhash_kv_t *) pfhash_get_kv_16 (p, bucket_contents, key,
					  match_index);
      break;
    case 8:
      if (p->value_size == 4)
	kv = (pfhash_kv_t *) pfhash_get_kv_8 (p, bucket_contents,
					      key, match_index);
      else
	kv = (pfhash_kv_t *) pfhash_get_kv_8v8 (p, bucket_contents,
						key, match_index);
      break;
    case 4:
      kv =
	(pfhash_kv_t *) pfhash_get_kv_4 (p, bucket_contents, key,
					 match_index);
      break;
    default:
      ASSERT (0);
    }
  return kv;
}

u64
pfhash_get (pfhash_t * p, u32 bucket, void *key)
{
  pfhash_kv_t *kv;
  u32 match_index = ~0;
  pfhash_kv_16_t *kv16;
  pfhash_kv_8_t *kv8;
  pfhash_kv_8v8_t *kv8v8;
  pfhash_kv_4_t *kv4;

  u32 bucket_contents = pfhash_read_bucket_prefetch_kv (p, bucket);

  if (bucket_contents == PFHASH_BUCKET_OVERFLOW)
    {
      uword *hp;

      hp = hash_get_mem (p->overflow_hash, key);
      if (hp)
	return hp[0];
      return (u64) ~ 0;
    }

  kv = pfhash_get_internal (p, bucket_contents, key, &match_index);
  if (match_index == (u32) ~ 0)
    return (u64) ~ 0;

  kv16 = (void *) kv;
  kv8 = (void *) kv;
  kv4 = (void *) kv;
  kv8v8 = (void *) kv;

  switch (p->key_size)
    {
    case 16:
      return (kv16->values[match_index] == (u32) ~ 0)
	? (u64) ~ 0 : (u64) kv16->values[match_index];
    case 8:
      if (p->value_size == 4)
	return (kv8->values[match_index] == (u32) ~ 0)
	  ? (u64) ~ 0 : (u64) kv8->values[match_index];
      else
	return kv8v8->values[match_index];
    case 4:
      return (kv4->values[match_index] == (u32) ~ 0)
	? (u64) ~ 0 : (u64) kv4->values[match_index];
    default:
      ASSERT (0);
    }
  return (u64) ~ 0;
}

void
pfhash_set (pfhash_t * p, u32 bucket, void *key, void *value)
{
  u32 bucket_contents = pfhash_read_bucket_prefetch_kv (p, bucket);
  u32 match_index = (u32) ~ 0;
  pfhash_kv_t *kv;
  pfhash_kv_16_t *kv16;
  pfhash_kv_8_t *kv8;
  pfhash_kv_8v8_t *kv8v8;
  pfhash_kv_4_t *kv4;
  int i;
  u8 *kcopy;

  if (bucket_contents == PFHASH_BUCKET_OVERFLOW)
    {
      hash_pair_t *hp;
      hp = hash_get_pair_mem (p->overflow_hash, key);
      if (hp)
	{
	  clib_warning ("replace value 0x%08x with value 0x%08x",
			hp->value[0], (u64) value);
	  hp->value[0] = (u64) value;
	  return;
	}
      kcopy = clib_mem_alloc (p->key_size);
      clib_memcpy (kcopy, key, p->key_size);
      hash_set_mem (p->overflow_hash, kcopy, value);
      p->nitems++;
      p->nitems_in_overflow++;
      return;
    }

  if (bucket_contents == 0)
    {
      pool_get_aligned (p->kvp, kv, 16);
      memset (kv, 0xff, sizeof (*kv));
      p->buckets[bucket] = kv - p->kvp;
    }
  else
    kv = pfhash_get_internal (p, bucket_contents, key, &match_index);

  kv16 = (void *) kv;
  kv8 = (void *) kv;
  kv8v8 = (void *) kv;
  kv4 = (void *) kv;

  p->nitems++;

  if (match_index != (u32) ~ 0)
    {
      switch (p->key_size)
	{
	case 16:
	  kv16->values[match_index] = (u32) (u64) value;
	  return;

	case 8:
	  if (p->value_size == 4)
	    kv8->values[match_index] = (u32) (u64) value;
	  else
	    kv8v8->values[match_index] = (u64) value;
	  return;

	case 4:
	  kv4->values[match_index] = (u64) value;
	  return;

	default:
	  ASSERT (0);
	}
    }

  switch (p->key_size)
    {
    case 16:
      for (i = 0; i < 3; i++)
	{
	  if (kv16->values[i] == (u32) ~ 0)
	    {
	      clib_memcpy (&kv16->kb.k_u32x4[i], key, p->key_size);
	      kv16->values[i] = (u32) (u64) value;
	      return;
	    }
	}
      /* copy bucket contents to overflow hash tbl */
      for (i = 0; i < 3; i++)
	{
	  kcopy = clib_mem_alloc (p->key_size);
	  clib_memcpy (kcopy, &kv16->kb.k_u32x4[i], p->key_size);
	  hash_set_mem (p->overflow_hash, kcopy, kv16->values[i]);
	  p->nitems_in_overflow++;
	}
      /* Add new key to overflow */
      kcopy = clib_mem_alloc (p->key_size);
      clib_memcpy (kcopy, key, p->key_size);
      hash_set_mem (p->overflow_hash, kcopy, value);
      p->buckets[bucket] = PFHASH_BUCKET_OVERFLOW;
      p->overflow_count++;
      p->nitems_in_overflow++;
      return;

    case 8:
      if (p->value_size == 4)
	{
	  for (i = 0; i < 5; i++)
	    {
	      if (kv8->values[i] == (u32) ~ 0)
		{
		  clib_memcpy (&kv8->kb.k_u64[i], key, 8);
		  kv8->values[i] = (u32) (u64) value;
		  return;
		}
	    }
	  /* copy bucket contents to overflow hash tbl */
	  for (i = 0; i < 5; i++)
	    {
	      kcopy = clib_mem_alloc (p->key_size);
	      clib_memcpy (kcopy, &kv8->kb.k_u64[i], 8);
	      hash_set_mem (p->overflow_hash, kcopy, kv8->values[i]);
	      p->nitems_in_overflow++;
	    }
	}
      else
	{
	  for (i = 0; i < 4; i++)
	    {
	      if (kv8v8->values[i] == (u64) ~ 0)
		{
		  clib_memcpy (&kv8v8->kb.k_u64[i], key, 8);
		  kv8v8->values[i] = (u64) value;
		  return;
		}
	    }
	  /* copy bucket contents to overflow hash tbl */
	  for (i = 0; i < 4; i++)
	    {
	      kcopy = clib_mem_alloc (p->key_size);
	      clib_memcpy (kcopy, &kv8v8->kb.k_u64[i], 8);
	      hash_set_mem (p->overflow_hash, kcopy, kv8v8->values[i]);
	      p->nitems_in_overflow++;
	    }

	}
      /* Add new key to overflow */
      kcopy = clib_mem_alloc (p->key_size);
      clib_memcpy (kcopy, key, p->key_size);
      hash_set_mem (p->overflow_hash, kcopy, value);
      p->buckets[bucket] = PFHASH_BUCKET_OVERFLOW;
      p->overflow_count++;
      p->nitems_in_overflow++;
      return;

    case 4:
      for (i = 0; i < 8; i++)
	{
	  if (kv4->values[i] == (u32) ~ 0)
	    {
	      clib_memcpy (&kv4->kb.kb[i], key, 4);
	      kv4->values[i] = (u32) (u64) value;
	      return;
	    }
	}
      /* copy bucket contents to overflow hash tbl */
      for (i = 0; i < 8; i++)
	{
	  kcopy = clib_mem_alloc (p->key_size);
	  clib_memcpy (kcopy, &kv4->kb.kb[i], 4);
	  hash_set_mem (p->overflow_hash, kcopy, kv4->values[i]);
	  p->nitems_in_overflow++;
	}
      /* Add new key to overflow */
      kcopy = clib_mem_alloc (p->key_size);
      clib_memcpy (kcopy, key, p->key_size);
      hash_set_mem (p->overflow_hash, kcopy, value);
      p->buckets[bucket] = PFHASH_BUCKET_OVERFLOW;
      p->overflow_count++;
      p->nitems_in_overflow++;
      return;

    default:
      ASSERT (0);
    }
}

void
pfhash_unset (pfhash_t * p, u32 bucket, void *key)
{
  u32 bucket_contents = pfhash_read_bucket_prefetch_kv (p, bucket);
  u32 match_index = (u32) ~ 0;
  pfhash_kv_t *kv;
  pfhash_kv_16_t *kv16;
  pfhash_kv_8_t *kv8;
  pfhash_kv_8v8_t *kv8v8;
  pfhash_kv_4_t *kv4;
  void *oldkey;

  if (bucket_contents == PFHASH_BUCKET_OVERFLOW)
    {
      hash_pair_t *hp;
      hp = hash_get_pair_mem (p->overflow_hash, key);
      if (hp)
	{
	  oldkey = (void *) hp->key;
	  hash_unset_mem (p->overflow_hash, key);
	  clib_mem_free (oldkey);
	  p->nitems--;
	  p->nitems_in_overflow--;
	}
      return;
    }

  kv = pfhash_get_internal (p, bucket_contents, key, &match_index);
  if (match_index == (u32) ~ 0)
    return;

  p->nitems--;

  kv16 = (void *) kv;
  kv8 = (void *) kv;
  kv8v8 = (void *) kv;
  kv4 = (void *) kv;

  switch (p->key_size)
    {
    case 16:
      kv16->values[match_index] = (u32) ~ 0;
      return;

    case 8:
      if (p->value_size == 4)
	kv8->values[match_index] = (u32) ~ 0;
      else
	kv8v8->values[match_index] = (u64) ~ 0;
      return;

    case 4:
      kv4->values[match_index] = (u32) ~ 0;
      return;

    default:
      ASSERT (0);
    }
}

void
pfhash_free (pfhash_t * p)
{
  hash_pair_t *hp;
  int i;
  u8 **keys = 0;

  vec_free (p->name);

  pool_free (p->kvp);

  /* *INDENT-OFF* */
  hash_foreach_pair (hp, p->overflow_hash,
  ({
    vec_add1 (keys, (u8 *)hp->key);
  }));
  /* *INDENT-ON* */
  hash_free (p->overflow_hash);
  for (i = 0; i < vec_len (keys); i++)
    vec_free (keys[i]);
  vec_free (keys);
}

#endif

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */