summaryrefslogtreecommitdiffstats
path: root/nsh-plugin/nsh
diff options
context:
space:
mode:
Diffstat (limited to 'nsh-plugin/nsh')
-rw-r--r--nsh-plugin/nsh/nsh.api10
-rw-r--r--nsh-plugin/nsh/nsh.c902
-rw-r--r--nsh-plugin/nsh/nsh.h124
-rw-r--r--nsh-plugin/nsh/nsh_packet.h25
-rw-r--r--nsh-plugin/nsh/nsh_test.c12
5 files changed, 890 insertions, 183 deletions
diff --git a/nsh-plugin/nsh/nsh.api b/nsh-plugin/nsh/nsh.api
index 8ee4943..ee3f91f 100644
--- a/nsh-plugin/nsh/nsh.api
+++ b/nsh-plugin/nsh/nsh.api
@@ -13,7 +13,7 @@
@param c2 - 32bit Metadata type1 field (context2)
@param c3 - 32bit Metadata type1 field (context3)
@param c4 - 32bit Metadata type1 field (context4)
- @param tlvs - Metadata Type 2 only, Type Length Value metadata. Not currently supported
+ @param tlvs - Metadata Type 2 only, Type Length Value metadata.
*/
define nsh_add_del_entry {
u32 client_index;
@@ -28,8 +28,8 @@ define nsh_add_del_entry {
u32 c2;
u32 c3;
u32 c4;
- u32 tlv_length;
- u8 tlv[tlv_length];
+ u8 tlv_length;
+ u8 tlv[248];
};
/** \brief Reply from adding NSH entry (nsh_add_del_entry)
@@ -61,8 +61,8 @@ define nsh_entry_details {
u32 c2;
u32 c3;
u32 c4;
- u32 tlv_length;
- u8 tlv[tlv_length];
+ u8 tlv_length;
+ u8 tlv[248];
};
/** \brief Set or delete a mapping from one NSH header to another and its egress (decap to inner packet, encap NSH with outer header)
diff --git a/nsh-plugin/nsh/nsh.c b/nsh-plugin/nsh/nsh.c
index 86fc88d..1699126 100644
--- a/nsh-plugin/nsh/nsh.c
+++ b/nsh-plugin/nsh/nsh.c
@@ -109,30 +109,202 @@ VLIB_PLUGIN_REGISTER () = {
};
/* *INDENT-ON* */
+ /* Uses network order's class and type to register */
+int
+nsh_md2_register_option (u16 class,
+ u8 type,
+ u8 option_size,
+ int add_options (u8 * opt,
+ u8 * opt_size),
+ int options(vlib_buffer_t * b,
+ nsh_tlv_header_t * opt),
+ int swap_options (vlib_buffer_t * b,
+ nsh_tlv_header_t * old_opt,
+ nsh_tlv_header_t * new_opt),
+ int pop_options (vlib_buffer_t * b,
+ nsh_tlv_header_t * opt),
+ u8 * trace (u8 * s,
+ nsh_tlv_header_t * opt))
+{
+ nsh_main_t *nm = &nsh_main;
+ nsh_option_map_by_key_t key, *key_copy;
+ uword *p;
+ nsh_option_map_t *nsh_option;
+
+ key.class = class;
+ key.type = type;
+ key.pad = 0;
+
+ p = hash_get_mem(nm->nsh_option_map_by_key, &key);
+ /* Already registered */
+ if (p != 0)
+ {
+ return (-1);
+ }
+
+ pool_get_aligned (nm->nsh_option_mappings, nsh_option, CLIB_CACHE_LINE_BYTES);
+ memset (nsh_option, 0, sizeof (*nsh_option));
+ nsh_option->option_id = nsh_option - nm->nsh_option_mappings;
+
+ key_copy = clib_mem_alloc (sizeof (*key_copy));
+ clib_memcpy (key_copy, &key, sizeof (*key_copy));
+ hash_set_mem (nm->nsh_option_map_by_key, key_copy,
+ nsh_option - nm->nsh_option_mappings);
+
+ if(option_size > (MAX_NSH_OPTION_LEN + sizeof(nsh_tlv_header_t)) )
+ {
+ return (-1);
+ }
+ nm->options_size[nsh_option->option_id] = option_size;
+ nm->add_options[nsh_option->option_id] = add_options;
+ nm->options[nsh_option->option_id] = options;
+ nm->swap_options[nsh_option->option_id] = swap_options;
+ nm->pop_options[nsh_option->option_id] = pop_options;
+ nm->trace[nsh_option->option_id] = trace;
+
+ return (0);
+}
+
+/* Uses network order's class and type to lookup */
+nsh_option_map_t *
+nsh_md2_lookup_option (u16 class, u8 type)
+{
+ nsh_main_t *nm = &nsh_main;
+ nsh_option_map_by_key_t key;
+ uword *p;
+
+ key.class = class;
+ key.type = type;
+ key.pad = 0;
+
+ p = hash_get_mem(nm->nsh_option_map_by_key, &key);
+ /* not registered */
+ if (p == 0)
+ {
+ return NULL;
+ }
+
+ return pool_elt_at_index(nm->nsh_option_mappings, p[0]);
+
+}
+
+/* Uses network order's class and type to unregister */
+int
+nsh_md2_unregister_option (u16 class,
+ u8 type,
+ int options(vlib_buffer_t * b,
+ nsh_tlv_header_t * opt),
+ u8 * trace (u8 * s,
+ nsh_tlv_header_t * opt))
+{
+ nsh_main_t *nm = &nsh_main;
+ nsh_option_map_by_key_t key, *key_copy;
+ uword *p;
+ hash_pair_t *hp;
+ nsh_option_map_t *nsh_option;
+
+ key.class = class;
+ key.type = type;
+ key.pad = 0;
+
+ p = hash_get_mem(nm->nsh_option_map_by_key, &key);
+ /* not registered */
+ if (p == 0)
+ {
+ return (-1);
+ }
+
+ nsh_option = pool_elt_at_index(nm->nsh_option_mappings, p[0]);
+ nm->options[nsh_option->option_id] = NULL;
+ nm->add_options[nsh_option->option_id] = NULL;
+ nm->pop_options[nsh_option->option_id] = NULL;
+ nm->trace[nsh_option->option_id] = NULL;
+
+ hp = hash_get_pair (nm->nsh_option_map_by_key, &key);
+ key_copy = (void *)(hp->key);
+ hash_unset_mem (nm->nsh_option_map_by_key, &key_copy);
+ clib_mem_free (key_copy);
+
+ pool_put (nm->nsh_option_mappings, nsh_option);
+
+ return (0);
+}
+
typedef struct {
- nsh_header_t nsh_header;
+ u8 trace_data[256];
} nsh_input_trace_t;
+/* format from network order */
u8 * format_nsh_header (u8 * s, va_list * args)
{
- nsh_header_t * nsh = va_arg (*args, nsh_header_t *);
-
- s = format (s, "nsh ver %d ", (nsh->ver_o_c>>6));
- if (nsh->ver_o_c & NSH_O_BIT)
+ nsh_main_t *nm = &nsh_main;
+ nsh_md2_data_t *opt0;
+ nsh_md2_data_t *limit0;
+ nsh_option_map_t *nsh_option;
+ u8 option_len = 0;
+
+ u8 * header = va_arg (*args, u8 *);
+ nsh_base_header_t * nsh_base = (nsh_base_header_t *) header ;
+ nsh_md1_data_t * nsh_md1 = (nsh_md1_data_t *)(nsh_base + 1);
+ nsh_md2_data_t * nsh_md2 = (nsh_md2_data_t *)(nsh_base + 1);
+ opt0 = (nsh_md2_data_t *)nsh_md2;
+ limit0 = (nsh_md2_data_t *) ((u8 *) nsh_md2 +
+ (nsh_base->length*4-sizeof(nsh_base_header_t)) );
+
+ s = format (s, "nsh ver %d ", (nsh_base->ver_o_c>>6));
+ if (nsh_base->ver_o_c & NSH_O_BIT)
s = format (s, "O-set ");
- if (nsh->ver_o_c & NSH_C_BIT)
+ if (nsh_base->ver_o_c & NSH_C_BIT)
s = format (s, "C-set ");
s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
- nsh->length, nsh->length * 4, nsh->md_type, nsh->next_protocol);
+ nsh_base->length, nsh_base->length * 4,
+ nsh_base->md_type, nsh_base->next_protocol);
s = format (s, " service path %d service index %d\n",
- (nsh->nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
- nsh->nsp_nsi & NSH_NSI_MASK);
+ (clib_net_to_host_u32(nsh_base->nsp_nsi)>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
+ clib_net_to_host_u32(nsh_base->nsp_nsi) & NSH_NSI_MASK);
+
+ if (nsh_base->md_type == 1 )
+ {
+ s = format (s, " c1 %d c2 %d c3 %d c4 %d\n",
+ clib_net_to_host_u32(nsh_md1->c1),
+ clib_net_to_host_u32(nsh_md1->c2),
+ clib_net_to_host_u32(nsh_md1->c3),
+ clib_net_to_host_u32(nsh_md1->c4) );
+ }
+ else if (nsh_base->md_type == 2 )
+ {
+ s = format (s, " Supported TLVs: \n");
- s = format (s, " c1 %d c2 %d c3 %d c4 %d\n",
- nsh->c1, nsh->c2, nsh->c3, nsh->c4);
+ /* Scan the set of variable metadata, network order */
+ while (opt0 < limit0)
+ {
+ nsh_option = nsh_md2_lookup_option(opt0->class, opt0->type);
+ if( nsh_option != NULL)
+ {
+ if (nm->trace[nsh_option->option_id] != NULL)
+ {
+ s = (*nm->trace[nsh_option->option_id]) (s, opt0);
+ }
+ else
+ {
+ s = format (s, "\n untraced option %d length %d", opt0->type,
+ opt0->length);
+ }
+ }
+ else
+ {
+ s = format (s, "\n unrecognized option %d length %d", opt0->type,
+ opt0->length);
+ }
+
+ /* round to 4-byte */
+ option_len = ( (opt0->length+3)>>2 ) << 2;
+ opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) + option_len);
+ }
+ }
return s;
}
@@ -195,6 +367,11 @@ u8 * format_nsh_map (u8 * s, va_list * args)
s = format (s, "encap-none");
break;
}
+ case NSH_NODE_NEXT_ENCAP_LISP_GPE:
+ {
+ s = format (s, "encapped by LISP GPE intf: %d", map->sw_if_index);
+ break;
+ }
default:
s = format (s, "only GRE and VXLANGPE support in this rev");
}
@@ -202,40 +379,6 @@ u8 * format_nsh_map (u8 * s, va_list * args)
return s;
}
-u8 * format_nsh_header_with_length (u8 * s, va_list * args)
-{
- nsh_header_t * h = va_arg (*args, nsh_header_t *);
- u32 max_header_bytes = va_arg (*args, u32);
- u32 tmp, header_bytes;
-
- header_bytes = sizeof (h[0]);
- if (max_header_bytes != 0 && header_bytes > max_header_bytes)
- return format (s, "nsh header truncated");
-
- tmp = clib_net_to_host_u32 (h->nsp_nsi);
- s = format (s, " nsp %d nsi %d ",
- (tmp>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
- tmp & NSH_NSI_MASK);
-
- s = format (s, "c1 %u c2 %u c3 %u c4 %u",
- clib_net_to_host_u32 (h->c1),
- clib_net_to_host_u32 (h->c2),
- clib_net_to_host_u32 (h->c3),
- clib_net_to_host_u32 (h->c4));
-
- s = format (s, "ver %d ", h->ver_o_c>>6);
-
- if (h->ver_o_c & NSH_O_BIT)
- s = format (s, "O-set ");
-
- if (h->ver_o_c & NSH_C_BIT)
- s = format (s, "C-set ");
-
- s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
- h->length, h->length * 4, h->md_type, h->next_protocol);
- return s;
-}
-
u8 * format_nsh_node_map_trace (u8 * s, va_list * args)
{
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
@@ -243,8 +386,7 @@ u8 * format_nsh_node_map_trace (u8 * s, va_list * args)
nsh_input_trace_t * t
= va_arg (*args, nsh_input_trace_t *);
- s = format (s, "\n %U", format_nsh_header, &t->nsh_header,
- (u32) sizeof (t->nsh_header) );
+ s = format (s, "\n %U", format_nsh_header, &(t->trace_data) );
return s;
}
@@ -263,7 +405,8 @@ int nsh_add_del_map (nsh_add_del_map_args_t *a, u32 * map_indexp)
hash_pair_t *hp;
u32 map_index = ~0;
- key = a->map.nsp_nsi;
+ /* net order, so data plane could use nsh header to lookup directly */
+ key = clib_host_to_net_u32(a->map.nsp_nsi);
entry = hash_get_mem (nm->nsh_mapping_by_key, &key);
@@ -347,7 +490,8 @@ int nsh_add_del_proxy_session (nsh_add_del_map_args_t *a)
return -1;
nsi = nsi -1;
- proxy->nsp_nsi = (nsp<< NSH_NSP_SHIFT) | nsi;
+ /* net order, so could use it to lookup nsh map table directly */
+ proxy->nsp_nsi = clib_host_to_net_u32((nsp<< NSH_NSP_SHIFT) | nsi);
key_copy = clib_mem_alloc (sizeof (*key_copy));
clib_memcpy (key_copy, &key, sizeof (*key_copy));
@@ -433,6 +577,8 @@ nsh_add_del_map_command_fn (vlib_main_t * vm,
next_node = NSH_NODE_NEXT_ENCAP_GRE;
else if (unformat (line_input, "encap-vxlan-gpe-intf %d", &sw_if_index))
next_node = NSH_NODE_NEXT_ENCAP_VXLANGPE;
+ else if (unformat (line_input, "encap-lisp-gpe-intf %d", &sw_if_index))
+ next_node = NSH_NODE_NEXT_ENCAP_LISP_GPE;
else if (unformat (line_input, "encap-vxlan4-intf %d", &sw_if_index))
next_node = NSH_NODE_NEXT_ENCAP_VXLAN4;
else if (unformat (line_input, "encap-vxlan6-intf %d", &sw_if_index))
@@ -456,7 +602,7 @@ nsh_add_del_map_command_fn (vlib_main_t * vm,
return clib_error_return (0, "nsh_action required: swap|push|pop.");
if (next_node == ~0)
- return clib_error_return (0, "must specific action: [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-none]");
+ return clib_error_return (0, "must specific action: [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> | encap-none]");
memset (a, 0, sizeof (*a));
@@ -513,7 +659,7 @@ VLIB_CLI_COMMAND (create_nsh_map_command, static) = {
.path = "create nsh map",
.short_help =
"create nsh map nsp <nn> nsi <nn> [del] mapped-nsp <nn> mapped-nsi <nn> nsh_action [swap|push|pop] "
- "[encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-none]\n",
+ "[encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> | encap-none]\n",
.function = nsh_add_del_map_command_fn,
};
@@ -575,56 +721,176 @@ VLIB_CLI_COMMAND (show_nsh_map_command, static) = {
.function = show_nsh_map_command_fn,
};
+int nsh_header_rewrite(nsh_entry_t *nsh_entry)
+{
+ u8 *rw = 0;
+ int len = 0;
+ nsh_base_header_t * nsh_base;
+ nsh_md1_data_t * nsh_md1;
+ nsh_main_t *nm = &nsh_main;
+ nsh_md2_data_t *opt0;
+ nsh_md2_data_t *limit0;
+ nsh_md2_data_t *nsh_md2;
+ nsh_option_map_t _nsh_option, *nsh_option=&_nsh_option;
+ u8 old_option_size = 0;
+ u8 new_option_size = 0;
+
+ vec_free(nsh_entry->rewrite);
+ if (nsh_entry->nsh_base.md_type == 1)
+ {
+ len = sizeof(nsh_base_header_t) + sizeof(nsh_md1_data_t);
+ }
+ else if (nsh_entry->nsh_base.md_type == 2)
+ {
+ /* set to maxim, maybe dataplane will add more TLVs */
+ len = MAX_NSH_HEADER_LEN;
+ }
+ vec_validate_aligned (rw, len-1, CLIB_CACHE_LINE_BYTES);
+ memset (rw, 0, len);
+
+ nsh_base = (nsh_base_header_t *) rw;
+ nsh_base->ver_o_c = nsh_entry->nsh_base.ver_o_c;
+ nsh_base->md_type = nsh_entry->nsh_base.md_type;
+ nsh_base->next_protocol = nsh_entry->nsh_base.next_protocol;
+ nsh_base->nsp_nsi = clib_host_to_net_u32(nsh_entry->nsh_base.nsp_nsi);
+
+ if (nsh_base->md_type == 1)
+ {
+ nsh_md1 =(nsh_md1_data_t *)(rw + sizeof(nsh_base_header_t));
+ nsh_md1->c1 = clib_host_to_net_u32(nsh_entry->md.md1_data.c1);
+ nsh_md1->c2 = clib_host_to_net_u32(nsh_entry->md.md1_data.c2);
+ nsh_md1->c3 = clib_host_to_net_u32(nsh_entry->md.md1_data.c3);
+ nsh_md1->c4 = clib_host_to_net_u32(nsh_entry->md.md1_data.c4);
+ nsh_entry->rewrite_size = 24;
+ }
+ else if (nsh_base->md_type == 2)
+ {
+ opt0 = (nsh_md2_data_t *)(nsh_entry->tlvs_data);
+ limit0 = (nsh_md2_data_t *) ((u8 *) opt0 + nsh_entry->tlvs_len);
+
+ nsh_md2 = (nsh_md2_data_t *)(rw + sizeof(nsh_base_header_t));
+ nsh_entry->rewrite_size = sizeof(nsh_base_header_t);
+
+ while(opt0 < limit0)
+ {
+ old_option_size = sizeof (nsh_md2_data_t) + opt0->length;
+ /* round to 4-byte */
+ old_option_size = ( (old_option_size+3)>>2 ) << 2;
+
+ nsh_option = nsh_md2_lookup_option(opt0->class, opt0->type);
+ if( nsh_option == NULL)
+ {
+ goto next_tlv_md2;
+ }
+
+ if(nm->add_options[nsh_option->option_id] != NULL)
+ {
+ if (0 != nm->add_options[nsh_option->option_id] (
+ (u8 *)nsh_md2, &new_option_size ))
+ {
+ goto next_tlv_md2;
+ }
+
+ /* round to 4-byte */
+ new_option_size = ( (new_option_size+3)>>2 ) << 2;
+
+ nsh_entry->rewrite_size += new_option_size;
+ nsh_md2 = (nsh_md2_data_t *) (((u8 *) nsh_md2) + new_option_size);
+ opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
+ }
+ else
+ {
+next_tlv_md2:
+ opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
+ }
+
+ }
+ }
+
+ nsh_entry->rewrite = rw;
+ nsh_base->length = nsh_entry->rewrite_size >> 2;
+
+ return 0;
+}
+
+
/**
* Action function for adding an NSH entry
+ * nsh_add_del_entry_args_t *a: host order
*/
int nsh_add_del_entry (nsh_add_del_entry_args_t *a, u32 * entry_indexp)
{
nsh_main_t * nm = &nsh_main;
- nsh_header_t *hdr = 0;
+ nsh_entry_t *nsh_entry = 0;
u32 key, *key_copy;
- uword * entry;
+ uword * entry_id;
hash_pair_t *hp;
u32 entry_index = ~0;
+ u8 tlvs_len = 0;
+ u8 * data = 0;
- key = a->nsh.nsp_nsi;
+ /* host order, because nsh map table stores nsp_nsi in host order */
+ key = a->nsh_entry.nsh_base.nsp_nsi;
- entry = hash_get_mem (nm->nsh_entry_by_key, &key);
+ entry_id = hash_get_mem (nm->nsh_entry_by_key, &key);
if (a->is_add)
{
/* adding an entry, must not already exist */
- if (entry)
+ if (entry_id)
return -1; // TODO VNET_API_ERROR_INVALID_VALUE;
- pool_get_aligned (nm->nsh_entries, hdr, CLIB_CACHE_LINE_BYTES);
- memset (hdr, 0, sizeof (*hdr));
+ pool_get_aligned (nm->nsh_entries, nsh_entry, CLIB_CACHE_LINE_BYTES);
+ memset (nsh_entry, 0, sizeof (*nsh_entry));
/* copy from arg structure */
-#define _(x) hdr->x = a->nsh.x;
- foreach_copy_nshhdr_field;
+#define _(x) nsh_entry->nsh_base.x = a->nsh_entry.nsh_base.x;
+ foreach_copy_nsh_base_hdr_field;
#undef _
+ if (a->nsh_entry.nsh_base.md_type == 1)
+ {
+ nsh_entry->md.md1_data.c1 = a->nsh_entry.md.md1_data.c1;
+ nsh_entry->md.md1_data.c2 = a->nsh_entry.md.md1_data.c2;
+ nsh_entry->md.md1_data.c3 = a->nsh_entry.md.md1_data.c3;
+ nsh_entry->md.md1_data.c4 = a->nsh_entry.md.md1_data.c4;
+ }
+ else if (a->nsh_entry.nsh_base.md_type == 2)
+ {
+ vec_free(nsh_entry->tlvs_data);
+ tlvs_len = a->nsh_entry.tlvs_len;
+ vec_validate_aligned(data, tlvs_len-1, CLIB_CACHE_LINE_BYTES);
+
+ clib_memcpy(data, a->nsh_entry.tlvs_data, tlvs_len);
+ nsh_entry->tlvs_data = data;
+ nsh_entry->tlvs_len = tlvs_len;
+ vec_free(a->nsh_entry.tlvs_data);
+ }
+
+ nsh_header_rewrite(nsh_entry);
+
key_copy = clib_mem_alloc (sizeof (*key_copy));
clib_memcpy (key_copy, &key, sizeof (*key_copy));
hash_set_mem (nm->nsh_entry_by_key, key_copy,
- hdr - nm->nsh_entries);
- entry_index = hdr - nm->nsh_entries;
+ nsh_entry - nm->nsh_entries);
+ entry_index = nsh_entry - nm->nsh_entries;
}
else
{
- if (!entry)
+ if (!entry_id)
return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
- hdr = pool_elt_at_index (nm->nsh_entries, entry[0]);
+ nsh_entry = pool_elt_at_index (nm->nsh_entries, entry_id[0]);
hp = hash_get_pair (nm->nsh_entry_by_key, &key);
key_copy = (void *)(hp->key);
hash_unset_mem (nm->nsh_entry_by_key, &key);
clib_mem_free (key_copy);
- pool_put (nm->nsh_entries, hdr);
+ vec_free (nsh_entry->tlvs_data);
+ vec_free (nsh_entry->rewrite);
+ pool_put (nm->nsh_entries, nsh_entry);
}
if (entry_indexp)
@@ -658,10 +924,18 @@ nsh_add_del_entry_command_fn (vlib_main_t * vm,
u32 c2 = 0;
u32 c3 = 0;
u32 c4 = 0;
+ u8 * data = 0;
+ nsh_tlv_header_t tlv_header;
+ u8 cur_len = 0, tlvs_len = 0;
+ u8 * current;
+ nsh_main_t *nm = &nsh_main;
+ nsh_option_map_t _nsh_option, *nsh_option=&_nsh_option;
+ u8 option_size = 0;
u32 tmp;
int rv;
u32 entry_index;
nsh_add_del_entry_args_t _a, * a = &_a;
+ u8 has_ioam_trace_option = 0;
/* Get a line of input. */
if (! unformat_user (input, unformat_line_input, line_input))
@@ -696,6 +970,8 @@ nsh_add_del_entry_command_fn (vlib_main_t * vm,
nsp_set = 1;
else if (unformat (line_input, "nsi %d", &nsi))
nsi_set = 1;
+ else if (unformat (line_input, "tlv-ioam-trace"))
+ has_ioam_trace_option = 1;
else
return clib_error_return (0, "parse error: '%U'",
format_unformat_error, line_input);
@@ -709,20 +985,66 @@ nsh_add_del_entry_command_fn (vlib_main_t * vm,
if (nsi_set == 0)
return clib_error_return (0, "nsi not specified");
- if (md_type != 1)
- return clib_error_return (0, "md-type 1 only supported at this time");
-
- md_type = 1;
- length = 6;
+ if (md_type == 1 && has_ioam_trace_option == 1)
+ return clib_error_return (0, "Invalid MD Type");
nsp_nsi = (nsp<<8) | nsi;
memset (a, 0, sizeof (*a));
-
a->is_add = is_add;
-#define _(x) a->nsh.x = x;
- foreach_copy_nshhdr_field;
+ if (md_type == 1)
+ {
+ a->nsh_entry.md.md1_data.c1 = c1;
+ a->nsh_entry.md.md1_data.c2 = c2;
+ a->nsh_entry.md.md1_data.c3 = c3;
+ a->nsh_entry.md.md1_data.c4 = c4;
+ length = (sizeof(nsh_base_header_t)+sizeof(nsh_md1_data_t)) >> 2;
+ }
+ else if (md_type == 2)
+ {
+ length = sizeof(nsh_base_header_t) >> 2;
+
+ vec_free(a->nsh_entry.tlvs_data);
+ tlvs_len = (MAX_METADATA_LEN << 2);
+ vec_validate_aligned (data, tlvs_len-1, CLIB_CACHE_LINE_BYTES);
+ a->nsh_entry.tlvs_data = data;
+ current = data;
+
+ if(has_ioam_trace_option)
+ {
+ tlv_header.class = clib_host_to_net_u16(NSH_MD2_IOAM_CLASS);
+ tlv_header.type = NSH_MD2_IOAM_OPTION_TYPE_TRACE;
+ /* Uses network order's class and type to lookup */
+ nsh_option = nsh_md2_lookup_option(tlv_header.class, tlv_header.type);
+ if( nsh_option == NULL)
+ return clib_error_return (0, "iOAM Trace not registered");
+
+ if(nm->add_options[nsh_option->option_id] != NULL)
+ {
+ if (0 != nm->add_options[nsh_option->option_id] (
+ (u8 *)current, &option_size ))
+ {
+ return clib_error_return (0, "Invalid MD Type");
+ }
+ }
+
+ nm->options_size[nsh_option->option_id]= option_size;
+ /* round to 4-byte */
+ option_size = ( ((option_size+3)>>2) << 2 );
+
+ cur_len += option_size;
+ current = data + option_size;
+ }
+
+ /* Add more options' parsing */
+
+ a->nsh_entry.tlvs_len = cur_len;
+ length += (cur_len >> 2);
+ }
+
+#define _(x) a->nsh_entry.nsh_base.x = x;
+ foreach_copy_nsh_base_hdr_field;
#undef _
rv = nsh_add_del_entry (a, &entry_index);
@@ -742,8 +1064,8 @@ nsh_add_del_entry_command_fn (vlib_main_t * vm,
VLIB_CLI_COMMAND (create_nsh_entry_command, static) = {
.path = "create nsh entry",
.short_help =
- "create nsh entry {nsp <nn> nsi <nn>} c1 <nn> c2 <nn> c3 <nn> c4 <nn>"
- " [md-type <nn>] [tlv <xx>] [del]\n",
+ "create nsh entry {nsp <nn> nsi <nn>} [md-type <nn>]"
+ " [c1 <nn> c2 <nn> c3 <nn> c4 <nn>] [tlv-ioam-trace] [del]\n",
.function = nsh_add_del_entry_command_fn,
};
@@ -756,17 +1078,32 @@ static void vl_api_nsh_add_del_entry_t_handler
int rv;
nsh_add_del_entry_args_t _a, *a = &_a;
u32 entry_index = ~0;
+ u8 tlvs_len = 0;
+ u8 * data = 0;
a->is_add = mp->is_add;
- a->nsh.ver_o_c = mp->ver_o_c;
- a->nsh.length = mp->length;
- a->nsh.md_type = mp->md_type;
- a->nsh.next_protocol = mp->next_protocol;
- a->nsh.nsp_nsi = ntohl(mp->nsp_nsi);
- a->nsh.c1 = ntohl(mp->c1);
- a->nsh.c2 = ntohl(mp->c2);
- a->nsh.c3 = ntohl(mp->c3);
- a->nsh.c4 = ntohl(mp->c4);
+ a->nsh_entry.nsh_base.ver_o_c = mp->ver_o_c;
+ a->nsh_entry.nsh_base.length = mp->length;
+ a->nsh_entry.nsh_base.md_type = mp->md_type;
+ a->nsh_entry.nsh_base.next_protocol = mp->next_protocol;
+ a->nsh_entry.nsh_base.nsp_nsi = ntohl(mp->nsp_nsi);
+ if (mp->md_type == 1)
+ {
+ a->nsh_entry.md.md1_data.c1 = ntohl(mp->c1);
+ a->nsh_entry.md.md1_data.c2 = ntohl(mp->c2);
+ a->nsh_entry.md.md1_data.c3 = ntohl(mp->c3);
+ a->nsh_entry.md.md1_data.c4 = ntohl(mp->c4);
+ }
+ else if (mp->md_type == 2)
+ {
+ vec_free(a->nsh_entry.tlvs_data);
+ tlvs_len = mp->tlv_length;
+ vec_validate_aligned (data, tlvs_len-1, CLIB_CACHE_LINE_BYTES);
+
+ clib_memcpy(data, a->nsh_entry.tlvs_data, tlvs_len);
+ a->nsh_entry.tlvs_data = data;
+ a->nsh_entry.tlvs_len = tlvs_len;
+ }
rv = nsh_add_del_entry (a, &entry_index);
@@ -777,7 +1114,7 @@ static void vl_api_nsh_add_del_entry_t_handler
}
static void send_nsh_entry_details
-(nsh_header_t * t, unix_shared_memory_queue_t * q, u32 context)
+(nsh_entry_t * t, unix_shared_memory_queue_t * q, u32 context)
{
vl_api_nsh_entry_details_t * rmp;
nsh_main_t * nm = &nsh_main;
@@ -786,15 +1123,24 @@ static void send_nsh_entry_details
memset (rmp, 0, sizeof (*rmp));
rmp->_vl_msg_id = ntohs((VL_API_NSH_ENTRY_DETAILS)+nm->msg_id_base);
- rmp->ver_o_c = t->ver_o_c;
- rmp->length = t->length;
- rmp->md_type = t->md_type;
- rmp->next_protocol = t->next_protocol;
- rmp->nsp_nsi = htonl(t->nsp_nsi);
- rmp->c1 = htonl(t->c1);
- rmp->c2 = htonl(t->c2);
- rmp->c3 = htonl(t->c3);
- rmp->c4 = htonl(t->c4);
+ rmp->ver_o_c = t->nsh_base.ver_o_c;
+ rmp->length = t->nsh_base.length;
+ rmp->md_type = t->nsh_base.md_type;
+ rmp->next_protocol = t->nsh_base.next_protocol;
+ rmp->nsp_nsi = htonl(t->nsh_base.nsp_nsi);
+
+ if (t->nsh_base.md_type == 1)
+ {
+ rmp->tlv_length = 4;
+ rmp->c1 = htonl(t->md.md1_data.c1);
+ rmp->c2 = htonl(t->md.md1_data.c2);
+ rmp->c3 = htonl(t->md.md1_data.c3);
+ rmp->c4 = htonl(t->md.md1_data.c4);
+ }
+ else if (t->nsh_base.md_type == 2)
+ {
+ /* TBD */
+ }
rmp->context = context;
@@ -806,7 +1152,7 @@ static void vl_api_nsh_entry_dump_t_handler
{
unix_shared_memory_queue_t * q;
nsh_main_t * nm = &nsh_main;
- nsh_header_t * t;
+ nsh_entry_t * t;
u32 entry_index;
q = vl_api_client_index_to_input_queue (mp->client_index);
@@ -894,14 +1240,18 @@ show_nsh_entry_command_fn (vlib_main_t * vm,
vlib_cli_command_t * cmd)
{
nsh_main_t * nm = &nsh_main;
- nsh_header_t * hdr;
+ nsh_entry_t * nsh_entry;
if (pool_elts (nm->nsh_entries) == 0)
vlib_cli_output (vm, "No nsh entries configured.");
- pool_foreach (hdr, nm->nsh_entries,
+ pool_foreach (nsh_entry, nm->nsh_entries,
({
- vlib_cli_output (vm, "%U", format_nsh_header, hdr);
+ vlib_cli_output (vm, "%U", format_nsh_header,
+ nsh_entry->rewrite );
+
+ vlib_cli_output (vm, " rewrite_size: %d bytes",
+ nsh_entry->rewrite_size);
}));
return 0;
@@ -932,8 +1282,179 @@ nsh_plugin_api_hookup (vlib_main_t *vm)
return 0;
}
+always_inline void
+nsh_md2_encap (vlib_buffer_t * b, nsh_base_header_t *hdr,
+ nsh_entry_t * nsh_entry)
+{
+ nsh_main_t *nm = &nsh_main;
+ nsh_base_header_t * nsh_base;
+ nsh_tlv_header_t * opt0;
+ nsh_tlv_header_t * limit0;
+ nsh_tlv_header_t * nsh_md2;
+ nsh_option_map_t * nsh_option;
+ u8 old_option_size = 0;
+ u8 new_option_size = 0;
+
+ /* Populate the NSH Header */
+ opt0 = (nsh_tlv_header_t *)(nsh_entry->tlvs_data);
+ limit0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data + nsh_entry->tlvs_len);
+
+ nsh_md2 = (nsh_tlv_header_t *)((u8 *)hdr /*nsh_entry->rewrite*/ + sizeof(nsh_base_header_t));
+ nsh_entry->rewrite_size = sizeof(nsh_base_header_t);
+
+ /* Scan the set of variable metadata, process ones that we understand */
+ while (opt0 < limit0)
+ {
+ old_option_size = sizeof (nsh_tlv_header_t) + opt0->length;
+ /* round to 4-byte */
+ old_option_size = ( (old_option_size+3)>>2 ) << 2;
+
+ nsh_option = nsh_md2_lookup_option(opt0->class, opt0->type);
+ if( nsh_option == NULL)
+ {
+ goto next_tlv_md2;
+ }
+
+ if (nm->options[nsh_option->option_id])
+ {
+ if ( (*nm->options[nsh_option->option_id]) (b, nsh_md2) )
+ {
+ goto next_tlv_md2;
+ }
+
+ /* option length may be varied */
+ new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length;
+ /* round to 4-byte */
+ new_option_size = ( (new_option_size+3)>>2 ) << 2;
+ nsh_entry->rewrite_size += new_option_size;
+ nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size);
+ opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
+ }
+ else
+ {
+next_tlv_md2:
+ opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
+ }
+ }
+
+ /* update nsh header's length */
+ nsh_base = (nsh_base_header_t *)nsh_entry->rewrite;
+ nsh_base->length = (nsh_entry->rewrite_size >> 2);
+
+ return;
+}
+
+always_inline void
+nsh_md2_swap (vlib_buffer_t * b,
+ nsh_base_header_t * hdr,
+ u32 header_len,
+ nsh_entry_t * nsh_entry,
+ u32 * next,
+ u32 drop_node_val)
+{
+ nsh_main_t *nm = &nsh_main;
+ nsh_base_header_t * nsh_base;
+ nsh_tlv_header_t * opt0;
+ nsh_tlv_header_t * limit0;
+ nsh_tlv_header_t * nsh_md2;
+ nsh_option_map_t * nsh_option;
+ u8 old_option_size = 0;
+ u8 new_option_size = 0;
+
+ /* Populate the NSH Header */
+ opt0 = (nsh_md2_data_t *)(hdr + 1);
+ limit0 = (nsh_md2_data_t *) ((u8 *) hdr + header_len);
+
+ nsh_md2 = (nsh_tlv_header_t *)(nsh_entry->rewrite + sizeof(nsh_base_header_t));
+ nsh_entry->rewrite_size = sizeof(nsh_base_header_t);
+
+ /* Scan the set of variable metadata, process ones that we understand */
+ while (opt0 < limit0)
+ {
+ old_option_size = sizeof (nsh_tlv_header_t) + opt0->length;
+ /* round to 4-byte */
+ old_option_size = ( (old_option_size+3)>>2 ) << 2;
+
+ nsh_option = nsh_md2_lookup_option(opt0->class, opt0->type);
+ if( nsh_option == NULL)
+ {
+ goto next_tlv_md2;
+ }
+
+ if (nm->swap_options[nsh_option->option_id])
+ {
+ if ( (*nm->swap_options[nsh_option->option_id]) (b, opt0, nsh_md2) )
+ {
+ goto next_tlv_md2;
+ }
+
+ /* option length may be varied */
+ new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length;
+ /* round to 4-byte */
+ new_option_size = ( (new_option_size+3)>>2 ) << 2;
+ nsh_entry->rewrite_size += new_option_size;
+ nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size);
+
+ opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
+
+ }
+ else
+ {
+next_tlv_md2:
+ opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
+ }
+ }
+
+ /* update nsh header's length */
+ nsh_base = (nsh_base_header_t *)nsh_entry->rewrite;
+ nsh_base->length = (nsh_entry->rewrite_size >> 2);
+ return;
+}
+
+always_inline void
+nsh_md2_decap (vlib_buffer_t * b,
+ nsh_base_header_t * hdr,
+ u32 header_len,
+ u32 * next,
+ u32 drop_node_val)
+{
+ nsh_main_t *nm = &nsh_main;
+ nsh_md2_data_t *opt0;
+ nsh_md2_data_t *limit0;
+ nsh_option_map_t *nsh_option;
+ u8 option_len = 0;
+
+ /* Populate the NSH Header */
+ opt0 = (nsh_md2_data_t *)(hdr + 1);
+ limit0 = (nsh_md2_data_t *) ((u8 *) hdr + header_len);
+
+ /* Scan the set of variable metadata, process ones that we understand */
+ while (opt0 < limit0)
+ {
+ nsh_option = nsh_md2_lookup_option(opt0->class, opt0->type);
+ if( nsh_option == NULL)
+ {
+ *next = drop_node_val;
+ return;
+ }
+
+ if (nm->pop_options[nsh_option->option_id])
+ {
+ if ( (*nm->pop_options[nsh_option->option_id]) (b, opt0) )
+ {
+ *next = drop_node_val;
+ return;
+ }
+ }
+ /* round to 4-byte */
+ option_len = ( (opt0->length+3)>>2 ) << 2;
+ opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) + option_len);
+ }
+
+ return;
+}
static uword
nsh_input_map (vlib_main_t * vm,
@@ -961,12 +1482,13 @@ nsh_input_map (vlib_main_t * vm,
vlib_buffer_t * b0, *b1;
u32 next0 = NSH_NODE_NEXT_DROP, next1 = NSH_NODE_NEXT_DROP;
uword * entry0, *entry1;
- nsh_header_t * hdr0 = 0, *hdr1 = 0;
+ nsh_base_header_t * hdr0 = 0, *hdr1 = 0;
u32 header_len0 = 0, header_len1 = 0;
u32 nsp_nsi0, nsp_nsi1;
u32 error0, error1;
nsh_map_t * map0 = 0, *map1 = 0;
- nsh_header_t *encap_hdr0 = 0, *encap_hdr1 = 0;
+ nsh_entry_t * nsh_entry0 = 0, *nsh_entry1 = 0;
+ nsh_base_header_t *encap_hdr0 = 0, *encap_hdr1 = 0;
u32 encap_hdr_len0 = 0, encap_hdr_len1 = 0;
nsh_proxy_session_by_key_t key0, key1;
uword *p0, *p1;
@@ -999,10 +1521,11 @@ nsh_input_map (vlib_main_t * vm,
error1 = 0;
b0 = vlib_get_buffer(vm, bi0);
+ b1 = vlib_get_buffer(vm, bi1);
hdr0 = vlib_buffer_get_current(b0);
if(node_type == NSH_INPUT_TYPE)
{
- nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
+ nsp_nsi0 = hdr0->nsp_nsi;
header_len0 = hdr0->length * 4;
}
else if(node_type == NSH_CLASSIFIER_TYPE)
@@ -1031,13 +1554,10 @@ nsh_input_map (vlib_main_t * vm,
nsp_nsi0 = proxy0->nsp_nsi;
}
- entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
-
- b1 = vlib_get_buffer(vm, bi1);
hdr1 = vlib_buffer_get_current(b1);
if(node_type == NSH_INPUT_TYPE)
{
- nsp_nsi1 = clib_net_to_host_u32(hdr1->nsp_nsi);
+ nsp_nsi1 = hdr1->nsp_nsi;
header_len1 = hdr1->length * 4;
}
else if(node_type == NSH_CLASSIFIER_TYPE)
@@ -1066,8 +1586,6 @@ nsh_input_map (vlib_main_t * vm,
nsp_nsi1 = proxy1->nsp_nsi;
}
- entry1 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi1);
-
/* Process packet 0 */
entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
if (PREDICT_FALSE(entry0 == 0))
@@ -1090,6 +1608,17 @@ nsh_input_map (vlib_main_t * vm,
if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
{
+ /* Manipulate MD2 */
+ if(PREDICT_FALSE(hdr0->md_type == 2))
+ {
+ nsh_md2_decap(b0, hdr0, header_len0, &next0, NSH_NODE_NEXT_DROP);
+ if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
+ {
+ error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
+ goto trace0;
+ }
+ }
+
/* Pop NSH header */
vlib_buffer_advance(b0, (word)header_len0);
goto trace0;
@@ -1102,14 +1631,30 @@ nsh_input_map (vlib_main_t * vm,
goto trace0;
}
- encap_hdr0 = pool_elt_at_index(nm->nsh_entries, entry0[0]);
- encap_hdr_len0 = encap_hdr0->length * 4;
+ nsh_entry0 = (nsh_entry_t *)pool_elt_at_index(nm->nsh_entries, entry0[0]);
+ encap_hdr0 = (nsh_base_header_t *)(nsh_entry0->rewrite);
+ /* rewrite_size should equal to (encap_hdr0->length * 4) */
+ encap_hdr_len0 = nsh_entry0->rewrite_size;
if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_SWAP))
{
+ /* Manipulate MD2 */
+ if(PREDICT_FALSE(hdr0->md_type == 2))
+ {
+ nsh_md2_swap(b0, hdr0, header_len0, nsh_entry0,
+ &next0, NSH_NODE_NEXT_DROP);
+ if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
+ {
+ error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
+ goto trace0;
+ }
+ }
+
/* Pop old NSH header */
vlib_buffer_advance(b0, (word)header_len0);
+ /* After processing, md2's length may be varied */
+ encap_hdr_len0 = nsh_entry0->rewrite_size;
/* Push new NSH header */
vlib_buffer_advance(b0, -(word)encap_hdr_len0);
hdr0 = vlib_buffer_get_current(b0);
@@ -1120,10 +1665,19 @@ nsh_input_map (vlib_main_t * vm,
if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_PUSH))
{
+ /* After processing, md2's length may be varied */
+ encap_hdr_len0 = nsh_entry0->rewrite_size;
/* Push new NSH header */
vlib_buffer_advance(b0, -(word)encap_hdr_len0);
hdr0 = vlib_buffer_get_current(b0);
clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
+
+ /* Manipulate MD2 */
+ if(PREDICT_FALSE(nsh_entry0->nsh_base.md_type == 2))
+ {
+ nsh_md2_encap(b0, hdr0, nsh_entry0);
+ }
+
}
trace0: b0->error = error0 ? node->errors[error0] : 0;
@@ -1131,7 +1685,7 @@ nsh_input_map (vlib_main_t * vm,
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
- tr->nsh_header = *hdr0;
+ clib_memcpy ( &(tr->trace_data), hdr0, (hdr0->length*4) );
}
/* Process packet 1 */
@@ -1156,6 +1710,17 @@ nsh_input_map (vlib_main_t * vm,
if(PREDICT_FALSE(map1->nsh_action == NSH_ACTION_POP))
{
+ /* Manipulate MD2 */
+ if(PREDICT_FALSE(hdr1->md_type == 2))
+ {
+ nsh_md2_decap(b1, hdr1, header_len1, &next1, NSH_NODE_NEXT_DROP);
+ if (PREDICT_FALSE(next1 == NSH_NODE_NEXT_DROP))
+ {
+ error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
+ goto trace1;
+ }
+ }
+
/* Pop NSH header */
vlib_buffer_advance(b1, (word)header_len1);
goto trace1;
@@ -1168,36 +1733,61 @@ nsh_input_map (vlib_main_t * vm,
goto trace1;
}
- encap_hdr1 = pool_elt_at_index(nm->nsh_entries, entry1[0]);
- encap_hdr_len1 = encap_hdr1->length * 4;
+ nsh_entry1 = (nsh_entry_t *)pool_elt_at_index(nm->nsh_entries, entry1[0]);
+ encap_hdr1 = (nsh_base_header_t *)(nsh_entry1->rewrite);
+ /* rewrite_size should equal to (encap_hdr0->length * 4) */
+ encap_hdr_len1 = nsh_entry1->rewrite_size;
if(PREDICT_TRUE(map1->nsh_action == NSH_ACTION_SWAP))
{
+ /* Manipulate MD2 */
+ if(PREDICT_FALSE(hdr1->md_type == 2))
+ {
+ nsh_md2_swap(b1, hdr1, header_len1, nsh_entry1,
+ &next1, NSH_NODE_NEXT_DROP);
+ if (PREDICT_FALSE(next1 == NSH_NODE_NEXT_DROP))
+ {
+ error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
+ goto trace1;
+ }
+ }
+
/* Pop old NSH header */
- vlib_buffer_advance(b1, (word)header_len1);
+ vlib_buffer_advance(b1, (word)header_len1);
- /* Push new NSH header */
- vlib_buffer_advance(b1, -(word)encap_hdr_len1);
- hdr1 = vlib_buffer_get_current(b1);
- clib_memcpy(hdr1, encap_hdr1, (word)encap_hdr_len1);
+ /* After processing, md2's length may be varied */
+ encap_hdr_len1 = nsh_entry1->rewrite_size;
+ /* Push new NSH header */
+ vlib_buffer_advance(b1, -(word)encap_hdr_len1);
+ hdr1 = vlib_buffer_get_current(b1);
+ clib_memcpy(hdr1, encap_hdr1, (word)encap_hdr_len1);
- goto trace1;
- }
+ goto trace1;
+ }
if(PREDICT_FALSE(map1->nsh_action == NSH_ACTION_PUSH))
{
- /* Push new NSH header */
- vlib_buffer_advance(b1, -(word)encap_hdr_len1);
- hdr1 = vlib_buffer_get_current(b1);
- clib_memcpy(hdr1, encap_hdr1, (word)encap_hdr_len1);
- }
+ /* After processing, md2's length may be varied */
+ encap_hdr_len1 = nsh_entry1->rewrite_size;
+ /* Push new NSH header */
+ vlib_buffer_advance(b1, -(word)encap_hdr_len1);
+ hdr1 = vlib_buffer_get_current(b1);
+ clib_memcpy(hdr1, encap_hdr1, (word)encap_hdr_len1);
+
+ /* Manipulate MD2 */
+ if(PREDICT_FALSE(nsh_entry1->nsh_base.md_type == 2))
+ {
+ nsh_md2_encap(b1, hdr1, nsh_entry1);
+ }
+
+ }
trace1: b1->error = error1 ? node->errors[error1] : 0;
if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
{
nsh_input_trace_t *tr = vlib_add_trace(vm, node, b1, sizeof(*tr));
- tr->nsh_header = *hdr1;
+ clib_memcpy ( &(tr->trace_data), hdr1, (hdr1->length*4) );
}
vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
@@ -1207,16 +1797,17 @@ nsh_input_map (vlib_main_t * vm,
while (n_left_from > 0 && n_left_to_next > 0)
{
- u32 bi0;
- vlib_buffer_t * b0;
+ u32 bi0 = 0;
+ vlib_buffer_t * b0 = NULL;
u32 next0 = NSH_NODE_NEXT_DROP;
uword * entry0;
- nsh_header_t * hdr0 = 0;
+ nsh_base_header_t * hdr0 = 0;
u32 header_len0 = 0;
u32 nsp_nsi0;
u32 error0;
nsh_map_t * map0 = 0;
- nsh_header_t * encap_hdr0 = 0;
+ nsh_entry_t * nsh_entry0 = 0;
+ nsh_base_header_t * encap_hdr0 = 0;
u32 encap_hdr_len0 = 0;
nsh_proxy_session_by_key_t key0;
uword *p0;
@@ -1235,7 +1826,7 @@ nsh_input_map (vlib_main_t * vm,
if(node_type == NSH_INPUT_TYPE)
{
- nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
+ nsp_nsi0 = hdr0->nsp_nsi;
header_len0 = hdr0->length * 4;
}
else if(node_type == NSH_CLASSIFIER_TYPE)
@@ -1287,6 +1878,17 @@ nsh_input_map (vlib_main_t * vm,
if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
{
+ /* Manipulate MD2 */
+ if(PREDICT_FALSE(hdr0->md_type == 2))
+ {
+ nsh_md2_decap(b0, hdr0, header_len0, &next0, NSH_NODE_NEXT_DROP);
+ if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
+ {
+ error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
+ goto trace00;
+ }
+ }
+
/* Pop NSH header */
vlib_buffer_advance(b0, (word)header_len0);
goto trace00;
@@ -1299,14 +1901,30 @@ nsh_input_map (vlib_main_t * vm,
goto trace00;
}
- encap_hdr0 = pool_elt_at_index(nm->nsh_entries, entry0[0]);
- encap_hdr_len0 = encap_hdr0->length * 4;
+ nsh_entry0 = (nsh_entry_t *)pool_elt_at_index(nm->nsh_entries, entry0[0]);
+ encap_hdr0 = (nsh_base_header_t *)(nsh_entry0->rewrite);
+ /* rewrite_size should equal to (encap_hdr0->length * 4) */
+ encap_hdr_len0 = nsh_entry0->rewrite_size;
if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_SWAP))
{
+ /* Manipulate MD2 */
+ if(PREDICT_FALSE(hdr0->md_type == 2))
+ {
+ nsh_md2_swap(b0, hdr0, header_len0, nsh_entry0,
+ &next0, NSH_NODE_NEXT_DROP);
+ if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
+ {
+ error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
+ goto trace00;
+ }
+ }
+
/* Pop old NSH header */
vlib_buffer_advance(b0, (word)header_len0);
+ /* After processing, md2's length may be varied */
+ encap_hdr_len0 = nsh_entry0->rewrite_size;
/* Push new NSH header */
vlib_buffer_advance(b0, -(word)encap_hdr_len0);
hdr0 = vlib_buffer_get_current(b0);
@@ -1317,10 +1935,18 @@ nsh_input_map (vlib_main_t * vm,
if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_PUSH))
{
+ /* After processing, md2's length may be varied */
+ encap_hdr_len0 = nsh_entry0->rewrite_size;
/* Push new NSH header */
vlib_buffer_advance(b0, -(word)encap_hdr_len0);
hdr0 = vlib_buffer_get_current(b0);
clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
+ /* Manipulate MD2 */
+ if(PREDICT_FALSE(nsh_entry0->nsh_base.md_type == 2))
+ {
+ nsh_md2_encap(b0, hdr0, nsh_entry0);
+ }
+
}
trace00: b0->error = error0 ? node->errors[error0] : 0;
@@ -1328,7 +1954,7 @@ nsh_input_map (vlib_main_t * vm,
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
- tr->nsh_header = *hdr0;
+ clib_memcpy ( &(tr->trace_data[0]), hdr0, (hdr0->length*4) );
}
vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
@@ -1408,7 +2034,7 @@ VLIB_REGISTER_NODE (nsh_input_node) = {
.name = "nsh-input",
.vector_size = sizeof (u32),
.format_trace = format_nsh_node_map_trace,
- .format_buffer = format_nsh_header_with_length,
+ .format_buffer = format_nsh_header,
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = ARRAY_LEN(nsh_node_error_strings),
@@ -1431,7 +2057,7 @@ VLIB_REGISTER_NODE (nsh_proxy_node) = {
.name = "nsh-proxy",
.vector_size = sizeof (u32),
.format_trace = format_nsh_node_map_trace,
- .format_buffer = format_nsh_header_with_length,
+ .format_buffer = format_nsh_header,
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = ARRAY_LEN(nsh_node_error_strings),
@@ -1454,7 +2080,7 @@ VLIB_REGISTER_NODE (nsh_classifier_node) = {
.name = "nsh-classifier",
.vector_size = sizeof (u32),
.format_trace = format_nsh_node_map_trace,
- .format_buffer = format_nsh_header_with_length,
+ .format_buffer = format_nsh_header,
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = ARRAY_LEN(nsh_node_error_strings),
@@ -1471,6 +2097,7 @@ VLIB_REGISTER_NODE (nsh_classifier_node) = {
VLIB_NODE_FUNCTION_MULTIARCH (nsh_classifier_node, nsh_classifier);
+
clib_error_t *nsh_init (vlib_main_t *vm)
{
nsh_main_t *nm = &nsh_main;
@@ -1495,6 +2122,9 @@ clib_error_t *nsh_init (vlib_main_t *vm)
nm->nsh_proxy_session_by_key
= hash_create_mem (0, sizeof(nsh_proxy_session_by_key_t), sizeof (uword));
+ nm->nsh_option_map_by_key
+ = hash_create_mem (0, sizeof(nsh_option_map_by_key_t), sizeof (uword));
+
name = format (0, "nsh_%08x%c", api_version, 0);
/* Set up the API */
diff --git a/nsh-plugin/nsh/nsh.h b/nsh-plugin/nsh/nsh.h
index 632a2c4..ee6982b 100644
--- a/nsh-plugin/nsh/nsh.h
+++ b/nsh-plugin/nsh/nsh.h
@@ -20,10 +20,42 @@
#include <vnet/ip/ip4_packet.h>
typedef struct {
+ u16 class;
+ u8 type;
+ u8 pad;
+} nsh_option_map_by_key_t;
+typedef struct {
+ u32 option_id;
+} nsh_option_map_t;
+
+#define MAX_METADATA_LEN 62
+/** Note:
+ * rewrite and rewrite_size used to support varied nsh header
+ */
+typedef struct {
+ nsh_base_header_t nsh_base;
+ union {
+ nsh_md1_data_t md1_data;
+ nsh_md2_data_t md2_data;
+ } md;
+ u8 tlvs_len; /* configured md2 metadata's length, unit: byte */
+ u8 * tlvs_data; /* configured md2 metadata, network order */
+
+ /** Rewrite string. network order
+ * contains base header and metadata */
+ u8 * rewrite;
+ u8 rewrite_size; /* unit: byte */
+} nsh_entry_t;
+
+typedef struct {
+ u8 is_add;
+ nsh_entry_t nsh_entry;
+} nsh_add_del_entry_args_t;
+
+typedef struct {
/** Key for nsh_header_t entry: 24bit NSP 8bit NSI */
u32 nsp_nsi;
-
/** Key for nsh_header_t entry to map to. : 24bit NSP 8bit NSI
* This may be ~0 if next action is to decap to NSH next protocol
* Note the following heuristic:
@@ -32,48 +64,36 @@ typedef struct {
* Note: these are heuristics. Rules about NSI decrement are out of scope
*/
u32 mapped_nsp_nsi;
-
/* NSH Header action: swap, push and pop */
u32 nsh_action;
-
/* vnet intfc sw_if_index */
u32 sw_if_index;
-
u32 next_node;
-
} nsh_map_t;
typedef struct {
+ u8 is_add;
+ nsh_map_t map;
+} nsh_add_del_map_args_t;
+typedef struct {
u32 transport_type; /* 1:vxlan; */
-
u32 transport_index; /* transport's sw_if_index */
-
} nsh_proxy_session_by_key_t;
typedef struct {
-
/* 24bit NSP 8bit NSI */
u32 nsp_nsi;
-
} nsh_proxy_session_t;
-typedef struct {
- nsh_map_t map;
- u8 is_add;
-} nsh_add_del_map_args_t;
-
-typedef struct {
- u8 is_add;
- nsh_header_t nsh;
-} nsh_add_del_entry_args_t;
+#define MAX_MD2_OPTIONS 256
typedef struct {
/* API message ID base */
u16 msg_id_base;
/* vector of nsh_header entry instances */
- nsh_header_t *nsh_entries;
+ nsh_entry_t *nsh_entries;
/* hash lookup nsh header by key: {u32: nsp_nsi} */
uword * nsh_entry_by_key;
@@ -91,6 +111,30 @@ typedef struct {
/* hash lookup nsh_proxy by key */
uword * nsh_proxy_session_by_key;
+ /* vector of nsh_option_map */
+ nsh_option_map_t * nsh_option_mappings;
+ /* hash lookup nsh_option_map by key */
+ uword * nsh_option_map_by_key;
+
+ /* Array of function pointers to process MD-Type 2 handling routines */
+ /*
+ * For API or CLI configuration and construct the rewrite buffer, invokes add_options() function.
+ * In the encap node, i.e. when performing PUSH nsh header, invokes options() function.
+ * In the swap node, i.e. when performing SWAP nsh header, invokes swap_options() function.
+ * In the decap node, i.e. when performing POP nsh header, invokes pop_options() function.
+ */
+ u8 options_size[MAX_MD2_OPTIONS]; /* sum of header and metadata */
+ int (*add_options[MAX_MD2_OPTIONS]) (u8 * opt,
+ u8 * opt_size);
+ int (*options[MAX_MD2_OPTIONS]) (vlib_buffer_t * b,
+ nsh_tlv_header_t * opt);
+ int (*swap_options[MAX_MD2_OPTIONS]) (vlib_buffer_t * b,
+ nsh_tlv_header_t * old_opt,
+ nsh_tlv_header_t * new_opt);
+ int (*pop_options[MAX_MD2_OPTIONS]) (vlib_buffer_t * b,
+ nsh_tlv_header_t * opt);
+ u8 *(*trace[MAX_MD2_OPTIONS]) (u8 * s, nsh_tlv_header_t * opt);
+
/* convenience */
vlib_main_t * vlib_main;
vnet_main_t * vnet_main;
@@ -102,23 +146,12 @@ u8 * format_nsh_input_map_trace (u8 * s, va_list * args);
u8 * format_nsh_header_with_length (u8 * s, va_list * args);
/* Helper macros used in nsh.c and nsh_test.c */
-#define foreach_copy_nshhdr_field \
+#define foreach_copy_nsh_base_hdr_field \
_(ver_o_c) \
_(length) \
_(md_type) \
_(next_protocol) \
-_(nsp_nsi) \
-_(c1) \
-_(c2) \
-_(c3) \
-_(c4)
-/* TODO Temp killing tlvs as its causing pain - fix in NSH_SFC */
-#define foreach_32bit_field \
-_(nsp_nsi) \
-_(c1) \
-_(c2) \
-_(c3) \
-_(c4)
+_(nsp_nsi)
/* Statistics (not really errors) */
#define foreach_nsh_node_error \
@@ -127,6 +160,7 @@ _(NO_MAPPING, "no mapping for nsh key") \
_(NO_ENTRY, "no entry for nsh key") \
_(NO_PROXY, "no proxy for transport key") \
_(INVALID_NEXT_PROTOCOL, "invalid next protocol") \
+_(INVALID_OPTIONS, "invalid md2 options") \
typedef enum {
#define _(sym,str) NSH_NODE_ERROR_##sym,
@@ -143,6 +177,7 @@ typedef enum {
_(ENCAP_VXLAN4, "vxlan4-encap" ) \
_(ENCAP_VXLAN6, "vxlan6-encap" ) \
_(DECAP_ETH_INPUT, "ethernet-input" ) \
+ _(ENCAP_LISP_GPE, "interface-output" ) \
/* /\* TODO once moved to Project:NSH_SFC *\/ */
/* _(ENCAP_ETHERNET, "*** TX TO ETHERNET ***") \ */
/* _(DECAP_IP4_INPUT, "ip4-input") \ */
@@ -167,4 +202,29 @@ typedef enum {
NSH_CLASSIFIER_TYPE,
} nsh_entity_type;
+/* md2 class and type definition */
+#define NSH_MD2_IOAM_CLASS 0x9
+#define NSH_MD2_IOAM_OPTION_TYPE_TRACE 0x3B
+#define NSH_MD2_IOAM_OPTION_TYPE_PROOF_OF_TRANSIT 0x3C
+
+#define NSH_MD2_IOAM_TRACE_DUMMY_LEN 0x8
+
+#define MAX_NSH_HEADER_LEN 256
+#define MAX_NSH_OPTION_LEN 128
+
+int
+nsh_md2_register_option (u16 class,
+ u8 type,
+ u8 option_size,
+ int add_options (u8 * opt,
+ u8 * opt_size),
+ int options(vlib_buffer_t * b,
+ nsh_tlv_header_t * opt),
+ int swap_options (vlib_buffer_t * b,
+ nsh_tlv_header_t * old_opt,
+ nsh_tlv_header_t * new_opt),
+ int pop_options (vlib_buffer_t * b,
+ nsh_tlv_header_t * opt),
+ u8 * trace (u8 * s,
+ nsh_tlv_header_t * opt));
#endif /* included_nsh_h */
diff --git a/nsh-plugin/nsh/nsh_packet.h b/nsh-plugin/nsh/nsh_packet.h
index 553fc0b..101652a 100644
--- a/nsh-plugin/nsh/nsh_packet.h
+++ b/nsh-plugin/nsh/nsh_packet.h
@@ -74,11 +74,30 @@ typedef CLIB_PACKED(struct {
u8 md_type;
u8 next_protocol;
u32 nsp_nsi; // nsp 24 bits, nsi 8 bits
+}) nsh_base_header_t;
+
+typedef CLIB_PACKED(struct {
/* Context headers, always present */
- u32 c1; u32 c2; u32 c3; u32 c4;
+ u32 c1;
+ u32 c2;
+ u32 c3;
+ u32 c4;
+}) nsh_md1_data_t;
- /* Optional variable length metadata */
- u32 tlvs[0];
+typedef CLIB_PACKED(struct {
+ u16 class;
+ u8 type;
+ u8 length;
+}) nsh_tlv_header_t;
+
+typedef nsh_tlv_header_t nsh_md2_data_t;
+
+typedef CLIB_PACKED(struct {
+ nsh_base_header_t nsh_base;
+ union {
+ nsh_md1_data_t md1_data;
+ nsh_md2_data_t md2_data;
+ } md;
}) nsh_header_t;
#define NSH_VERSION (0<<6)
diff --git a/nsh-plugin/nsh/nsh_test.c b/nsh-plugin/nsh/nsh_test.c
index a7b7957..1d0a16c 100644
--- a/nsh-plugin/nsh/nsh_test.c
+++ b/nsh-plugin/nsh/nsh_test.c
@@ -187,12 +187,10 @@ static int api_nsh_add_del_entry (vat_main_t * vam)
if (nsi_set == 0)
return -2; //TODO Error type for this cond:clib_error_return (0, "nsi not specified");
- if (md_type != 1)
- return -3; //TODO Error type for this cond: clib_error_return (0, "md-type 1 only supported at this time");
-
- //TODO sort out TLVS and MD Type2 support
- md_type = 1;
- length = 6;
+ if (md_type == 1)
+ length = 6;
+ else if (md_type == 2)
+ length = 2; /* base header length */
nsp_nsi = (nsp<<8) | nsi;
@@ -201,7 +199,7 @@ static int api_nsh_add_del_entry (vat_main_t * vam)
mp->is_add = is_add;
#define _(x) mp->x = x;
- foreach_copy_nshhdr_field;
+ foreach_copy_nsh_base_hdr_field;
#undef _