From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- src/vnet/lisp-cp/lisp_types.h | 354 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 354 insertions(+) create mode 100644 src/vnet/lisp-cp/lisp_types.h (limited to 'src/vnet/lisp-cp/lisp_types.h') diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h new file mode 100644 index 00000000..ac58b894 --- /dev/null +++ b/src/vnet/lisp-cp/lisp_types.h @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2016 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. + */ + +#ifndef VNET_LISP_GPE_LISP_TYPES_H_ +#define VNET_LISP_GPE_LISP_TYPES_H_ + +#include +#include + +#define SHA1_AUTH_DATA_LEN 20 +#define SHA256_AUTH_DATA_LEN 32 + +typedef enum +{ + HMAC_NO_KEY = 0, + HMAC_SHA_1_96, + HMAC_SHA_256_128 +} lisp_key_type_t; + +uword unformat_hmac_key_id (unformat_input_t * input, va_list * args); +u8 *format_hmac_key_id (u8 * s, va_list * args); + +typedef enum +{ + IP4, + IP6 +} ip_address_type_t; + +/* *INDENT-OFF* */ +typedef CLIB_PACKED(struct ip_address +{ + union + { + ip4_address_t v4; + ip6_address_t v6; + } ip; + u8 version; +}) ip_address_t; +/* *INDENT-ON* */ + +#define ip_addr_addr(_a) (_a)->ip +#define ip_addr_v4(_a) (_a)->ip.v4 +#define ip_addr_v6(_a) (_a)->ip.v6 +#define ip_addr_version(_a) (_a)->version + +int ip_address_cmp (const ip_address_t * ip1, const ip_address_t * ip2); +void ip_address_copy (ip_address_t * dst, const ip_address_t * src); +void ip_address_copy_addr (void *dst, const ip_address_t * src); +void ip_address_set (ip_address_t * dst, const void *src, u8 version); + +/* *INDENT-OFF* */ +typedef CLIB_PACKED(struct ip_prefix +{ + ip_address_t addr; + u8 len; +}) ip_prefix_t; +/* *INDENT-ON* */ + +#define ip_prefix_addr(_a) (_a)->addr +#define ip_prefix_version(_a) ip_addr_version(&ip_prefix_addr(_a)) +#define ip_prefix_len(_a) (_a)->len +#define ip_prefix_v4(_a) ip_addr_v4(&ip_prefix_addr(_a)) +#define ip_prefix_v6(_a) ip_addr_v6(&ip_prefix_addr(_a)) + +void ip_prefix_normalize (ip_prefix_t * a); + +extern void ip_address_to_fib_prefix (const ip_address_t * addr, + fib_prefix_t * prefix); +extern void ip_prefix_to_fib_prefix (const ip_prefix_t * ipp, + fib_prefix_t * fibp); + +typedef enum +{ + /* NOTE: ip addresses are left out on purpose. Use max masked ip-prefixes + * instead */ + GID_ADDR_IP_PREFIX, + GID_ADDR_LCAF, + GID_ADDR_MAC, + GID_ADDR_SRC_DST, + GID_ADDR_NO_ADDRESS, + GID_ADDR_TYPES +} gid_address_type_t; + +typedef enum +{ + /* make sure that values corresponds with RFC */ + LCAF_NULL_BODY = 0, + LCAF_AFI_LIST_TYPE, + LCAF_INSTANCE_ID, + LCAF_SOURCE_DEST = 12, + LCAF_TYPES +} lcaf_type_t; + +typedef enum fid_addr_type_t_ +{ + FID_ADDR_IP_PREF, + FID_ADDR_MAC +} __attribute__ ((packed)) fid_addr_type_t; + +/* flat address type */ +typedef struct +{ + union + { + ip_prefix_t ippref; + u8 mac[6]; + }; + fid_addr_type_t type; +} fid_address_t; + +typedef fid_address_t dp_address_t; + +#define fid_addr_ippref(_a) (_a)->ippref +#define fid_addr_mac(_a) (_a)->mac +#define fid_addr_type(_a) (_a)->type +u8 *format_fid_address (u8 * s, va_list * args); + +typedef struct +{ + fid_address_t src; + fid_address_t dst; +} source_dest_t; + +#define sd_dst(_a) (_a)->dst +#define sd_src(_a) (_a)->src +#define sd_src_ippref(_a) fid_addr_ippref(&sd_src(_a)) +#define sd_dst_ippref(_a) fid_addr_ippref(&sd_dst(_a)) +#define sd_src_mac(_a) fid_addr_mac(&sd_src(_a)) +#define sd_dst_mac(_a) fid_addr_mac(&sd_dst(_a)) +#define sd_src_type(_a) fid_addr_type(&sd_src(_a)) +#define sd_dst_type(_a) fid_addr_type(&sd_dst(_a)) + +typedef struct +{ + u8 vni_mask_len; + u32 vni; + struct _gid_address_t *gid_addr; +} vni_t; + +#define vni_vni(_a) (_a)->vni +#define vni_mask_len(_a) (_a)->vni_mask_len +#define vni_gid(_a) (_a)->gid_addr + +typedef struct +{ + /* the union needs to be at the beginning! */ + union + { + source_dest_t sd; + vni_t uni; + }; + u8 type; +} lcaf_t; + +#define lcaf_type(_a) (_a)->type +#define lcaf_vni(_a) vni_vni(& (_a)->uni) +#define lcaf_vni_len(_a) vni_mask_len(& (_a)->uni) + +/* might want to expand this in the future :) */ +typedef struct _gid_address_t +{ + union + { + ip_prefix_t ippref; + lcaf_t lcaf; + u8 mac[6]; + source_dest_t sd; + }; + u8 type; + u32 vni; + u8 vni_mask; +} gid_address_t; + +u8 *format_ip_address (u8 * s, va_list * args); +uword unformat_ip_address (unformat_input_t * input, va_list * args); +u8 *format_ip_prefix (u8 * s, va_list * args); +uword unformat_ip_prefix (unformat_input_t * input, va_list * args); +u8 *format_mac_address (u8 * s, va_list * args); +uword unformat_mac_address (unformat_input_t * input, va_list * args); + +u16 ip4_address_size_to_put (); +u16 ip6_address_size_to_put (); +u32 ip4_address_put (u8 * b, ip4_address_t * a); +u32 ip6_address_put (u8 * b, ip6_address_t * a); + +u16 ip_address_size_to_write (ip_address_t * a); +u16 ip_address_iana_afi (ip_address_t * a); +u8 ip_address_max_len (u8 ver); +u32 ip_address_put (u8 * b, ip_address_t * a); +void ip_address_to_46 (const ip_address_t * addr, + ip46_address_t * a, fib_protocol_t * proto); + +/* LISP AFI codes */ +typedef enum +{ + LISP_AFI_NO_ADDR, + LISP_AFI_IP, + LISP_AFI_IP6, + LISP_AFI_LCAF = 16387, + LISP_AFI_MAC = 16389 +} lisp_afi_e; + +u8 *format_gid_address (u8 * s, va_list * args); +uword unformat_gid_address (unformat_input_t * input, va_list * args); +int gid_address_cmp (gid_address_t * a1, gid_address_t * a2); +void gid_address_free (gid_address_t * a); + +u16 gid_address_size_to_put (gid_address_t * a); +u16 gid_address_put (u8 * b, gid_address_t * gid); +u8 gid_address_len (gid_address_t * a); +void *gid_address_cast (gid_address_t * gid, gid_address_type_t type); +void gid_address_copy (gid_address_t * dst, gid_address_t * src); +u32 gid_address_parse (u8 * offset, gid_address_t * a); +void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); + +#define gid_address_type(_a) (_a)->type +#define gid_address_ippref(_a) (_a)->ippref +#define gid_address_ippref_len(_a) (_a)->ippref.len +#define gid_address_ip(_a) ip_prefix_addr(&gid_address_ippref(_a)) +#define gid_address_ip_version(_a) ip_addr_version(&gid_address_ip(_a)) +#define gid_address_lcaf(_a) (_a)->lcaf +#define gid_address_mac(_a) (_a)->mac +#define gid_address_vni(_a) (_a)->vni +#define gid_address_vni_mask(_a) (_a)->vni_mask +#define gid_address_sd_dst_ippref(_a) sd_dst_ippref(&(_a)->sd) +#define gid_address_sd_src_ippref(_a) sd_src_ippref(&(_a)->sd) +#define gid_address_sd_dst_mac(_a) sd_dst_mac(&(_a)->sd) +#define gid_address_sd_src_mac(_a) sd_src_mac(&(_a)->sd) +#define gid_address_sd(_a) (_a)->sd +#define gid_address_sd_src(_a) sd_src(&gid_address_sd(_a)) +#define gid_address_sd_dst(_a) sd_dst(&gid_address_sd(_a)) +#define gid_address_sd_src_type(_a) sd_src_type(&gid_address_sd(_a)) +#define gid_address_sd_dst_type(_a) sd_dst_type(&gid_address_sd(_a)) + +/* 'sub'address functions */ +#define foreach_gid_address_type_fcns \ + _(ip_prefix) \ + _(lcaf) \ + _(mac) \ + _(sd) + +/* *INDENT-OFF* */ +#define _(_n) \ +u16 _n ## _size_to_write (void * pref); \ +u16 _n ## _write (u8 * p, void * pref); \ +u8 _n ## _length (void *a); \ +void * _n ## _cast (gid_address_t * a); \ +void _n ## _copy (void * dst , void * src); + +foreach_gid_address_type_fcns +#undef _ +/* *INDENT-ON* */ + +always_inline u64 +mac_to_u64 (u8 * m) +{ + return (*((u64 *) m) & 0xffffffffffff); +} + +typedef struct +{ + /* mark locator as local as opposed to remote */ + u8 local; + u8 state; + union + { + u32 sw_if_index; + gid_address_t address; + }; + u8 priority; + u8 weight; + u8 mpriority; + u8 mweight; + u8 probed; +} locator_t; + +u32 locator_parse (void *ptr, locator_t * loc); +void locator_copy (locator_t * dst, locator_t * src); +u32 locator_cmp (locator_t * l1, locator_t * l2); +void locator_free (locator_t * l); + +typedef struct +{ + /* locator-set name */ + u8 *name; + + /* vector of locator indices */ + u32 *locator_indices; + u8 local; +} locator_set_t; + +typedef struct +{ + gid_address_t eid; + + /* index of local locator set */ + union + { + u32 locator_set_index; + locator_t *locators; /* used for map register message */ + }; + + u32 ttl; + u8 action; + u8 authoritative; + + u8 local; + /* valid only for remote mappings */ + u8 is_static; + u8 *key; + lisp_key_type_t key_id; + u8 timer_set; +} mapping_t; + +uword +unformat_negative_mapping_action (unformat_input_t * input, va_list * args); +u8 *format_negative_mapping_action (u8 *, va_list * args); + +typedef struct locator_pair +{ + /* local and remote locators (underlay attachment points) */ + ip_address_t lcl_loc; + ip_address_t rmt_loc; + + u8 priority; + u8 weight; +} locator_pair_t; + +void +build_src_dst (gid_address_t * sd, gid_address_t * src, gid_address_t * dst); + +void gid_address_from_ip (gid_address_t * g, ip_address_t * ip); + +#endif /* VNET_LISP_GPE_LISP_TYPES_H_ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg From ce1b4c7f05ce28d7b73eb7ed0a8ea4bd483f09e9 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Thu, 26 Jan 2017 14:25:34 -0800 Subject: Basic support for LISP-GPE encapsulated NSH packets Change-Id: I97fedb0f70dd18ed9bbe985407cc5fe714e8a2e2 Signed-off-by: Florin Coras --- src/vnet.am | 2 + src/vnet/adj/adj_internal.h | 4 +- src/vnet/adj/adj_midchain.c | 20 +++ src/vnet/adj/adj_nsh.c | 211 ++++++++++++++++++++++ src/vnet/adj/adj_nsh.h | 31 ++++ src/vnet/dpo/dpo.c | 2 + src/vnet/dpo/dpo.h | 6 +- src/vnet/fib/fib_entry_delegate.c | 4 + src/vnet/fib/fib_entry_delegate.h | 3 +- src/vnet/fib/fib_entry_src.c | 1 + src/vnet/fib/fib_path.c | 4 + src/vnet/fib/fib_types.c | 6 + src/vnet/fib/fib_types.h | 11 +- src/vnet/gre/gre.c | 3 + src/vnet/interface.c | 1 + src/vnet/interface.h | 4 +- src/vnet/lisp-cp/control.c | 32 ++++ src/vnet/lisp-cp/lisp_api.c | 2 + src/vnet/lisp-cp/lisp_cp_dpo.c | 5 + src/vnet/lisp-cp/lisp_types.c | 43 ++++- src/vnet/lisp-cp/lisp_types.h | 15 +- src/vnet/lisp-gpe/interface.c | 196 ++++++++++++++++++++- src/vnet/lisp-gpe/lisp_gpe.c | 2 +- src/vnet/lisp-gpe/lisp_gpe.h | 9 + src/vnet/lisp-gpe/lisp_gpe_adjacency.c | 8 +- src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c | 309 ++++++++++++++++++++++++++++++++- src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h | 31 +++- src/vnet/mfib/mfib_entry.c | 1 + 28 files changed, 944 insertions(+), 22 deletions(-) create mode 100644 src/vnet/adj/adj_nsh.c create mode 100644 src/vnet/adj/adj_nsh.h (limited to 'src/vnet/lisp-cp/lisp_types.h') diff --git a/src/vnet.am b/src/vnet.am index 9b148f69..a8cc696f 100644 --- a/src/vnet.am +++ b/src/vnet.am @@ -958,12 +958,14 @@ libvnet_la_SOURCES += \ vnet/adj/adj_midchain.c \ vnet/adj/adj_mcast.c \ vnet/adj/adj_l2.c \ + vnet/adj/adj_nsh.c \ vnet/adj/adj.c nobase_include_HEADERS += \ vnet/adj/adj.h \ vnet/adj/adj_types.h \ vnet/adj/adj_glean.h \ + vnet/adj/adj_nsh.h \ vnet/adj/adj_nbr.h ######################################## diff --git a/src/vnet/adj/adj_internal.h b/src/vnet/adj/adj_internal.h index ece59121..30668625 100644 --- a/src/vnet/adj/adj_internal.h +++ b/src/vnet/adj/adj_internal.h @@ -20,7 +20,7 @@ #include #include #include - +#include /** * big switch to turn on Adjacency debugging @@ -53,6 +53,8 @@ adj_get_rewrite_node (vnet_link_t linkt) return (mpls_output_node.index); case VNET_LINK_ETHERNET: return (adj_l2_rewrite_node.index); + case VNET_LINK_NSH: + return (adj_nsh_rewrite_node.index); case VNET_LINK_ARP: break; } diff --git a/src/vnet/adj/adj_midchain.c b/src/vnet/adj/adj_midchain.c index 8c6ab5aa..35cdb003 100644 --- a/src/vnet/adj/adj_midchain.c +++ b/src/vnet/adj/adj_midchain.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -308,6 +309,18 @@ VNET_FEATURE_INIT (adj_midchain_tx_no_count_ethernet, static) = { .runs_before = VNET_FEATURES ("error-drop"), .feature_index_ptr = &adj_midchain_tx_no_count_feature_node[VNET_LINK_ETHERNET], }; +VNET_FEATURE_INIT (adj_midchain_tx_nsh, static) = { + .arc_name = "nsh-output", + .node_name = "adj-midchain-tx", + .runs_before = VNET_FEATURES ("error-drop"), + .feature_index_ptr = &adj_midchain_tx_feature_node[VNET_LINK_NSH], +}; +VNET_FEATURE_INIT (adj_midchain_tx_no_count_nsh, static) = { + .arc_name = "nsh-output", + .node_name = "adj-midchain-tx-no-count", + .runs_before = VNET_FEATURES ("error-drop"), + .feature_index_ptr = &adj_midchain_tx_no_count_feature_node[VNET_LINK_NSH], +}; static inline u32 adj_get_midchain_node (vnet_link_t link) @@ -321,6 +334,8 @@ adj_get_midchain_node (vnet_link_t link) return (mpls_midchain_node.index); case VNET_LINK_ETHERNET: return (adj_l2_midchain_node.index); + case VNET_LINK_NSH: + return (adj_nsh_midchain_node.index); case VNET_LINK_ARP: break; } @@ -354,6 +369,11 @@ adj_midchain_get_feature_arc_index_for_link_type (const ip_adjacency_t *adj) arc = ethernet_main.output_feature_arc_index; break; } + case VNET_LINK_NSH: + { + arc = nsh_main_dummy.output_feature_arc_index; + break; + } case VNET_LINK_ARP: ASSERT(0); break; diff --git a/src/vnet/adj/adj_nsh.c b/src/vnet/adj/adj_nsh.c new file mode 100644 index 00000000..9a0f9d8b --- /dev/null +++ b/src/vnet/adj/adj_nsh.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2017 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 +#include +#include + +nsh_main_dummy_t nsh_main_dummy; + +/** + * @brief Trace data for a NSH Midchain + */ +typedef struct adj_nsh_trace_t_ { + /** Adjacency index taken. */ + u32 adj_index; +} adj_nsh_trace_t; + +static u8 * +format_adj_nsh_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + adj_nsh_trace_t * t = va_arg (*args, adj_nsh_trace_t *); + + s = format (s, "adj-idx %d : %U", + t->adj_index, + format_ip_adjacency, t->adj_index, FORMAT_IP_ADJACENCY_NONE); + return s; +} + +typedef enum adj_nsh_rewrite_next_t_ +{ + ADJ_NSH_REWRITE_NEXT_DROP, +} adj_gpe_rewrite_next_t; + +always_inline uword +adj_nsh_rewrite_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame, + int is_midchain) +{ + u32 * from = vlib_frame_vector_args (frame); + u32 n_left_from, n_left_to_next, * to_next, next_index; + u32 cpu_index = os_get_cpu_number(); + + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + ip_adjacency_t * adj0; + vlib_buffer_t * p0; + char *h0; + u32 pi0, rw_len0, adj_index0, next0 = 0; + u32 tx_sw_if_index0; + + pi0 = to_next[0] = from[0]; + from += 1; + n_left_from -= 1; + to_next += 1; + n_left_to_next -= 1; + + p0 = vlib_get_buffer (vm, pi0); + h0 = vlib_buffer_get_current (p0); + + adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; + + /* We should never rewrite a pkt using the MISS adjacency */ + ASSERT(adj_index0); + + adj0 = adj_get (adj_index0); + + /* Guess we are only writing on simple IP4 header. */ + vnet_rewrite_one_header(adj0[0], h0, sizeof(ip4_header_t)); + + /* Update packet buffer attributes/set output interface. */ + rw_len0 = adj0[0].rewrite_header.data_bytes; + vnet_buffer(p0)->ip.save_rewrite_length = rw_len0; + + vlib_increment_combined_counter(&adjacency_counters, + cpu_index, + adj_index0, + /* packet increment */ 0, + /* byte increment */ rw_len0); + + /* Check MTU of outgoing interface. */ + if (PREDICT_TRUE((vlib_buffer_length_in_chain (vm, p0) <= + adj0[0].rewrite_header.max_l3_packet_bytes))) + { + /* Don't adjust the buffer for ttl issue; icmp-error node wants + * to see the IP headerr */ + p0->current_data -= rw_len0; + p0->current_length += rw_len0; + tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index; + + if (is_midchain) + { + adj0->sub_type.midchain.fixup_func(vm, adj0, p0); + } + + vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0; + + /* + * Follow the feature ARC. this will result eventually in + * the midchain-tx node + */ + vnet_feature_arc_start (nsh_main_dummy.output_feature_arc_index, + tx_sw_if_index0, &next0, p0); + } + else + { + /* can't fragment NSH */ + next0 = ADJ_NSH_REWRITE_NEXT_DROP; + } + + if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) + { + adj_nsh_trace_t *tr = vlib_add_trace (vm, node, + p0, sizeof (*tr)); + tr->adj_index = vnet_buffer(p0)->ip.adj_index[VLIB_TX]; + } + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + pi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +static uword +adj_nsh_rewrite (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return adj_nsh_rewrite_inline (vm, node, frame, 0); +} + +static uword +adj_nsh_midchain (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return adj_nsh_rewrite_inline (vm, node, frame, 1); +} + +VLIB_REGISTER_NODE (adj_nsh_rewrite_node) = { + .function = adj_nsh_rewrite, + .name = "adj-nsh-rewrite", + .vector_size = sizeof (u32), + + .format_trace = format_adj_nsh_trace, + + .n_next_nodes = 1, + .next_nodes = { + [ADJ_NSH_REWRITE_NEXT_DROP] = "error-drop", + }, +}; + +VLIB_NODE_FUNCTION_MULTIARCH (adj_nsh_rewrite_node, adj_nsh_rewrite) + +VLIB_REGISTER_NODE (adj_nsh_midchain_node) = { + .function = adj_nsh_midchain, + .name = "adj-nsh-midchain", + .vector_size = sizeof (u32), + + .format_trace = format_adj_nsh_trace, + + .n_next_nodes = 1, + .next_nodes = { + [ADJ_NSH_REWRITE_NEXT_DROP] = "error-drop", + }, +}; + +VLIB_NODE_FUNCTION_MULTIARCH (adj_nsh_midchain_node, adj_nsh_midchain) + +/* Built-in ip4 tx feature path definition */ +/* *INDENT-OFF* */ +VNET_FEATURE_ARC_INIT (nsh_output, static) = +{ + .arc_name = "nsh-output", + .start_nodes = VNET_FEATURES ("adj-nsh-midchain"), + .arc_index_ptr = &nsh_main_dummy.output_feature_arc_index, +}; + +VNET_FEATURE_INIT (nsh_tx_drop, static) = +{ + .arc_name = "nsh-output", + .node_name = "error-drop", + .runs_before = 0, /* not before any other features */ +}; +/* *INDENT-ON* */ diff --git a/src/vnet/adj/adj_nsh.h b/src/vnet/adj/adj_nsh.h new file mode 100644 index 00000000..5501fbb9 --- /dev/null +++ b/src/vnet/adj/adj_nsh.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 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. + */ + +#ifndef __ADJ_NSH_H__ +#define __ADJ_NSH_H__ + +#include + +extern vlib_node_registration_t adj_nsh_midchain_node; +extern vlib_node_registration_t adj_nsh_rewrite_node; + +typedef struct _nsh_main_dummy +{ + u8 output_feature_arc_index; +} nsh_main_dummy_t; + +extern nsh_main_dummy_t nsh_main_dummy; + +#endif diff --git a/src/vnet/dpo/dpo.c b/src/vnet/dpo/dpo.c index cc2fa0eb..d8e075a7 100644 --- a/src/vnet/dpo/dpo.c +++ b/src/vnet/dpo/dpo.c @@ -98,6 +98,8 @@ vnet_link_to_dpo_proto (vnet_link_t linkt) return (DPO_PROTO_MPLS); case VNET_LINK_ETHERNET: return (DPO_PROTO_ETHERNET); + case VNET_LINK_NSH: + return (DPO_PROTO_NSH); case VNET_LINK_ARP: break; } diff --git a/src/vnet/dpo/dpo.h b/src/vnet/dpo/dpo.h index aff4e1b8..48b92d3d 100644 --- a/src/vnet/dpo/dpo.h +++ b/src/vnet/dpo/dpo.h @@ -67,9 +67,10 @@ typedef enum dpo_proto_t_ DPO_PROTO_IP6, DPO_PROTO_ETHERNET, DPO_PROTO_MPLS, + DPO_PROTO_NSH, } __attribute__((packed)) dpo_proto_t; -#define DPO_PROTO_NUM ((dpo_proto_t)(DPO_PROTO_MPLS+1)) +#define DPO_PROTO_NUM ((dpo_proto_t)(DPO_PROTO_NSH+1)) #define DPO_PROTO_NONE ((dpo_proto_t)(DPO_PROTO_NUM+1)) #define DPO_PROTOS { \ @@ -77,11 +78,12 @@ typedef enum dpo_proto_t_ [DPO_PROTO_IP6] = "ip6", \ [DPO_PROTO_ETHERNET] = "ethernet", \ [DPO_PROTO_MPLS] = "mpls", \ + [DPO_PROTO_NSH] = "nsh", \ } #define FOR_EACH_DPO_PROTO(_proto) \ for (_proto = DPO_PROTO_IP4; \ - _proto <= DPO_PROTO_MPLS; \ + _proto <= DPO_PROTO_NSH; \ _proto++) /** diff --git a/src/vnet/fib/fib_entry_delegate.c b/src/vnet/fib/fib_entry_delegate.c index efe402d1..70840b16 100644 --- a/src/vnet/fib/fib_entry_delegate.c +++ b/src/vnet/fib/fib_entry_delegate.c @@ -122,6 +122,8 @@ fib_entry_chain_type_to_delegate_type (fib_forward_chain_type_t fct) case FIB_FORW_CHAIN_TYPE_MCAST_IP4: case FIB_FORW_CHAIN_TYPE_MCAST_IP6: break; + case FIB_FORW_CHAIN_TYPE_NSH: + return (FIB_ENTRY_DELEGATE_CHAIN_NSH); } ASSERT(0); return (FIB_ENTRY_DELEGATE_CHAIN_UNICAST_IP4); @@ -142,6 +144,8 @@ fib_entry_delegate_type_to_chain_type (fib_entry_delegate_type_t fdt) return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS); case FIB_ENTRY_DELEGATE_CHAIN_ETHERNET: return (FIB_FORW_CHAIN_TYPE_ETHERNET); + case FIB_ENTRY_DELEGATE_CHAIN_NSH: + return (FIB_FORW_CHAIN_TYPE_NSH); case FIB_ENTRY_DELEGATE_COVERED: case FIB_ENTRY_DELEGATE_ATTACHED_IMPORT: case FIB_ENTRY_DELEGATE_ATTACHED_EXPORT: diff --git a/src/vnet/fib/fib_entry_delegate.h b/src/vnet/fib/fib_entry_delegate.h index 6d3a6549..d9183c5f 100644 --- a/src/vnet/fib/fib_entry_delegate.h +++ b/src/vnet/fib/fib_entry_delegate.h @@ -35,6 +35,7 @@ typedef enum fib_entry_delegate_type_t_ { FIB_ENTRY_DELEGATE_CHAIN_MPLS_EOS = FIB_FORW_CHAIN_TYPE_MPLS_EOS, FIB_ENTRY_DELEGATE_CHAIN_MPLS_NON_EOS = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, FIB_ENTRY_DELEGATE_CHAIN_ETHERNET = FIB_FORW_CHAIN_TYPE_ETHERNET, + FIB_ENTRY_DELEGATE_CHAIN_NSH = FIB_FORW_CHAIN_TYPE_NSH, /** * Dependency list of covered entries. * these are more specific entries that are interested in changes @@ -51,7 +52,7 @@ typedef enum fib_entry_delegate_type_t_ { #define FOR_EACH_DELEGATE_CHAIN(_entry, _fdt, _fed, _body) \ { \ for (_fdt = FIB_ENTRY_DELEGATE_CHAIN_UNICAST_IP4; \ - _fdt <= FIB_ENTRY_DELEGATE_CHAIN_ETHERNET; \ + _fdt <= FIB_ENTRY_DELEGATE_CHAIN_NSH; \ _fdt++) \ { \ _fed = fib_entry_delegate_get(_entry, _fdt); \ diff --git a/src/vnet/fib/fib_entry_src.c b/src/vnet/fib/fib_entry_src.c index d54787cd..57109153 100644 --- a/src/vnet/fib/fib_entry_src.c +++ b/src/vnet/fib/fib_entry_src.c @@ -355,6 +355,7 @@ fib_entry_src_collect_forwarding (fib_node_index_t pl_index, break; } case FIB_FORW_CHAIN_TYPE_ETHERNET: + case FIB_FORW_CHAIN_TYPE_NSH: ASSERT(0); break; } diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c index 080057f3..aa545b5e 100644 --- a/src/vnet/fib/fib_path.c +++ b/src/vnet/fib/fib_path.c @@ -1755,6 +1755,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index, case FIB_FORW_CHAIN_TYPE_MPLS_EOS: case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS: case FIB_FORW_CHAIN_TYPE_ETHERNET: + case FIB_FORW_CHAIN_TYPE_NSH: { adj_index_t ai; @@ -1787,6 +1788,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index, case FIB_FORW_CHAIN_TYPE_MCAST_IP4: case FIB_FORW_CHAIN_TYPE_MCAST_IP6: case FIB_FORW_CHAIN_TYPE_ETHERNET: + case FIB_FORW_CHAIN_TYPE_NSH: ASSERT(0); break; } @@ -1809,6 +1811,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index, case FIB_FORW_CHAIN_TYPE_MCAST_IP4: case FIB_FORW_CHAIN_TYPE_MCAST_IP6: case FIB_FORW_CHAIN_TYPE_ETHERNET: + case FIB_FORW_CHAIN_TYPE_NSH: ASSERT(0); break; } @@ -1824,6 +1827,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index, case FIB_FORW_CHAIN_TYPE_UNICAST_IP6: case FIB_FORW_CHAIN_TYPE_MPLS_EOS: case FIB_FORW_CHAIN_TYPE_ETHERNET: + case FIB_FORW_CHAIN_TYPE_NSH: break; case FIB_FORW_CHAIN_TYPE_MCAST_IP4: case FIB_FORW_CHAIN_TYPE_MCAST_IP6: diff --git a/src/vnet/fib/fib_types.c b/src/vnet/fib/fib_types.c index 3ecb38e8..2837a59d 100644 --- a/src/vnet/fib/fib_types.c +++ b/src/vnet/fib/fib_types.c @@ -279,6 +279,8 @@ fib_forw_chain_type_from_dpo_proto (dpo_proto_t proto) return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS); case DPO_PROTO_ETHERNET: return (FIB_FORW_CHAIN_TYPE_ETHERNET); + case DPO_PROTO_NSH: + return (FIB_FORW_CHAIN_TYPE_NSH); } ASSERT(0); return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4); @@ -297,6 +299,8 @@ fib_forw_chain_type_to_link_type (fib_forward_chain_type_t fct) return (VNET_LINK_IP6); case FIB_FORW_CHAIN_TYPE_ETHERNET: return (VNET_LINK_ETHERNET); + case FIB_FORW_CHAIN_TYPE_NSH: + return (VNET_LINK_NSH); case FIB_FORW_CHAIN_TYPE_MPLS_EOS: /* * insufficient information to to convert @@ -322,6 +326,8 @@ fib_forw_chain_type_to_dpo_proto (fib_forward_chain_type_t fct) return (DPO_PROTO_IP6); case FIB_FORW_CHAIN_TYPE_ETHERNET: return (DPO_PROTO_ETHERNET); + case FIB_FORW_CHAIN_TYPE_NSH: + return (DPO_PROTO_NSH); case FIB_FORW_CHAIN_TYPE_MPLS_EOS: case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS: return (DPO_PROTO_MPLS); diff --git a/src/vnet/fib/fib_types.h b/src/vnet/fib/fib_types.h index c51bc9c0..05e0e0af 100644 --- a/src/vnet/fib/fib_types.h +++ b/src/vnet/fib/fib_types.h @@ -105,10 +105,14 @@ typedef enum fib_forward_chain_type_t_ { FIB_FORW_CHAIN_TYPE_MCAST_IP6, /** * Contribute an object that is to be used to forward Ethernet packets. + */ + FIB_FORW_CHAIN_TYPE_ETHERNET, + /** + * Contribute an object that is to be used to forward NSH packets. * This is last in the list since it is not valid for many FIB objects, * and thus their array of per-chain-type DPOs can be sized smaller. */ - FIB_FORW_CHAIN_TYPE_ETHERNET, + FIB_FORW_CHAIN_TYPE_NSH, } __attribute__ ((packed)) fib_forward_chain_type_t; #define FIB_FORW_CHAINS { \ @@ -119,14 +123,15 @@ typedef enum fib_forward_chain_type_t_ { [FIB_FORW_CHAIN_TYPE_MCAST_IP6] = "multicast-ip6", \ [FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS] = "mpls-neos", \ [FIB_FORW_CHAIN_TYPE_MPLS_EOS] = "mpls-eos", \ + [FIB_FORW_CHAIN_TYPE_NSH] = "nsh", \ } -#define FIB_FORW_CHAIN_NUM (FIB_FORW_CHAIN_TYPE_MPLS_ETHERNET+1) +#define FIB_FORW_CHAIN_NUM (FIB_FORW_CHAIN_TYPE_NSH+1) #define FIB_FORW_CHAIN_MPLS_NUM (FIB_FORW_CHAIN_TYPE_MPLS_EOS+1) #define FOR_EACH_FIB_FORW_CHAIN(_item) \ for (_item = FIB_FORW_CHAIN_TYPE_UNICAST_IP4; \ - _item <= FIB_FORW_CHAIN_TYPE_ETHERNET; \ + _item <= FIB_FORW_CHAIN_TYPE_NSH; \ _item++) #define FOR_EACH_FIB_FORW_MPLS_CHAIN(_item) \ diff --git a/src/vnet/gre/gre.c b/src/vnet/gre/gre.c index 0faed13e..cd43a3af 100644 --- a/src/vnet/gre/gre.c +++ b/src/vnet/gre/gre.c @@ -177,6 +177,9 @@ gre_proto_from_vnet_link (vnet_link_t link) return (GRE_PROTOCOL_teb); case VNET_LINK_ARP: return (GRE_PROTOCOL_arp); + case VNET_LINK_NSH: + ASSERT(0); + break; } ASSERT(0); return (GRE_PROTOCOL_ip4); diff --git a/src/vnet/interface.c b/src/vnet/interface.c index 9454ac18..2a1e70e8 100644 --- a/src/vnet/interface.c +++ b/src/vnet/interface.c @@ -1364,6 +1364,7 @@ vnet_link_to_l3_proto (vnet_link_t link) case VNET_LINK_ARP: return (VNET_L3_PACKET_TYPE_ARP); case VNET_LINK_ETHERNET: + case VNET_LINK_NSH: ASSERT (0); break; } diff --git a/src/vnet/interface.h b/src/vnet/interface.h index d42e5fda..7b791751 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -240,6 +240,7 @@ typedef enum vnet_link_t_ VNET_LINK_MPLS, VNET_LINK_ETHERNET, VNET_LINK_ARP, + VNET_LINK_NSH, } __attribute__ ((packed)) vnet_link_t; #define VNET_LINKS { \ @@ -248,13 +249,14 @@ typedef enum vnet_link_t_ [VNET_LINK_IP6] = "ipv6", \ [VNET_LINK_MPLS] = "mpls", \ [VNET_LINK_ARP] = "arp", \ + [VNET_LINK_NSH] = "nsh", \ } /** * @brief Number of link types. Not part of the enum so it does not have to be included in * switch statements */ -#define VNET_LINK_NUM (VNET_LINK_ARP+1) +#define VNET_LINK_NUM (VNET_LINK_NSH+1) /** * @brief Convert a link to to an Ethertype diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index cc73dfc5..f0383e16 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -2700,6 +2700,11 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, gid_address_vni (dst) = vni; gid_address_vni (src) = vni; } + else if (LISP_AFI_LCAF == type) + { + /* Eventually extend this to support NSH and other */ + ASSERT (0); + } } static uword @@ -2818,6 +2823,14 @@ lisp_cp_lookup_l2 (vlib_main_t * vm, return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_MAC)); } +static uword +lisp_cp_lookup_nsh (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * from_frame) +{ + /* TODO decide if NSH should be propagated as LCAF or not */ + return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_LCAF)); +} + /* *INDENT-OFF* */ VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = { .function = lisp_cp_lookup_ip4, @@ -2875,6 +2888,25 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = { }; /* *INDENT-ON* */ +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (lisp_cp_lookup_nsh_node) = { + .function = lisp_cp_lookup_nsh, + .name = "lisp-cp-lookup-nsh", + .vector_size = sizeof (u32), + .format_trace = format_lisp_cp_lookup_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = LISP_CP_LOOKUP_N_ERROR, + .error_strings = lisp_cp_lookup_error_strings, + + .n_next_nodes = LISP_CP_LOOKUP_N_NEXT, + + .next_nodes = { + [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + /* lisp_cp_input statistics */ #define foreach_lisp_cp_input_error \ _(DROP, "drop") \ diff --git a/src/vnet/lisp-cp/lisp_api.c b/src/vnet/lisp-cp/lisp_api.c index a877540b..78d32e17 100644 --- a/src/vnet/lisp-cp/lisp_api.c +++ b/src/vnet/lisp-cp/lisp_api.c @@ -714,6 +714,8 @@ fid_type_to_api_type (fid_address_t * fid) case FID_ADDR_MAC: return 2; + case FID_ADDR_NSH: + return 3; } return ~0; diff --git a/src/vnet/lisp-cp/lisp_cp_dpo.c b/src/vnet/lisp-cp/lisp_cp_dpo.c index 185b07a2..848f621e 100644 --- a/src/vnet/lisp-cp/lisp_cp_dpo.c +++ b/src/vnet/lisp-cp/lisp_cp_dpo.c @@ -79,12 +79,17 @@ const static char *const lisp_cp_ethernet_nodes[] = { NULL, }; +const static char *const lisp_cp_nsh_nodes[] = { + "lisp-cp-lookup-nsh", + NULL, +}; const static char *const *const lisp_cp_nodes[DPO_PROTO_NUM] = { [DPO_PROTO_IP4] = lisp_cp_ip4_nodes, [DPO_PROTO_IP6] = lisp_cp_ip6_nodes, [DPO_PROTO_ETHERNET] = lisp_cp_ethernet_nodes, [DPO_PROTO_MPLS] = NULL, + [DPO_PROTO_NSH] = lisp_cp_nsh_nodes, }; clib_error_t * diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c index 748905d2..4a3d05b7 100644 --- a/src/vnet/lisp-cp/lisp_types.c +++ b/src/vnet/lisp-cp/lisp_types.c @@ -202,6 +202,20 @@ format_mac_address (u8 * s, va_list * args) a[0], a[1], a[2], a[3], a[4], a[5]); } +uword +unformat_nsh_address (unformat_input_t * input, va_list * args) +{ + nsh_t *a = va_arg (*args, nsh_t *); + return unformat (input, "SPI:%d SI:%d", &a->spi, &a->si); +} + +u8 * +format_nsh_address (u8 * s, va_list * args) +{ + nsh_t *a = va_arg (*args, nsh_t *); + return format (s, "SPI:%d SI:%d", a->spi, a->si); +} + u8 * format_fid_address (u8 * s, va_list * args) { @@ -211,9 +225,10 @@ format_fid_address (u8 * s, va_list * args) { case FID_ADDR_IP_PREF: return format (s, "%U", format_ip_prefix, &fid_addr_ippref (a)); - case FID_ADDR_MAC: return format (s, "%U", format_mac_address, &fid_addr_mac (a)); + case FID_ADDR_NSH: + return format (s, "%U", format_nsh_address, &fid_addr_nsh (a)); default: clib_warning ("Can't format fid address type %d!", fid_addr_type (a)); @@ -239,6 +254,8 @@ format_gid_address (u8 * s, va_list * args) case GID_ADDR_MAC: return format (s, "[%d] %U", gid_address_vni (a), format_mac_address, &gid_address_mac (a)); + case GID_ADDR_NSH: + return format (s, "%U", format_nsh_address, &gid_address_nsh (a)); default: clib_warning ("Can't format gid type %d", type); return 0; @@ -252,6 +269,7 @@ unformat_fid_address (unformat_input_t * i, va_list * args) fid_address_t *a = va_arg (*args, fid_address_t *); ip_prefix_t ippref; u8 mac[6] = { 0 }; + nsh_t nsh; if (unformat (i, "%U", unformat_ip_prefix, &ippref)) { @@ -263,6 +281,11 @@ unformat_fid_address (unformat_input_t * i, va_list * args) fid_addr_type (a) = FID_ADDR_MAC; mac_copy (fid_addr_mac (a), mac); } + else if (unformat (i, "%U", unformat_nsh_address, &nsh)) + { + fid_addr_type (a) = FID_ADDR_NSH; + nsh_copy (&fid_addr_nsh (a), mac); + } else return 0; @@ -301,6 +324,7 @@ unformat_gid_address (unformat_input_t * input, va_list * args) u8 mac[6] = { 0 }; ip_prefix_t ippref; fid_address_t sim1, sim2; + nsh_t nsh; memset (&ippref, 0, sizeof (ippref)); memset (&sim1, 0, sizeof (sim1)); @@ -323,6 +347,11 @@ unformat_gid_address (unformat_input_t * input, va_list * args) mac_copy (gid_address_mac (a), mac); gid_address_type (a) = GID_ADDR_MAC; } + else if (unformat (input, "%U", unformat_nsh_address, &nsh)) + { + nsh_copy (&gid_address_nsh (a), &nsh); + gid_address_type (a) = GID_ADDR_NSH; + } else return 0; @@ -588,6 +617,10 @@ fid_addr_parse (u8 * p, fid_address_t * a) case FID_ADDR_IP_PREF: return ip_address_parse (p, afi, ip_addr); + + case FID_ADDR_NSH: + ASSERT (0); + break; } return ~0; } @@ -917,6 +950,12 @@ mac_copy (void *dst, void *src) clib_memcpy (dst, src, 6); } +void +nsh_copy (void *dst, void *src) +{ + clib_memcpy (dst, src, sizeof (nsh_t)); +} + void sd_copy (void *dst, void *src) { @@ -1083,6 +1122,8 @@ fid_address_length (fid_address_t * a) return ip_prefix_length (&fid_addr_ippref (a)); case FID_ADDR_MAC: return 0; + case FID_ADDR_NSH: + return 0; } return 0; } diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h index ac58b894..e43f5ab0 100644 --- a/src/vnet/lisp-cp/lisp_types.h +++ b/src/vnet/lisp-cp/lisp_types.h @@ -89,6 +89,7 @@ typedef enum GID_ADDR_LCAF, GID_ADDR_MAC, GID_ADDR_SRC_DST, + GID_ADDR_NSH, GID_ADDR_NO_ADDRESS, GID_ADDR_TYPES } gid_address_type_t; @@ -106,7 +107,8 @@ typedef enum typedef enum fid_addr_type_t_ { FID_ADDR_IP_PREF, - FID_ADDR_MAC + FID_ADDR_MAC, + FID_ADDR_NSH } __attribute__ ((packed)) fid_addr_type_t; /* flat address type */ @@ -116,6 +118,7 @@ typedef struct { ip_prefix_t ippref; u8 mac[6]; + u32 nsh; }; fid_addr_type_t type; } fid_address_t; @@ -124,6 +127,7 @@ typedef fid_address_t dp_address_t; #define fid_addr_ippref(_a) (_a)->ippref #define fid_addr_mac(_a) (_a)->mac +#define fid_addr_nsh(_a) (_a)->nsh #define fid_addr_type(_a) (_a)->type u8 *format_fid_address (u8 * s, va_list * args); @@ -153,6 +157,12 @@ typedef struct #define vni_mask_len(_a) (_a)->vni_mask_len #define vni_gid(_a) (_a)->gid_addr +typedef struct +{ + u32 spi; + u8 si; +} nsh_t; + typedef struct { /* the union needs to be at the beginning! */ @@ -177,6 +187,7 @@ typedef struct _gid_address_t lcaf_t lcaf; u8 mac[6]; source_dest_t sd; + nsh_t nsh; }; u8 type; u32 vni; @@ -232,6 +243,7 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); #define gid_address_ip_version(_a) ip_addr_version(&gid_address_ip(_a)) #define gid_address_lcaf(_a) (_a)->lcaf #define gid_address_mac(_a) (_a)->mac +#define gid_address_nsh(_a) (_a)->nsh #define gid_address_vni(_a) (_a)->vni #define gid_address_vni_mask(_a) (_a)->vni_mask #define gid_address_sd_dst_ippref(_a) sd_dst_ippref(&(_a)->sd) @@ -249,6 +261,7 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); _(ip_prefix) \ _(lcaf) \ _(mac) \ + _(nsh) \ _(sd) /* *INDENT-OFF* */ diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c index 3288b241..d12dc362 100644 --- a/src/vnet/lisp-gpe/interface.c +++ b/src/vnet/lisp-gpe/interface.c @@ -201,7 +201,7 @@ VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = { typedef struct { - u32 lb_index; + u32 dpo_index; } l2_lisp_gpe_tx_trace_t; static u8 * @@ -211,7 +211,7 @@ format_l2_lisp_gpe_tx_trace (u8 * s, va_list * args) CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); l2_lisp_gpe_tx_trace_t *t = va_arg (*args, l2_lisp_gpe_tx_trace_t *); - s = format (s, "L2-LISP-GPE-TX: load-balance %d", t->lb_index); + s = format (s, "L2-LISP-GPE-TX: load-balance %d", t->dpo_index); return s; } @@ -278,7 +278,7 @@ l2_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node, { l2_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); - tr->lb_index = lbi0; + tr->dpo_index = lbi0; } vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, l2_arc_to_lb); @@ -306,6 +306,110 @@ VNET_DEVICE_CLASS (l2_lisp_gpe_device_class,static) = { }; /* *INDENT-ON* */ +typedef struct +{ + u32 dpo_index; +} nsh_lisp_gpe_tx_trace_t; + +u8 * +format_nsh_lisp_gpe_tx_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + nsh_lisp_gpe_tx_trace_t *t = va_arg (*args, nsh_lisp_gpe_tx_trace_t *); + + s = format (s, "NSH-GPE-TX: tunnel %d", t->dpo_index); + return s; +} + +/** + * @brief LISP-GPE interface TX for NSH overlays. + * @node nsh_lisp_gpe_interface_tx + * + * The NSH LISP-GPE interface TX function. + * + * @param[in] vm vlib_main_t corresponding to the current thread. + * @param[in] node vlib_node_runtime_t data for this node. + * @param[in] frame vlib_frame_t whose contents should be dispatched. + * + * @return number of vectors in frame. + */ +static uword +nsh_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 n_left_from, next_index, *from, *to_next; + lisp_gpe_main_t *lgm = &lisp_gpe_main; + + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + vlib_buffer_t *b0; + u32 bi0; + u32 *nsh0, next0; + const dpo_id_t *dpo0; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + nsh0 = vlib_buffer_get_current (b0); + + vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_LCAF; + + /* lookup SPI + SI (second word of the NSH header). + * NB: Load balancing was done by the control plane */ + dpo0 = lisp_nsh_fib_lookup (lgm, nsh0[1]); + + next0 = dpo0->dpoi_next_node; + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; + + if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) + { + nsh_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0, + sizeof (*tr)); + tr->dpo_index = dpo0->dpoi_index; + } + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return from_frame->n_vectors; +} + +static u8 * +format_nsh_lisp_gpe_name (u8 * s, va_list * args) +{ + u32 dev_instance = va_arg (*args, u32); + return format (s, "nsh_lisp_gpe%d", dev_instance); +} + +/* *INDENT-OFF* */ +VNET_DEVICE_CLASS (nsh_lisp_gpe_device_class,static) = { + .name = "NSH_LISP_GPE", + .format_device_name = format_nsh_lisp_gpe_name, + .format_tx_trace = format_nsh_lisp_gpe_tx_trace, + .tx_function = nsh_lisp_gpe_interface_tx, +}; +/* *INDENT-ON* */ + static vnet_hw_interface_t * lisp_gpe_create_iface (lisp_gpe_main_t * lgm, u32 vni, u32 dp_table, vnet_device_class_t * dev_class, @@ -615,6 +719,72 @@ lisp_gpe_del_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id) lisp_gpe_remove_iface (lgm, hip[0], bd_index, &lgm->l2_ifaces); } +/** + * @brief Add LISP-GPE NSH interface. + * + * Creates LISP-GPE interface, sets it in L3 mode. + * + * @param[in] lgm Reference to @ref lisp_gpe_main_t. + * @param[in] a Parameters to create interface. + * + * @return sw_if_index. + */ +u32 +lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm) +{ + vnet_main_t *vnm = lgm->vnet_main; + tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces; + vnet_hw_interface_t *hi; + uword *hip, *si; + + hip = hash_get (nsh_ifaces->hw_if_index_by_dp_table, 0); + + if (hip) + { + clib_warning ("NSH interface 0 already exists"); + return ~0; + } + + si = hash_get (nsh_ifaces->sw_if_index_by_vni, 0); + if (si) + { + clib_warning ("NSH interface already exists"); + return ~0; + } + + /* create lisp iface and populate tunnel tables */ + hi = lisp_gpe_create_iface (lgm, 0, 0, + &nsh_lisp_gpe_device_class, &lgm->nsh_ifaces); + + /* enable interface */ + vnet_sw_interface_set_flags (vnm, hi->sw_if_index, + VNET_SW_INTERFACE_FLAG_ADMIN_UP); + vnet_hw_interface_set_flags (vnm, hi->hw_if_index, + VNET_HW_INTERFACE_FLAG_LINK_UP); + + return (hi->sw_if_index); +} + +/** + * @brief Del LISP-GPE NSH interface. + * + */ +void +lisp_gpe_del_nsh_iface (lisp_gpe_main_t * lgm) +{ + tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces; + uword *hip; + + hip = hash_get (nsh_ifaces->hw_if_index_by_dp_table, 0); + + if (hip == 0) + { + clib_warning ("The NSH 0 interface doesn't exist"); + return; + } + lisp_gpe_remove_iface (lgm, hip[0], 0, &lgm->nsh_ifaces); +} + static clib_error_t * lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) @@ -623,6 +793,7 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, u8 is_add = 1; u32 table_id, vni, bd_id; u8 vni_is_set = 0, vrf_is_set = 0, bd_index_is_set = 0; + u8 nsh_iface = 0; if (vnet_lisp_gpe_enable_disable_status () == 0) { @@ -651,6 +822,10 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, { bd_index_is_set = 1; } + else if (unformat (line_input, "nsh")) + { + nsh_iface = 1; + } else { return clib_error_return (0, "parse error: '%U'", @@ -689,6 +864,21 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, lisp_gpe_tenant_l3_iface_unlock (vni); } + if (nsh_iface) + { + if (is_add) + { + if (~0 == lisp_gpe_add_nsh_iface (&lisp_gpe_main)) + { + return clib_error_return (0, "NSH interface not created"); + } + else + { + lisp_gpe_del_nsh_iface (&lisp_gpe_main); + } + } + } + return (NULL); } diff --git a/src/vnet/lisp-gpe/lisp_gpe.c b/src/vnet/lisp-gpe/lisp_gpe.c index e78d45c9..e76c03f0 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.c +++ b/src/vnet/lisp-gpe/lisp_gpe.c @@ -151,6 +151,7 @@ lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm, gid_address_copy (&a->lcl_eid, leid); gid_address_copy (&a->rmt_eid, reid); a->locator_pairs = pairs; + a->action = action; rv = vnet_lisp_gpe_add_del_fwd_entry (a, 0); if (0 != rv) @@ -291,7 +292,6 @@ format_vnet_lisp_gpe_status (u8 * s, va_list * args) return format (s, "%s", lgm->is_en ? "enabled" : "disabled"); } - /** LISP-GPE init function. */ clib_error_t * lisp_gpe_init (vlib_main_t * vm) diff --git a/src/vnet/lisp-gpe/lisp_gpe.h b/src/vnet/lisp-gpe/lisp_gpe.h index 3288c99f..e92df385 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.h +++ b/src/vnet/lisp-gpe/lisp_gpe.h @@ -119,6 +119,15 @@ typedef struct lisp_gpe_main /** Load-balance for a miss in the table */ dpo_id_t l2_lb_cp_lkup; + /* NSH data structures + * ================== */ + + BVT (clib_bihash) nsh_fib; + + tunnel_lookup_t nsh_ifaces; + + const dpo_id_t *nsh_cp_lkup; + /** convenience */ vlib_main_t *vlib_main; vnet_main_t *vnet_main; diff --git a/src/vnet/lisp-gpe/lisp_gpe_adjacency.c b/src/vnet/lisp-gpe/lisp_gpe_adjacency.c index 8c96a25c..1dbf8677 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_adjacency.c +++ b/src/vnet/lisp-gpe/lisp_gpe_adjacency.c @@ -211,6 +211,8 @@ lisp_gpe_adj_proto_from_vnet_link_type (vnet_link_t linkt) return (LISP_GPE_NEXT_PROTO_IP6); case VNET_LINK_ETHERNET: return (LISP_GPE_NEXT_PROTO_ETHERNET); + case VNET_LINK_NSH: + return (LISP_GPE_NEXT_PROTO_NSH); default: ASSERT (0); } @@ -254,14 +256,14 @@ lisp_gpe_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai) ladj = pool_elt_at_index (lisp_adj_pool, lai); lgt = lisp_gpe_tunnel_get (ladj->tunnel_index); linkt = adj_get_link_type (ai); - adj_nbr_midchain_update_rewrite (ai, lisp_gpe_fixup, (VNET_LINK_ETHERNET == linkt ? ADJ_MIDCHAIN_FLAG_NO_COUNT : ADJ_MIDCHAIN_FLAG_NONE), - lisp_gpe_tunnel_build_rewrite - (lgt, ladj, lisp_gpe_adj_proto_from_vnet_link_type (linkt))); + lisp_gpe_tunnel_build_rewrite (lgt, ladj, + lisp_gpe_adj_proto_from_vnet_link_type + (linkt))); lisp_gpe_adj_stack_one (ladj, ai); } diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c index 7ad8679e..e51b585e 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c +++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c @@ -340,10 +340,14 @@ gid_to_dp_address (gid_address_t * g, dp_address_t * d) d->type = FID_ADDR_IP_PREF; break; case GID_ADDR_MAC: - default: mac_copy (&d->mac, &gid_address_mac (g)); d->type = FID_ADDR_MAC; break; + case GID_ADDR_NSH: + default: + d->nsh = gid_address_nsh (g).spi << 8 | gid_address_nsh (g).si; + d->type = FID_ADDR_NSH; + break; } } @@ -671,7 +675,7 @@ del_l2_fwd_entry (lisp_gpe_main_t * lgm, } /** - * @brief Construct and insert the forwarding information used by a L2 entry + * @brief Construct and insert the forwarding information used by an L2 entry */ static void lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe) @@ -688,7 +692,16 @@ lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe) } else { - dpo_copy (&dpo, &lgm->l2_lb_cp_lkup); + switch (lfe->action) + { + case SEND_MAP_REQUEST: + dpo_copy (&dpo, &lgm->l2_lb_cp_lkup); + break; + case NO_ACTION: + case FORWARD_NATIVE: + case DROP: + dpo_copy (&dpo, drop_dpo_get (DPO_PROTO_ETHERNET)); + } } /* add entry to l2 lisp fib */ @@ -784,6 +797,276 @@ add_l2_fwd_entry (lisp_gpe_main_t * lgm, return 0; } +/** + * @brief Lookup NSH SD FIB entry + * + * Does an SPI+SI lookup in the NSH LISP FIB. + * + * @param[in] lgm Reference to @ref lisp_gpe_main_t. + * @param[in] spi_si SPI + SI. + * + * @return next node index. + */ +const dpo_id_t * +lisp_nsh_fib_lookup (lisp_gpe_main_t * lgm, u32 spi_si) +{ + int rv; + BVT (clib_bihash_kv) kv, value; + + memset (&kv, 0, sizeof (kv)); + kv.key[0] = spi_si; + rv = BV (clib_bihash_search_inline_2) (&lgm->nsh_fib, &kv, &value); + + if (rv != 0) + { + return lgm->nsh_cp_lkup; + } + else + { + lisp_gpe_fwd_entry_t *lfe; + lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, value.value); + return &lfe->nsh.choice; + } +} + +/** + * @brief Add/del NSH FIB entry + * + * Inserts value in NSH FIB keyed by SPI+SI. If entry is + * overwritten the associated value is returned. + * + * @param[in] lgm Reference to @ref lisp_gpe_main_t. + * @param[in] spi_si SPI + SI. + * @param[in] dpo Load balanced mapped to SPI + SI + * + * @return ~0 or value of overwritten entry. + */ +static u32 +lisp_nsh_fib_add_del_entry (u32 spi_si, u32 lfei, u8 is_add) +{ + lisp_gpe_main_t *lgm = &lisp_gpe_main; + BVT (clib_bihash_kv) kv, value; + u32 old_val = ~0; + + memset (&kv, 0, sizeof (kv)); + kv.key[0] = spi_si; + kv.value = 0ULL; + + if (BV (clib_bihash_search) (&lgm->nsh_fib, &kv, &value) == 0) + old_val = value.value; + + if (!is_add) + BV (clib_bihash_add_del) (&lgm->nsh_fib, &kv, 0 /* is_add */ ); + else + { + kv.value = lfei; + BV (clib_bihash_add_del) (&lgm->nsh_fib, &kv, 1 /* is_add */ ); + } + return old_val; +} + +#define NSH_FIB_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) +#define NSH_FIB_DEFAULT_HASH_MEMORY_SIZE (32<<20) + +static void +nsh_fib_init (lisp_gpe_main_t * lgm) +{ + BV (clib_bihash_init) (&lgm->nsh_fib, "nsh fib", + 1 << max_log2 (NSH_FIB_DEFAULT_HASH_NUM_BUCKETS), + NSH_FIB_DEFAULT_HASH_MEMORY_SIZE); + + /* + * the result from a 'miss' in a NSH Table + */ + lgm->nsh_cp_lkup = lisp_cp_dpo_get (DPO_PROTO_NSH); +} + +static void +del_nsh_fwd_entry_i (lisp_gpe_main_t * lgm, lisp_gpe_fwd_entry_t * lfe) +{ + lisp_fwd_path_t *path; + + if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type) + { + vec_foreach (path, lfe->paths) + { + lisp_gpe_adjacency_unlock (path->lisp_adj); + } + fib_path_list_child_remove (lfe->nsh.path_list_index, + lfe->nsh.child_index); + dpo_reset (&lfe->nsh.choice); + } + + lisp_nsh_fib_add_del_entry (fid_addr_nsh (&lfe->key->rmt), (u32) ~ 0, 0); + + hash_unset_mem (lgm->lisp_gpe_fwd_entries, lfe->key); + clib_mem_free (lfe->key); + pool_put (lgm->lisp_fwd_entry_pool, lfe); +} + +/** + * @brief Delete LISP NSH forwarding entry. + * + * Coordinates the removal of forwarding entries for NSH LISP overlay: + * + * @param[in] lgm Reference to @ref lisp_gpe_main_t. + * @param[in] a Parameters for building the forwarding entry. + * + * @return 0 on success. + */ +static int +del_nsh_fwd_entry (lisp_gpe_main_t * lgm, + vnet_lisp_gpe_add_del_fwd_entry_args_t * a) +{ + lisp_gpe_fwd_entry_key_t key; + lisp_gpe_fwd_entry_t *lfe; + + lfe = find_fwd_entry (lgm, a, &key); + + if (NULL == lfe) + return VNET_API_ERROR_INVALID_VALUE; + + del_nsh_fwd_entry_i (lgm, lfe); + + return (0); +} + +/** + * @brief Construct and insert the forwarding information used by an NSH entry + */ +static void +lisp_gpe_nsh_update_fwding (lisp_gpe_fwd_entry_t * lfe) +{ + lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); + dpo_id_t dpo = DPO_INVALID; + vnet_hw_interface_t *hi; + uword *hip; + + if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type) + { + fib_path_list_contribute_forwarding (lfe->nsh.path_list_index, + FIB_FORW_CHAIN_TYPE_NSH, + &lfe->nsh.dpo); + + /* + * LISP encap is always the same for this SPI+SI so we do that hash now + * and stack on the choice. + */ + if (DPO_LOAD_BALANCE == lfe->nsh.dpo.dpoi_type) + { + const dpo_id_t *tmp; + const load_balance_t *lb; + int hash; + + lb = load_balance_get (lfe->nsh.dpo.dpoi_index); + hash = fid_addr_nsh (&lfe->key->rmt) % lb->lb_n_buckets; + tmp = + load_balance_get_bucket_i (lb, hash & lb->lb_n_buckets_minus_1); + + dpo_copy (&dpo, tmp); + } + } + else + { + switch (lfe->action) + { + case SEND_MAP_REQUEST: + dpo_copy (&dpo, lgm->nsh_cp_lkup); + break; + case NO_ACTION: + case FORWARD_NATIVE: + case DROP: + dpo_copy (&dpo, drop_dpo_get (DPO_PROTO_NSH)); + } + } + + /* We have only one nsh-lisp interface (no NSH virtualization) */ + hip = hash_get (lgm->nsh_ifaces.hw_if_index_by_dp_table, 0); + hi = vnet_get_hw_interface (lgm->vnet_main, hip[0]); + + dpo_stack_from_node (hi->tx_node_index, &lfe->nsh.choice, &dpo); + + /* add entry to nsh lisp fib */ + lisp_nsh_fib_add_del_entry (fid_addr_nsh (&lfe->key->rmt), + lfe - lgm->lisp_fwd_entry_pool, 1); + + dpo_reset (&dpo); +} + +/** + * @brief Add LISP NSH forwarding entry. + * + * Coordinates the creation of forwarding entries for L2 LISP overlay: + * creates lisp-gpe tunnel and injects new entry in Source/Dest L2 FIB. + * + * @param[in] lgm Reference to @ref lisp_gpe_main_t. + * @param[in] a Parameters for building the forwarding entry. + * + * @return 0 on success. + */ +static int +add_nsh_fwd_entry (lisp_gpe_main_t * lgm, + vnet_lisp_gpe_add_del_fwd_entry_args_t * a) +{ + lisp_gpe_fwd_entry_key_t key; + lisp_gpe_fwd_entry_t *lfe; + + lfe = find_fwd_entry (lgm, a, &key); + + if (NULL != lfe) + /* don't support updates */ + return VNET_API_ERROR_INVALID_VALUE; + + pool_get (lgm->lisp_fwd_entry_pool, lfe); + memset (lfe, 0, sizeof (*lfe)); + lfe->key = clib_mem_alloc (sizeof (key)); + memcpy (lfe->key, &key, sizeof (key)); + + hash_set_mem (lgm->lisp_gpe_fwd_entries, lfe->key, + lfe - lgm->lisp_fwd_entry_pool); + + lfe->type = (a->is_negative ? + LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE : + LISP_GPE_FWD_ENTRY_TYPE_NORMAL); + lfe->tenant = 0; + + if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type) + { + fib_route_path_t *rpaths; + + /* + * Make the sorted array of LISP paths with their resp. adjacency + */ + lisp_gpe_fwd_entry_mk_paths (lfe, a); + + /* + * From the LISP paths, construct a FIB path list that will + * contribute a load-balance. + */ + rpaths = lisp_gpe_mk_fib_paths (lfe->paths); + + lfe->nsh.path_list_index = + fib_path_list_create (FIB_PATH_LIST_FLAG_NONE, rpaths); + + /* + * become a child of the path-list so we receive updates when + * its forwarding state changes. this includes an implicit lock. + */ + lfe->nsh.child_index = + fib_path_list_child_add (lfe->nsh.path_list_index, + FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY, + lfe - lgm->lisp_fwd_entry_pool); + } + else + { + lfe->action = a->action; + } + + lisp_gpe_nsh_update_fwding (lfe); + + return 0; +} + /** * @brief conver from the embedded fib_node_t struct to the LSIP entry */ @@ -802,7 +1085,12 @@ static fib_node_back_walk_rc_t lisp_gpe_fib_node_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx) { - lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_from_fib_node (node)); + lisp_gpe_fwd_entry_t *lfe = lisp_gpe_fwd_entry_from_fib_node (node); + + if (fid_addr_type (&lfe->key->rmt) == FID_ADDR_MAC) + lisp_gpe_l2_update_fwding (lfe); + else if (fid_addr_type (&lfe->key->rmt) == FID_ADDR_NSH) + lisp_gpe_nsh_update_fwding (lfe); return (FIB_NODE_BACK_WALK_CONTINUE); } @@ -877,6 +1165,11 @@ vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, return add_l2_fwd_entry (lgm, a); else return del_l2_fwd_entry (lgm, a); + case GID_ADDR_NSH: + if (a->is_add) + return add_nsh_fwd_entry (lgm, a); + else + return del_nsh_fwd_entry (lgm, a); default: clib_warning ("Forwarding entries for type %d not supported!", type); return -1; @@ -903,6 +1196,9 @@ vnet_lisp_gpe_fwd_entry_flush (void) case FID_ADDR_IP_PREF: del_ip_fwd_entry_i (lgm, lfe); break; + case FID_ADDR_NSH: + del_nsh_fwd_entry_i (lgm, lfe); + break; } })); /* *INDENT-ON* */ @@ -967,6 +1263,10 @@ format_lisp_gpe_fwd_entry (u8 * s, va_list ap) s = format (s, " fib-path-list:%d\n", lfe->l2.path_list_index); s = format (s, " dpo:%U\n", format_dpo_id, &lfe->l2.dpo, 0); break; + case FID_ADDR_NSH: + s = format (s, " fib-path-list:%d\n", lfe->nsh.path_list_index); + s = format (s, " dpo:%U\n", format_dpo_id, &lfe->nsh.dpo, 0); + break; case FID_ADDR_IP_PREF: break; } @@ -1036,6 +1336,7 @@ lisp_gpe_fwd_entry_init (vlib_main_t * vm) return (error); l2_fib_init (lgm); + nsh_fib_init (lgm); fib_node_register_type (FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY, &lisp_fwd_vft); diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h index f7923671..d58895a3 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h +++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h @@ -81,7 +81,7 @@ typedef struct lisp_gpe_fwd_entry_t_ fib_node_t node; /** - * The Entry's key: {lEID,r-EID,vni} + * The Entry's key: {lEID,rEID,vni} */ lisp_gpe_fwd_entry_key_t *key; @@ -150,6 +150,33 @@ typedef struct lisp_gpe_fwd_entry_t_ */ dpo_id_t dpo; } l2; + + /** + * Fields relevant to an NSH entry + */ + struct + { + /** + * The path-list created for the forwarding + */ + fib_node_index_t path_list_index; + + /** + * Child index of this entry on the path-list + */ + u32 child_index; + + /** + * The DPO contributed by NSH + */ + dpo_id_t dpo; + + /** + * The DPO used for forwarding. Obtained after stacking tx node + * onto lb choice + */ + dpo_id_t choice; + } nsh; }; union @@ -177,6 +204,8 @@ extern void vnet_lisp_gpe_fwd_entry_flush (void); extern u32 lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[8], u8 dst_mac[8]); +extern const dpo_id_t *lisp_nsh_fib_lookup (lisp_gpe_main_t * lgm, + u32 spi_si); #endif /* diff --git a/src/vnet/mfib/mfib_entry.c b/src/vnet/mfib/mfib_entry.c index f1b6e8ee..acbe90bb 100644 --- a/src/vnet/mfib/mfib_entry.c +++ b/src/vnet/mfib/mfib_entry.c @@ -465,6 +465,7 @@ mfib_entry_src_collect_forwarding (fib_node_index_t pl_index, case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS: case FIB_FORW_CHAIN_TYPE_MPLS_EOS: case FIB_FORW_CHAIN_TYPE_ETHERNET: + case FIB_FORW_CHAIN_TYPE_NSH: ASSERT(0); break; } -- cgit 1.2.3-korg From 38206ee73d51cef6ef8c00a9947322eea9940f83 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Mon, 20 Feb 2017 17:31:57 +0100 Subject: LISP: don't show PITR generated mapping in dump call Change-Id: Iecba818ccf74a4d34e35d498e6f6a1d3c62419f4 Signed-off-by: Filip Tehlar --- src/vnet/lisp-cp/control.c | 1 + src/vnet/lisp-cp/lisp_api.c | 4 ++++ src/vnet/lisp-cp/lisp_cli.c | 3 +++ src/vnet/lisp-cp/lisp_types.h | 10 +++++++--- 4 files changed, 15 insertions(+), 3 deletions(-) (limited to 'src/vnet/lisp-cp/lisp_types.h') diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 66b560e4..ac11d890 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -1301,6 +1301,7 @@ vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add) pool_get (lcm->mapping_pool, m); m->locator_set_index = locator_set_index; m->local = 1; + m->pitr_set = 1; lcm->pitr_map_index = m - lcm->mapping_pool; /* enable pitr mode */ diff --git a/src/vnet/lisp-cp/lisp_api.c b/src/vnet/lisp-cp/lisp_api.c index 78d32e17..b2b31f09 100644 --- a/src/vnet/lisp-cp/lisp_api.c +++ b/src/vnet/lisp-cp/lisp_api.c @@ -752,6 +752,10 @@ send_lisp_eid_table_details (mapping_t * mapit, return; } + /* don't send PITR generated mapping */ + if (mapit->pitr_set) + return; + gid = &mapit->eid; ip_prefix = &gid_address_ippref (gid); mac = gid_address_mac (gid); diff --git a/src/vnet/lisp-cp/lisp_cli.c b/src/vnet/lisp-cp/lisp_cli.c index 15e6acbf..a2088dd3 100644 --- a/src/vnet/lisp-cp/lisp_cli.c +++ b/src/vnet/lisp-cp/lisp_cli.c @@ -799,6 +799,9 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ pool_foreach (mapit, lcm->mapping_pool, ({ + if (mapit->pitr_set) + continue; + locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool, mapit->locator_set_index); if (filter && !((1 == filter && ls->local) || diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h index e43f5ab0..672835bd 100644 --- a/src/vnet/lisp-cp/lisp_types.h +++ b/src/vnet/lisp-cp/lisp_types.h @@ -327,11 +327,15 @@ typedef struct u32 ttl; u8 action; - u8 authoritative; - u8 local; + u8 authoritative:1; + u8 local:1; /* valid only for remote mappings */ - u8 is_static; + u8 is_static:1; + u8 pitr_set:1; + u8 rsvd:4; + + u8 *key; lisp_key_type_t key_id; u8 timer_set; -- cgit 1.2.3-korg From 4868ff65eddfd694a1485d6c6c355f9a8ca9011d Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Thu, 9 Mar 2017 16:48:39 +0100 Subject: LISP statistics Change-Id: I399cac46d279e020ba33459ef759d9d29d3ac716 Signed-off-by: Filip Tehlar --- src/vat/api_format.c | 208 +++++++++++++++++++++++++++++++++ src/vnet/adj/adj_l2.c | 1 + src/vnet/lisp-cp/control.c | 72 ++++++++++-- src/vnet/lisp-cp/control.h | 14 +-- src/vnet/lisp-cp/lisp_types.c | 38 ++++++ src/vnet/lisp-cp/lisp_types.h | 3 + src/vnet/lisp-cp/one_api.c | 67 +++++++++++ src/vnet/lisp-cp/one_cli.c | 61 +++++++++- src/vnet/lisp-gpe/lisp_gpe.c | 2 + src/vnet/lisp-gpe/lisp_gpe.h | 30 +++++ src/vnet/lisp-gpe/lisp_gpe_adjacency.c | 100 ++++++++++++++++ src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c | 86 ++++++++++---- src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h | 3 + 13 files changed, 639 insertions(+), 46 deletions(-) (limited to 'src/vnet/lisp-cp/lisp_types.h') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 391fe9cf..d34a97f6 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -2610,6 +2610,92 @@ vl_api_one_eid_table_details_t_handler_json (vl_api_one_eid_table_details_t vec_free (eid); } +static void +vl_api_one_stats_details_t_handler (vl_api_one_stats_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u8 *seid = 0, *deid = 0; + u8 *(*format_ip_address_fcn) (u8 *, va_list *) = 0; + + deid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, mp->deid, mp->deid_pref_len, 0, 0, 0); + + seid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, mp->seid, mp->seid_pref_len, 0, 0, 0); + + vec_add1 (deid, 0); + vec_add1 (seid, 0); + + if (mp->is_ip4) + format_ip_address_fcn = format_ip4_address; + else + format_ip_address_fcn = format_ip6_address; + + + print (vam->ofp, "([%d] %s %s) (%U %U) %u %u", + clib_net_to_host_u32 (mp->vni), + seid, deid, + format_ip_address_fcn, mp->lloc, + format_ip_address_fcn, mp->rloc, + clib_net_to_host_u32 (mp->pkt_count), + clib_net_to_host_u32 (mp->bytes)); + + vec_free (deid); + vec_free (seid); +} + +static void +vl_api_one_stats_details_t_handler_json (vl_api_one_stats_details_t * mp) +{ + struct in6_addr ip6; + struct in_addr ip4; + vat_main_t *vam = &vat_main; + vat_json_node_t *node = 0; + u8 *deid = 0, *seid = 0; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + deid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, mp->deid, mp->deid_pref_len, 0, 0, 0); + + seid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, mp->seid, mp->seid_pref_len, 0, 0, 0); + + vec_add1 (deid, 0); + vec_add1 (seid, 0); + + vat_json_object_add_string_copy (node, "seid", seid); + vat_json_object_add_string_copy (node, "deid", deid); + vat_json_object_add_uint (node, "vni", clib_net_to_host_u32 (mp->vni)); + + if (mp->is_ip4) + { + clib_memcpy (&ip4, mp->lloc, sizeof (ip4)); + vat_json_object_add_ip4 (node, "lloc", ip4); + clib_memcpy (&ip4, mp->rloc, sizeof (ip4)); + vat_json_object_add_ip4 (node, "rloc", ip4); + } + else + { + clib_memcpy (&ip6, mp->lloc, sizeof (ip6)); + vat_json_object_add_ip6 (node, "lloc", ip6); + clib_memcpy (&ip6, mp->rloc, sizeof (ip6)); + vat_json_object_add_ip6 (node, "rloc", ip6); + } + vat_json_object_add_uint (node, "pkt_count", + clib_net_to_host_u32 (mp->pkt_count)); + vat_json_object_add_uint (node, "bytes", clib_net_to_host_u32 (mp->bytes)); + + vec_free (deid); + vec_free (seid); +} + static void vl_api_one_eid_table_map_details_t_handler (vl_api_one_eid_table_map_details_t * mp) @@ -2740,6 +2826,42 @@ static void vec_free (s); } +static void + vl_api_show_one_stats_enable_disable_reply_t_handler + (vl_api_show_one_stats_enable_disable_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + print (vam->ofp, "%s", mp->is_en ? "enabled" : "disabled"); +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_one_stats_enable_disable_reply_t_handler_json + (vl_api_show_one_stats_enable_disable_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t _node, *node = &_node; + int retval = clib_net_to_host_u32 (mp->retval); + + u8 *s = format (0, "%s", mp->is_en ? "enabled" : "disabled"); + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "state", s); + + vat_json_print (vam->ofp, node); + vat_json_free (node); + + vam->retval = retval; + vam->result_ready = 1; + vec_free (s); +} + static void api_gpe_fwd_entry_net_to_host (vl_api_gpe_fwd_entry_t * e) { @@ -4040,6 +4162,7 @@ _(one_map_request_mode_reply) \ _(one_add_del_map_request_itr_rlocs_reply) \ _(one_eid_table_add_del_map_reply) \ _(one_use_petr_reply) \ +_(one_stats_enable_disable_reply) \ _(gpe_add_del_fwd_entry_reply) \ _(gpe_enable_disable_reply) \ _(gpe_set_encap_mode_reply) \ @@ -4263,6 +4386,10 @@ _(ONE_EID_TABLE_VNI_DETAILS, one_eid_table_vni_details) \ _(ONE_MAP_RESOLVER_DETAILS, one_map_resolver_details) \ _(ONE_MAP_SERVER_DETAILS, one_map_server_details) \ _(ONE_ADJACENCIES_GET_REPLY, one_adjacencies_get_reply) \ +_(ONE_STATS_DETAILS, one_stats_details) \ +_(ONE_STATS_ENABLE_DISABLE_REPLY, one_stats_enable_disable_reply) \ +_(SHOW_ONE_STATS_ENABLE_DISABLE_REPLY, \ + show_one_stats_enable_disable_reply) \ _(GPE_SET_ENCAP_MODE_REPLY, gpe_set_encap_mode_reply) \ _(GPE_GET_ENCAP_MODE_REPLY, gpe_get_encap_mode_reply) \ _(GPE_ADD_DEL_IFACE_REPLY, gpe_add_del_iface_reply) \ @@ -14214,6 +14341,64 @@ api_show_one_rloc_probe_state (vat_main_t * vam) #define api_show_lisp_rloc_probe_state api_show_one_rloc_probe_state +static int +api_one_stats_enable_disable (vat_main_t * vam) +{ + vl_api_one_stats_enable_disable_t *mp; + unformat_input_t *input = vam->input; + u8 is_set = 0; + u8 is_en = 0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "enable")) + { + is_set = 1; + is_en = 1; + } + else if (unformat (input, "disable")) + { + is_set = 1; + } + else + break; + } + + if (!is_set) + { + errmsg ("Value not set"); + return -99; + } + + M (ONE_STATS_ENABLE_DISABLE, mp); + mp->is_en = is_en; + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + +static int +api_show_one_stats_enable_disable (vat_main_t * vam) +{ + vl_api_show_one_stats_enable_disable_t *mp; + int ret; + + M (SHOW_ONE_STATS_ENABLE_DISABLE, mp); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + static int api_show_one_map_request_mode (vat_main_t * vam) { @@ -15421,6 +15606,26 @@ api_one_map_resolver_dump (vat_main_t * vam) #define api_lisp_map_resolver_dump api_one_map_resolver_dump +static int +api_one_stats_dump (vat_main_t * vam) +{ + vl_api_one_stats_dump_t *mp; + vl_api_control_ping_t *mp_ping; + int ret; + + M (ONE_STATS_DUMP, mp); + /* send it... */ + S (mp); + + /* Use a control ping for synchronization */ + M (CONTROL_PING, mp_ping); + S (mp_ping); + + /* Wait for a reply... */ + W (ret); + return ret; +} + static int api_show_one_status (vat_main_t * vam) { @@ -18389,6 +18594,8 @@ _(one_locator_set_dump, "[local | remote]") \ _(one_locator_dump, "ls_index | ls_name ") \ _(one_eid_table_dump, "[eid / | ] [vni] " \ "[local] | [remote]") \ +_(one_stats_enable_disable, "enable|disalbe") \ +_(show_one_stats_enable_disable, "") \ _(one_eid_table_vni_dump, "") \ _(one_eid_table_map_dump, "l2|l3") \ _(one_map_resolver_dump, "") \ @@ -18397,6 +18604,7 @@ _(one_adjacencies_get, "vni ") \ _(show_one_rloc_probe_state, "") \ _(show_one_map_register_state, "") \ _(show_one_status, "") \ +_(one_stats_dump, "") \ _(one_get_map_request_itr_rlocs, "") \ _(show_one_pitr, "") \ _(show_one_use_petr, "") \ diff --git a/src/vnet/adj/adj_l2.c b/src/vnet/adj/adj_l2.c index 5a083643..fb64e505 100644 --- a/src/vnet/adj/adj_l2.c +++ b/src/vnet/adj/adj_l2.c @@ -93,6 +93,7 @@ adj_l2_rewrite_inline (vlib_main_t * vm, /* Update packet buffer attributes/set output interface. */ rw_len0 = adj0[0].rewrite_header.data_bytes; vnet_buffer(p0)->ip.save_rewrite_length = rw_len0; + vnet_buffer(p0)->sw_if_index[VLIB_TX] = adj0->rewrite_header.sw_if_index; vlib_increment_combined_counter(&adjacency_counters, cpu_index, diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 5c90c03b..47badeb9 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -284,6 +285,7 @@ dp_del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index) if (fe->is_src_dst) gid_address_copy (&a->lcl_eid, &fe->leid); + vnet_lisp_del_fwd_stats (a, feip[0]); vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index); /* delete entry in fwd table */ @@ -1228,9 +1230,6 @@ vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a) if (a->is_add) { - /* TODO 1) check if src/dst 2) once we have src/dst working, use it in - * delete*/ - /* check if source eid has an associated mapping. If pitr mode is on, * just use the pitr's mapping */ local_mi = lcm->lisp_pitr ? lcm->pitr_map_index : @@ -2654,16 +2653,15 @@ lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b) return vni; } -always_inline void +void get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, - gid_address_t * src, gid_address_t * dst) + gid_address_t * src, gid_address_t * dst, + u16 type) { u32 vni = 0; - u16 type; memset (src, 0, sizeof (*src)); memset (dst, 0, sizeof (*dst)); - type = vnet_buffer (b)->lisp.overlay_afi; if (LISP_AFI_IP == type || LISP_AFI_IP6 == type) { @@ -2742,10 +2740,9 @@ lisp_cp_lookup_inline (vlib_main_t * vm, b0 = vlib_get_buffer (vm, pi0); b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP]; - vnet_buffer (b0)->lisp.overlay_afi = overlay; /* src/dst eid pair */ - get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst); + get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst, overlay); /* if we have remote mapping for destination already in map-chache add forwarding tunnel directly. If not send a map-request */ @@ -3605,6 +3602,55 @@ lisp_cp_init (vlib_main_t * vm) return 0; } +static int +lisp_stats_api_fill (lisp_cp_main_t * lcm, lisp_gpe_main_t * lgm, + lisp_api_stats_t * stat, lisp_stats_key_t * key, + u32 stats_index) +{ + lisp_stats_t *s; + lisp_gpe_fwd_entry_key_t fwd_key; + const lisp_gpe_tunnel_t *lgt; + fwd_entry_t *fe; + + memset (stat, 0, sizeof (*stat)); + memset (&fwd_key, 0, sizeof (fwd_key)); + + fe = pool_elt_at_index (lcm->fwd_entry_pool, key->fwd_entry_index); + ASSERT (fe != 0); + + gid_to_dp_address (&fe->reid, &stat->deid); + gid_to_dp_address (&fe->leid, &stat->seid); + stat->vni = gid_address_vni (&fe->reid); + + lgt = lisp_gpe_tunnel_get (key->tunnel_index); + stat->loc_rloc = lgt->key->lcl; + stat->rmt_rloc = lgt->key->rmt; + + s = pool_elt_at_index (lgm->lisp_stats_pool, stats_index); + stat->stats = *s; + return 1; +} + +lisp_api_stats_t * +vnet_lisp_get_stats (void) +{ + lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + lisp_api_stats_t *stats = 0, stat; + lisp_stats_key_t *key; + u32 index; + + /* *INDENT-OFF* */ + hash_foreach_mem (key, index, lgm->lisp_stats_index_by_key, + { + if (lisp_stats_api_fill (lcm, lgm, &stat, key, index)) + vec_add1 (stats, stat); + }); + /* *INDENT-ON* */ + + return stats; +} + static void * send_map_request_thread_fn (void *arg) { @@ -3810,7 +3856,11 @@ vnet_lisp_stats_enable_disable (u8 enable) if (vnet_lisp_enable_disable_status () == 0) return VNET_API_ERROR_LISP_DISABLED; - lcm->stats_enabled = enable; + if (enable) + lcm->flags |= LISP_FLAG_STATS_ENABLED; + else + lcm->flags &= ~LISP_FLAG_STATS_ENABLED; + return 0; } @@ -3822,7 +3872,7 @@ vnet_lisp_stats_enable_disable_state (void) if (vnet_lisp_enable_disable_status () == 0) return VNET_API_ERROR_LISP_DISABLED; - return lcm->stats_enabled; + return lcm->flags & LISP_FLAG_STATS_ENABLED; } /* *INDENT-OFF* */ diff --git a/src/vnet/lisp-cp/control.h b/src/vnet/lisp-cp/control.h index 933b34b6..eae8a184 100644 --- a/src/vnet/lisp-cp/control.h +++ b/src/vnet/lisp-cp/control.h @@ -95,7 +95,8 @@ typedef enum } map_request_mode_t; #define foreach_lisp_flag_bit \ - _(USE_PETR, "Use Proxy-ETR") + _(USE_PETR, "Use Proxy-ETR") \ + _(STATS_ENABLED, "Statistics enabled") typedef enum lisp_flag_bits { @@ -210,9 +211,6 @@ typedef struct /* timing wheel for mappping timeouts */ timing_wheel_t wheel; - /* statistics */ - u8 stats_enabled; - /* commodity */ ip4_main_t *im4; ip6_main_t *im6; @@ -235,6 +233,11 @@ vnet_lisp_cp_get_main () return &lisp_control_main; } +void +get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, + gid_address_t * src, gid_address_t * dst, + u16 type); + typedef struct { u8 is_add; @@ -335,9 +338,6 @@ lisp_get_petr_mapping (lisp_cp_main_t * lcm) return pool_elt_at_index (lcm->mapping_pool, lcm->petr_map_index); } -u8 vnet_lisp_stats_enable_disable_state (void); -vnet_api_error_t vnet_lisp_stats_enable_disable (u8 enable); - #endif /* VNET_CONTROL_H_ */ /* diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c index b6466686..ad3a4bdf 100644 --- a/src/vnet/lisp-cp/lisp_types.c +++ b/src/vnet/lisp-cp/lisp_types.c @@ -573,6 +573,44 @@ ip_address_parse (void *offset, u16 iana_afi, ip_address_t * dst) return (sizeof (u16) + size); } +void +gid_to_dp_address (gid_address_t * g, dp_address_t * d) +{ + switch (gid_address_type (g)) + { + case GID_ADDR_SRC_DST: + switch (gid_address_sd_dst_type (g)) + { + case FID_ADDR_IP_PREF: + ip_prefix_copy (&d->ippref, &gid_address_sd_dst_ippref (g)); + d->type = FID_ADDR_IP_PREF; + break; + case FID_ADDR_MAC: + mac_copy (&d->mac, &gid_address_sd_dst_mac (g)); + d->type = FID_ADDR_MAC; + break; + default: + clib_warning ("Source/Dest address type %d not supported!", + gid_address_sd_dst_type (g)); + break; + } + break; + case GID_ADDR_IP_PREFIX: + ip_prefix_copy (&d->ippref, &gid_address_ippref (g)); + d->type = FID_ADDR_IP_PREF; + break; + case GID_ADDR_MAC: + mac_copy (&d->mac, &gid_address_mac (g)); + d->type = FID_ADDR_MAC; + break; + case GID_ADDR_NSH: + default: + d->nsh = gid_address_nsh (g).spi << 8 | gid_address_nsh (g).si; + d->type = FID_ADDR_NSH; + break; + } +} + u32 lcaf_hdr_parse (void *offset, lcaf_t * lcaf) { diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h index 672835bd..a65a479e 100644 --- a/src/vnet/lisp-cp/lisp_types.h +++ b/src/vnet/lisp-cp/lisp_types.h @@ -126,6 +126,8 @@ typedef struct typedef fid_address_t dp_address_t; #define fid_addr_ippref(_a) (_a)->ippref +#define fid_addr_prefix_length(_a) ip_prefix_len(&fid_addr_ippref(_a)) +#define fid_addr_ip_version(_a) ip_prefix_version(&fid_addr_ippref(_a)) #define fid_addr_mac(_a) (_a)->mac #define fid_addr_nsh(_a) (_a)->nsh #define fid_addr_type(_a) (_a)->type @@ -359,6 +361,7 @@ void build_src_dst (gid_address_t * sd, gid_address_t * src, gid_address_t * dst); void gid_address_from_ip (gid_address_t * g, ip_address_t * ip); +void gid_to_dp_address (gid_address_t * g, dp_address_t * d); #endif /* VNET_LISP_GPE_LISP_TYPES_H_ */ diff --git a/src/vnet/lisp-cp/one_api.c b/src/vnet/lisp-cp/one_api.c index 4faf6240..ab9e7a63 100644 --- a/src/vnet/lisp-cp/one_api.c +++ b/src/vnet/lisp-cp/one_api.c @@ -58,6 +58,21 @@ #include +#define REPLY_DETAILS(t, body) \ +do { \ + unix_shared_memory_queue_t * q; \ + rv = vl_msg_api_pd_handler (mp, rv); \ + q = vl_api_client_index_to_input_queue (mp->client_index); \ + if (!q) \ + return; \ + \ + rmp = vl_msg_api_alloc (sizeof (*rmp)); \ + rmp->_vl_msg_id = ntohs((t)); \ + rmp->context = mp->context; \ + do {body;} while (0); \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); + #define foreach_vpe_api_msg \ _(ONE_ADD_DEL_LOCATOR_SET, one_add_del_locator_set) \ _(ONE_ADD_DEL_LOCATOR, one_add_del_locator) \ @@ -1300,10 +1315,62 @@ static void REPLY_MACRO (VL_API_ONE_ENABLE_DISABLE_REPLY); } +static void +lisp_fid_addr_to_api (fid_address_t * fid, u8 * dst, u8 * api_eid_type, + u8 * prefix_length) +{ + switch (fid_addr_type (fid)) + { + case FID_ADDR_IP_PREF: + *prefix_length = fid_addr_prefix_length (fid); + if (fid_addr_ip_version (fid) == IP4) + { + *api_eid_type = 0; /* ipv4 type */ + clib_memcpy (dst, &fid_addr_ippref (fid), 4); + } + else + { + *api_eid_type = 1; /* ipv6 type */ + clib_memcpy (dst, &fid_addr_ippref (fid), 16); + } + break; + case FID_ADDR_MAC: + *api_eid_type = 2; /* l2 mac type */ + mac_copy (dst, fid_addr_mac (fid)); + break; + default: + ASSERT (0); + } +} + static void vl_api_one_stats_dump_t_handler (vl_api_one_stats_dump_t * mp) { + vl_api_one_stats_details_t *rmp; + lisp_api_stats_t *stats, *stat; + u8 rv = 0; + stats = vnet_lisp_get_stats (); + vec_foreach (stat, stats) + { + /* *INDENT-OFF* */ + REPLY_DETAILS (VL_API_ONE_STATS_DETAILS, + ({ + lisp_fid_addr_to_api (&stat->deid, rmp->deid, &rmp->eid_type, + &rmp->deid_pref_len); + lisp_fid_addr_to_api (&stat->seid, rmp->seid, &rmp->eid_type, + &rmp->seid_pref_len); + rmp->vni = clib_host_to_net_u32 (stat->vni); + + rmp->is_ip4 = ip_addr_version (&stat->rmt_rloc) == IP4 ? 1 : 0; + ip_address_copy_addr (rmp->rloc, &stat->rmt_rloc); + ip_address_copy_addr (rmp->lloc, &stat->loc_rloc); + + rmp->pkt_count = clib_host_to_net_u32 (stat->stats.pkt_count); + rmp->bytes = clib_host_to_net_u32 (stat->stats.bytes); + })); + /* *INDENT-ON* */ + } } /* diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c index 2ceeaf42..b5bc5292 100644 --- a/src/vnet/lisp-cp/one_cli.c +++ b/src/vnet/lisp-cp/one_cli.c @@ -352,7 +352,7 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm, } } - if (!eid_set) + if (!del_all && !eid_set) { clib_warning ("missing eid!"); goto done; @@ -372,8 +372,6 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm, goto done; } - /* TODO build src/dst with seid */ - /* if it's a delete, clean forwarding */ if (!is_add) { @@ -1654,12 +1652,46 @@ lisp_show_stats_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (one_show_stats_command) = { - .path = "show one stats", - .short_help = "show ONE statistics", + .path = "show one statistics status", + .short_help = "show ONE statistics enable/disable status", .function = lisp_show_stats_command_fn, }; /* *INDENT-ON* */ +static clib_error_t * +lisp_show_stats_details_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + lisp_api_stats_t *stat, *stats = vnet_lisp_get_stats (); + + if (vec_len (stats) > 0) + vlib_cli_output (vm, + "[src-EID, dst-EID] [loc-rloc, rmt-rloc] count bytes\n"); + else + vlib_cli_output (vm, "No statistics found.\n"); + + vec_foreach (stat, stats) + { + vlib_cli_output (vm, "[%U, %U] [%U, %U] %7u %7u\n", + format_fid_address, &stat->seid, + format_fid_address, &stat->deid, + format_ip_address, &stat->loc_rloc, + format_ip_address, &stat->rmt_rloc, + stat->stats.pkt_count, stat->stats.bytes); + } + vec_free (stats); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_show_stats_details_command) = { + .path = "show one statistics details", + .short_help = "show ONE statistics", + .function = lisp_show_stats_details_command_fn, +}; +/* *INDENT-ON* */ + static clib_error_t * lisp_stats_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -1692,12 +1724,29 @@ done: /* *INDENT-OFF* */ VLIB_CLI_COMMAND (one_stats_enable_disable_command) = { - .path = "one stats", + .path = "one statistics", .short_help = "enable/disable ONE statistics collecting", .function = lisp_stats_enable_disable_command_fn, }; /* *INDENT-ON* */ +static clib_error_t * +lisp_stats_flush_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vnet_lisp_flush_stats (); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_stats_flush_command) = { + .path = "one statistics flush", + .short_help = "Flush ONE statistics", + .function = lisp_stats_flush_command_fn, +}; +/* *INDENT-ON* */ + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/lisp-gpe/lisp_gpe.c b/src/vnet/lisp-gpe/lisp_gpe.c index 446ad445..1241ab9c 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.c +++ b/src/vnet/lisp-gpe/lisp_gpe.c @@ -424,6 +424,8 @@ lisp_gpe_init (vlib_main_t * vm) udp_register_dst_port (vm, UDP_DST_PORT_lisp_gpe6, lisp_gpe_ip6_input_node.index, 0 /* is_ip4 */ ); + lgm->lisp_stats_index_by_key = + hash_create_mem (0, sizeof (lisp_stats_key_t), sizeof (uword)); return 0; } diff --git a/src/vnet/lisp-gpe/lisp_gpe.h b/src/vnet/lisp-gpe/lisp_gpe.h index b5a50ec6..be447024 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.h +++ b/src/vnet/lisp-gpe/lisp_gpe.h @@ -90,6 +90,28 @@ typedef struct tunnel_lookup uword *vni_by_sw_if_index; } tunnel_lookup_t; +typedef struct +{ + u32 fwd_entry_index; + u32 tunnel_index; +} lisp_stats_key_t; + +typedef struct +{ + u32 pkt_count; + u32 bytes; +} lisp_stats_t; + +typedef struct +{ + u32 vni; + dp_address_t deid; + dp_address_t seid; + ip_address_t loc_rloc; + ip_address_t rmt_rloc; + + lisp_stats_t stats; +} lisp_api_stats_t; typedef enum gpe_encap_mode_e { @@ -143,6 +165,9 @@ typedef struct lisp_gpe_main gpe_encap_mode_t encap_mode; + lisp_stats_t *lisp_stats_pool; + uword *lisp_stats_index_by_key; + /** convenience */ vlib_main_t *vlib_main; vnet_main_t *vnet_main; @@ -283,6 +308,11 @@ lisp_api_gpe_fwd_entry_t *vnet_lisp_gpe_fwd_entries_get_by_vni (u32 vni); gpe_encap_mode_t vnet_gpe_get_encap_mode (void); int vnet_gpe_set_encap_mode (gpe_encap_mode_t mode); +u8 vnet_lisp_stats_enable_disable_state (void); +vnet_api_error_t vnet_lisp_stats_enable_disable (u8 enable); +lisp_api_stats_t *vnet_lisp_get_stats (void); +void vnet_lisp_flush_stats (void); + #endif /* included_vnet_lisp_gpe_h */ /* diff --git a/src/vnet/lisp-gpe/lisp_gpe_adjacency.c b/src/vnet/lisp-gpe/lisp_gpe_adjacency.c index dbcf7134..50662dd6 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_adjacency.c +++ b/src/vnet/lisp-gpe/lisp_gpe_adjacency.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -223,9 +224,108 @@ lisp_gpe_adj_proto_from_vnet_link_type (vnet_link_t linkt) #define is_v4_packet(_h) ((*(u8*) _h) & 0xF0) == 0x40 +static lisp_afi_e +lisp_afi_from_vnet_link_type (vnet_link_t link) +{ + switch (link) + { + case VNET_LINK_IP4: + return LISP_AFI_IP; + case VNET_LINK_IP6: + return LISP_AFI_IP6; + case VNET_LINK_ETHERNET: + return LISP_AFI_MAC; + default: + return LISP_AFI_NO_ADDR; + } +} + +static void +lisp_gpe_increment_stats_counters (lisp_cp_main_t * lcm, ip_adjacency_t * adj, + vlib_buffer_t * b) +{ + lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); + lisp_gpe_adjacency_t *ladj; + ip_address_t rloc; + index_t lai; + u32 si, di; + gid_address_t src, dst; + lisp_stats_t *stats; + uword *feip; + + ip46_address_to_ip_address (&adj->sub_type.nbr.next_hop, &rloc); + si = vnet_buffer (b)->sw_if_index[VLIB_TX]; + lai = lisp_adj_find (&rloc, si); + ASSERT (INDEX_INVALID != lai); + + ladj = pool_elt_at_index (lisp_adj_pool, lai); + + u8 *lisp_data = (u8 *) vlib_buffer_get_current (b); + + /* skip IP header */ + if (is_v4_packet (lisp_data)) + lisp_data += sizeof (ip4_header_t); + else + lisp_data += sizeof (ip6_header_t); + + /* skip UDP header */ + lisp_data += sizeof (udp_header_t); + // TODO: skip TCP? + + /* skip LISP GPE header */ + lisp_data += sizeof (lisp_gpe_header_t); + + i16 saved_current_data = b->current_data; + b->current_data = lisp_data - b->data; + + lisp_afi_e afi = lisp_afi_from_vnet_link_type (adj->ia_link); + get_src_and_dst_eids_from_buffer (lcm, b, &src, &dst, afi); + b->current_data = saved_current_data; + di = gid_dictionary_sd_lookup (&lcm->mapping_index_by_gid, &dst, &src); + if (PREDICT_FALSE (~0 == di)) + { + clib_warning ("dst mapping not found (%U, %U)", format_gid_address, + &src, format_gid_address, &dst); + return; + } + + feip = hash_get (lcm->fwd_entry_by_mapping_index, di); + if (PREDICT_FALSE (!feip)) + return; + + lisp_stats_key_t key; + memset (&key, 0, sizeof (key)); + key.fwd_entry_index = feip[0]; + key.tunnel_index = ladj->tunnel_index; + + uword *p = hash_get_mem (lgm->lisp_stats_index_by_key, &key); + if (p) + { + stats = pool_elt_at_index (lgm->lisp_stats_pool, p[0]); + } + else + { + pool_get (lgm->lisp_stats_pool, stats); + memset (stats, 0, sizeof (*stats)); + + lisp_stats_key_t *key_copy = clib_mem_alloc (sizeof (*key_copy)); + memcpy (key_copy, &key, sizeof (*key_copy)); + hash_set_mem (lgm->lisp_stats_index_by_key, key_copy, + stats - lgm->lisp_stats_pool); + } + stats->pkt_count++; + /* compute payload length starting after GPE */ + stats->bytes += b->current_length - (lisp_data - b->data - b->current_data); +} + static void lisp_gpe_fixup (vlib_main_t * vm, ip_adjacency_t * adj, vlib_buffer_t * b) { + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + + if (lcm->flags & LISP_FLAG_STATS_ENABLED) + lisp_gpe_increment_stats_counters (lcm, adj, b); + /* Fixup the checksum and len fields in the LISP tunnel encap * that was applied at the midchain node */ ip_udp_fixup_one (vm, b, is_v4_packet (vlib_buffer_get_current (b))); diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c index 2eb5ced6..f458a14c 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c +++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c @@ -329,28 +329,6 @@ delete_fib_entries (lisp_gpe_fwd_entry_t * lfe) lfe->eid_fib_index, &lfe->key->rmt.ippref); } -static void -gid_to_dp_address (gid_address_t * g, dp_address_t * d) -{ - switch (gid_address_type (g)) - { - case GID_ADDR_IP_PREFIX: - case GID_ADDR_SRC_DST: - ip_prefix_copy (&d->ippref, &gid_address_ippref (g)); - d->type = FID_ADDR_IP_PREF; - break; - case GID_ADDR_MAC: - mac_copy (&d->mac, &gid_address_mac (g)); - d->type = FID_ADDR_MAC; - break; - case GID_ADDR_NSH: - default: - d->nsh = gid_address_nsh (g).spi << 8 | gid_address_nsh (g).si; - d->type = FID_ADDR_NSH; - break; - } -} - static lisp_gpe_fwd_entry_t * find_fwd_entry (lisp_gpe_main_t * lgm, vnet_lisp_gpe_add_del_fwd_entry_args_t * a, @@ -1177,6 +1155,70 @@ vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, } } +void +vnet_lisp_flush_stats (void) +{ + lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); + lisp_stats_t *stat; + + /* *INDENT-OFF* */ + pool_foreach (stat, lgm->lisp_stats_pool, + { + stat->pkt_count = 0; + stat->bytes = 0; + }); + /* *INDENT-ON* */ +} + +static void +lisp_del_adj_stats (lisp_gpe_main_t * lgm, u32 fwd_entry_index, u32 ti) +{ + hash_pair_t *hp; + lisp_stats_key_t key; + void *key_copy; + uword *p; + lisp_stats_t *s; + + memset (&key, 0, sizeof (key)); + key.fwd_entry_index = fwd_entry_index; + key.tunnel_index = ti; + + p = hash_get_mem (lgm->lisp_stats_index_by_key, &key); + if (p) + { + s = pool_elt_at_index (lgm->lisp_stats_pool, p[0]); + hp = hash_get_pair (lgm->lisp_stats_index_by_key, &key); + key_copy = (void *) (hp->key); + hash_unset_mem (lgm->lisp_stats_index_by_key, &key); + clib_mem_free (key_copy); + pool_put (lgm->lisp_stats_pool, s); + } +} + +void +vnet_lisp_del_fwd_stats (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, + u32 fwd_entry_index) +{ + lisp_gpe_main_t *lgm = &lisp_gpe_main; + lisp_gpe_fwd_entry_key_t fe_key; + lisp_gpe_fwd_entry_t *lfe; + lisp_fwd_path_t *path; + const lisp_gpe_adjacency_t *ladj; + + lfe = find_fwd_entry (lgm, a, &fe_key); + if (!lfe) + return; + + if (LISP_GPE_FWD_ENTRY_TYPE_NORMAL != lfe->type) + return; + + vec_foreach (path, lfe->paths) + { + ladj = lisp_gpe_adjacency_get (path->lisp_adj); + lisp_del_adj_stats (lgm, fwd_entry_index, ladj->tunnel_index); + } +} + /** * @brief Flush all the forwrding entries */ diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h index d58895a3..618f7b53 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h +++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h @@ -206,6 +206,9 @@ extern u32 lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, extern const dpo_id_t *lisp_nsh_fib_lookup (lisp_gpe_main_t * lgm, u32 spi_si); +extern void +vnet_lisp_del_fwd_stats (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, + u32 fwd_entry_index); #endif /* -- cgit 1.2.3-korg From d5a65db98d66c66b03b057ac568be05f2456f73c Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Wed, 17 May 2017 17:21:10 +0200 Subject: LISP: L2 ARP handling Change-Id: I1ec328cda73f7eaf7867cd8a2a17852ee0cd23f1 Signed-off-by: Filip Tehlar --- src/vat/api_format.c | 233 ++++++++++++++++++++++++++++++++++++++ src/vnet/lisp-cp/control.c | 232 ++++++++++++++++++++++++++++++++----- src/vnet/lisp-cp/control.h | 15 +++ src/vnet/lisp-cp/gid_dictionary.c | 91 ++++++++++++++- src/vnet/lisp-cp/gid_dictionary.h | 25 +++- src/vnet/lisp-cp/lisp_types.c | 3 + src/vnet/lisp-cp/lisp_types.h | 15 +++ src/vnet/lisp-cp/one.api | 73 ++++++++++++ src/vnet/lisp-cp/one_api.c | 82 ++++++++++++++ src/vnet/lisp-cp/one_cli.c | 100 ++++++++++++++++ 10 files changed, 833 insertions(+), 36 deletions(-) (limited to 'src/vnet/lisp-cp/lisp_types.h') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index f3e6f64c..3eff8ef0 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -3163,6 +3163,123 @@ end: vam->result_ready = 1; } +static void + vl_api_one_l2_arp_entries_get_reply_t_handler + (vl_api_one_l2_arp_entries_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + + for (i = 0; i < n; i++) + print (vam->ofp, "%U -> %U", format_ip4_address, &mp->entries[i].ip4, + format_ethernet_address, mp->entries[i].mac); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_one_l2_arp_entries_get_reply_t_handler_json + (vl_api_one_l2_arp_entries_get_reply_t * mp) +{ + u8 *s = 0; + vat_main_t *vam = &vat_main; + vat_json_node_t *e = 0, root; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + vl_api_one_l2_arp_entry_t *arp_entry; + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + vat_json_init_array (&root); + + for (i = 0; i < n; i++) + { + e = vat_json_array_add (&root); + arp_entry = &mp->entries[i]; + + vat_json_init_object (e); + s = format (0, "%U", format_ethernet_address, arp_entry->mac); + vec_add1 (s, 0); + + vat_json_object_add_string_copy (e, "mac", s); + vec_free (s); + + s = format (0, "%U", format_ip4_address, &arp_entry->ip4); + vec_add1 (s, 0); + vat_json_object_add_string_copy (e, "ip4", s); + vec_free (s); + } + + vat_json_print (vam->ofp, &root); + vat_json_free (&root); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_one_l2_arp_bd_get_reply_t_handler + (vl_api_one_l2_arp_bd_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + + for (i = 0; i < n; i++) + { + print (vam->ofp, "%d", clib_net_to_host_u32 (mp->bridge_domains[i])); + } + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_one_l2_arp_bd_get_reply_t_handler_json + (vl_api_one_l2_arp_bd_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t root; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + vat_json_init_array (&root); + + for (i = 0; i < n; i++) + { + vat_json_array_add_uint (&root, + clib_net_to_host_u32 (mp->bridge_domains[i])); + } + + vat_json_print (vam->ofp, &root); + vat_json_free (&root); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + static void vl_api_one_adjacencies_get_reply_t_handler (vl_api_one_adjacencies_get_reply_t * mp) @@ -4158,6 +4275,10 @@ static void vl_api_flow_classify_details_t_handler_json #define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler #define vl_api_one_adjacencies_get_reply_t_endian vl_noop_handler #define vl_api_one_adjacencies_get_reply_t_print vl_noop_handler +#define vl_api_one_l2_arp_bd_get_reply_t_print vl_noop_handler +#define vl_api_one_l2_arp_entries_get_reply_t_endian vl_noop_handler +#define vl_api_one_l2_arp_entries_get_reply_t_print vl_noop_handler +#define vl_api_one_l2_arp_bd_get_reply_t_endian vl_noop_handler /* * Generate boilerplate reply handlers, which @@ -4267,6 +4388,7 @@ _(one_add_del_map_request_itr_rlocs_reply) \ _(one_eid_table_add_del_map_reply) \ _(one_use_petr_reply) \ _(one_stats_enable_disable_reply) \ +_(one_add_del_l2_arp_entry_reply) \ _(one_stats_flush_reply) \ _(gpe_add_del_fwd_entry_reply) \ _(gpe_enable_disable_reply) \ @@ -4499,6 +4621,9 @@ _(ONE_STATS_FLUSH_REPLY, one_stats_flush_reply) \ _(ONE_STATS_ENABLE_DISABLE_REPLY, one_stats_enable_disable_reply) \ _(SHOW_ONE_STATS_ENABLE_DISABLE_REPLY, \ show_one_stats_enable_disable_reply) \ +_(ONE_ADD_DEL_L2_ARP_ENTRY_REPLY, one_add_del_l2_arp_entry_reply) \ +_(ONE_L2_ARP_BD_GET_REPLY, one_l2_arp_bd_get_reply) \ +_(ONE_L2_ARP_ENTRIES_GET_REPLY, one_l2_arp_entries_get_reply) \ _(GPE_SET_ENCAP_MODE_REPLY, gpe_set_encap_mode_reply) \ _(GPE_GET_ENCAP_MODE_REPLY, gpe_get_encap_mode_reply) \ _(GPE_ADD_DEL_IFACE_REPLY, gpe_add_del_iface_reply) \ @@ -14736,6 +14861,111 @@ api_show_one_rloc_probe_state (vat_main_t * vam) #define api_show_lisp_rloc_probe_state api_show_one_rloc_probe_state +static int +api_one_add_del_l2_arp_entry (vat_main_t * vam) +{ + vl_api_one_add_del_l2_arp_entry_t *mp; + unformat_input_t *input = vam->input; + u8 is_add = 1; + u8 mac_set = 0; + u8 bd_set = 0; + u8 ip_set = 0; + u8 mac[6] = { 0, }; + u32 ip4 = 0, bd = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "mac %U", unformat_ethernet_address, mac)) + mac_set = 1; + else if (unformat (input, "ip %U", unformat_ip4_address, &ip4)) + ip_set = 1; + else if (unformat (input, "bd %d", &bd)) + bd_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!bd_set || !ip_set || (!mac_set && is_add)) + { + errmsg ("Missing BD, IP or MAC!"); + return -99; + } + + M (ONE_ADD_DEL_L2_ARP_ENTRY, mp); + mp->is_add = is_add; + clib_memcpy (mp->mac, mac, 6); + mp->bd = clib_host_to_net_u32 (bd); + mp->ip4 = ip4; + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + +static int +api_one_l2_arp_bd_get (vat_main_t * vam) +{ + vl_api_one_l2_arp_bd_get_t *mp; + int ret; + + M (ONE_L2_ARP_BD_GET, mp); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + +static int +api_one_l2_arp_entries_get (vat_main_t * vam) +{ + vl_api_one_l2_arp_entries_get_t *mp; + unformat_input_t *input = vam->input; + u8 bd_set = 0; + u32 bd = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "bd %d", &bd)) + bd_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!bd_set) + { + errmsg ("Expected bridge domain!"); + return -99; + } + + M (ONE_L2_ARP_ENTRIES_GET, mp); + mp->bd = clib_host_to_net_u32 (bd); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + static int api_one_stats_enable_disable (vat_main_t * vam) { @@ -19052,6 +19282,9 @@ _(one_locator_set_dump, "[local | remote]") \ _(one_locator_dump, "ls_index | ls_name ") \ _(one_eid_table_dump, "[eid / | ] [vni] " \ "[local] | [remote]") \ +_(one_add_del_l2_arp_entry, "[del] mac bd ip4 ") \ +_(one_l2_arp_bd_get, "") \ +_(one_l2_arp_entries_get, "bd ") \ _(one_stats_enable_disable, "enable|disalbe") \ _(show_one_stats_enable_disable, "") \ _(one_eid_table_vni_dump, "") \ diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 439802c9..cea92556 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -821,6 +823,99 @@ vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a, return vnet_lisp_map_cache_add_del (a, map_index_result); } +static void +add_l2_arp_bd (BVT (clib_bihash_kv) * kvp, void *arg) +{ + u32 **ht = arg; + u32 bd = (u32) kvp->key[0]; + hash_set (ht[0], bd, 0); +} + +u32 * +vnet_lisp_l2_arp_bds_get (void) +{ + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + u32 *bds = 0; + + gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid, + add_l2_arp_bd, &bds); + return bds; +} + +typedef struct +{ + void *vector; + u32 bd; +} lisp_add_l2_arp_args_t; + +static void +add_l2_arp_entry (BVT (clib_bihash_kv) * kvp, void *arg) +{ + lisp_add_l2_arp_args_t *a = arg; + lisp_api_l2_arp_entry_t **vector = a->vector, e; + + if ((u32) kvp->key[0] == a->bd) + { + mac_copy (e.mac, (void *) &kvp->value); + e.ip4 = (u32) kvp->key[1]; + vec_add1 (vector[0], e); + } +} + +lisp_api_l2_arp_entry_t * +vnet_lisp_l2_arp_entries_get_by_bd (u32 bd) +{ + lisp_api_l2_arp_entry_t *entries = 0; + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + lisp_add_l2_arp_args_t a; + + a.vector = &entries; + a.bd = bd; + + gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid, + add_l2_arp_entry, &a); + return entries; +} + +int +vnet_lisp_add_del_l2_arp_entry (gid_address_t * key, u8 * mac, u8 is_add) +{ + if (vnet_lisp_enable_disable_status () == 0) + { + clib_warning ("LISP is disabled!"); + return VNET_API_ERROR_LISP_DISABLED; + } + + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + int rc = 0; + + u64 res = gid_dictionary_lookup (&lcm->mapping_index_by_gid, key); + if (is_add) + { + if (res != GID_LOOKUP_MISS_L2) + { + clib_warning ("Entry %U exists in DB!", format_gid_address, key); + return VNET_API_ERROR_ENTRY_ALREADY_EXISTS; + } + u64 val = mac_to_u64 (mac); + gid_dictionary_add_del (&lcm->mapping_index_by_gid, key, val, + 1 /* is_add */ ); + } + else + { + if (res == GID_LOOKUP_MISS_L2) + { + clib_warning ("ONE ARP entry %U not found - cannot delete!", + format_gid_address, key); + return -1; + } + gid_dictionary_add_del (&lcm->mapping_index_by_gid, key, 0, + 0 /* is_add */ ); + } + + return rc; +} + int vnet_lisp_eid_table_map (u32 vni, u32 dp_id, u8 is_l2, u8 is_add) { @@ -830,7 +925,7 @@ vnet_lisp_eid_table_map (u32 vni, u32 dp_id, u8 is_l2, u8 is_add) if (vnet_lisp_enable_disable_status () == 0) { clib_warning ("LISP is disabled!"); - return -1; + return VNET_API_ERROR_LISP_DISABLED; } dp_table_by_vni = is_l2 ? &lcm->bd_id_by_vni : &lcm->table_id_by_vni; @@ -1931,7 +2026,8 @@ vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a) /* Statistics (not really errors) */ #define foreach_lisp_cp_lookup_error \ _(DROP, "drop") \ -_(MAP_REQUESTS_SENT, "map-request sent") +_(MAP_REQUESTS_SENT, "map-request sent") \ +_(ARP_REPLY_TX, "ARP replies sent") static char *lisp_cp_lookup_error_strings[] = { #define _(sym,string) string, @@ -1950,6 +2046,7 @@ typedef enum typedef enum { LISP_CP_LOOKUP_NEXT_DROP, + LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX, LISP_CP_LOOKUP_N_NEXT, } lisp_cp_lookup_next_t; @@ -2710,10 +2807,8 @@ lisp_get_vni_from_buffer_ip (lisp_cp_main_t * lcm, vlib_buffer_t * b, } always_inline u32 -lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b) +lisp_get_bd_from_buffer_eth (vlib_buffer_t * b) { - uword *vnip; - u32 vni = ~0; u32 sw_if_index0; l2input_main_t *l2im = &l2input_main; @@ -2724,12 +2819,21 @@ lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b) config = vec_elt_at_index (l2im->configs, sw_if_index0); bd_config = vec_elt_at_index (l2im->bd_configs, config->bd_index); - vnip = hash_get (lcm->vni_by_bd_id, bd_config->bd_id); + return bd_config->bd_id; +} + +always_inline u32 +lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b) +{ + uword *vnip; + u32 vni = ~0; + u32 bd = lisp_get_bd_from_buffer_eth (b); + + vnip = hash_get (lcm->vni_by_bd_id, bd); if (vnip) vni = vnip[0]; else - clib_warning ("bridge domain %d is not mapped to any vni!", - config->bd_index); + clib_warning ("bridge domain %d is not mapped to any vni!", bd); return vni; } @@ -2744,6 +2848,9 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, memset (src, 0, sizeof (*src)); memset (dst, 0, sizeof (*dst)); + gid_address_type (dst) = GID_ADDR_NO_ADDRESS; + gid_address_type (src) = GID_ADDR_NO_ADDRESS; + if (LISP_AFI_IP == type || LISP_AFI_IP6 == type) { ip4_header_t *ip; @@ -2767,19 +2874,35 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, else if (LISP_AFI_MAC == type) { ethernet_header_t *eh; + ethernet_arp_header_t *ah; eh = vlib_buffer_get_current (b); - gid_address_type (src) = GID_ADDR_MAC; - gid_address_type (dst) = GID_ADDR_MAC; - mac_copy (&gid_address_mac (src), eh->src_address); - mac_copy (&gid_address_mac (dst), eh->dst_address); + if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_ARP) + { + ah = (ethernet_arp_header_t *) (((u8 *) eh) + sizeof (*eh)); + if (clib_net_to_host_u16 (ah->opcode) + != ETHERNET_ARP_OPCODE_request) + return; + + gid_address_type (dst) = GID_ADDR_ARP; + gid_address_arp_bd (dst) = lisp_get_bd_from_buffer_eth (b); + clib_memcpy (&gid_address_arp_ip4 (dst), + &ah->ip4_over_ethernet[1].ip4, 4); + } + else + { + gid_address_type (src) = GID_ADDR_MAC; + gid_address_type (dst) = GID_ADDR_MAC; + mac_copy (&gid_address_mac (src), eh->src_address); + mac_copy (&gid_address_mac (dst), eh->dst_address); - /* get vni */ - vni = lisp_get_vni_from_buffer_eth (lcm, b); + /* get vni */ + vni = lisp_get_vni_from_buffer_eth (lcm, b); - gid_address_vni (dst) = vni; - gid_address_vni (src) = vni; + gid_address_vni (dst) = vni; + gid_address_vni (src) = vni; + } } else if (LISP_AFI_LCAF == type) { @@ -2793,38 +2916,81 @@ lisp_cp_lookup_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, int overlay) { - u32 *from, *to_next_drop, di, si; + u32 *from, *to_next, di, si; lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); - u32 pkts_mapped = 0; - uword n_left_from, n_left_to_next_drop; + u32 pkts_mapped = 0, next_index; + uword n_left_from, n_left_to_next; + vnet_main_t *vnm = vnet_get_main (); from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; + next_index = node->cached_next_index; while (n_left_from > 0) { - vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, - to_next_drop, n_left_to_next_drop); + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - while (n_left_from > 0 && n_left_to_next_drop > 0) + while (n_left_from > 0 && n_left_to_next > 0) { - u32 pi0; + u32 pi0, sw_if_index0, next0; + u64 mac0; vlib_buffer_t *b0; gid_address_t src, dst; + ethernet_arp_header_t *arp0; + ethernet_header_t *eth0; + vnet_hw_interface_t *hw_if0; pi0 = from[0]; from += 1; n_left_from -= 1; - to_next_drop[0] = pi0; - to_next_drop += 1; - n_left_to_next_drop -= 1; + to_next[0] = pi0; + to_next += 1; + n_left_to_next -= 1; b0 = vlib_get_buffer (vm, pi0); - b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP]; /* src/dst eid pair */ get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst, overlay); + if (gid_address_type (&dst) == GID_ADDR_ARP) + { + mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst); + if (GID_LOOKUP_MISS_L2 != mac0) + { + /* send ARP reply */ + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0; + + hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0); + + eth0 = vlib_buffer_get_current (b0); + arp0 = (ethernet_arp_header_t *) (((u8 *) eth0) + + sizeof (*eth0)); + arp0->opcode = + clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply); + arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0]; + clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, + (u8 *) & mac0, 6); + clib_memcpy (&arp0->ip4_over_ethernet[0].ip4, + &gid_address_arp_ip4 (&dst), 4); + + /* Hardware must be ethernet-like. */ + ASSERT (vec_len (hw_if0->hw_address) == 6); + + clib_memcpy (eth0->dst_address, eth0->src_address, 6); + clib_memcpy (eth0->src_address, hw_if0->hw_address, 6); + + b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX]; + next0 = LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX; + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, + n_left_to_next, pi0, + next0); + } + continue; + } + /* if we have remote mapping for destination already in map-chache add forwarding tunnel directly. If not send a map-request */ di = gid_dictionary_sd_lookup (&lcm->mapping_index_by_gid, &dst, @@ -2859,6 +3025,7 @@ lisp_cp_lookup_inline (vlib_main_t * vm, pkts_mapped++; } + b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP]; if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0, @@ -2871,10 +3038,13 @@ lisp_cp_lookup_inline (vlib_main_t * vm, } gid_address_free (&dst); gid_address_free (&src); + next0 = LISP_CP_LOOKUP_NEXT_DROP; + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, + n_left_to_next, pi0, next0); } - vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, - n_left_to_next_drop); + vlib_put_next_frame (vm, node, next_index, n_left_to_next); } vlib_node_increment_counter (vm, node->node_index, LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT, @@ -2926,6 +3096,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", + [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -2945,6 +3116,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip6_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", + [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -2964,6 +3136,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", + [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -2983,6 +3156,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_nsh_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", + [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ diff --git a/src/vnet/lisp-cp/control.h b/src/vnet/lisp-cp/control.h index cb98eb09..feb8cfa4 100644 --- a/src/vnet/lisp-cp/control.h +++ b/src/vnet/lisp-cp/control.h @@ -87,6 +87,12 @@ typedef struct miss_packet_type_t type; } miss_packet_t; +typedef struct +{ + u8 mac[6]; + u32 ip4; +} lisp_api_l2_arp_entry_t; + typedef enum { MR_MODE_DST_ONLY = 0, @@ -112,6 +118,12 @@ typedef enum lisp_flags #undef _ } lisp_flags_e; +typedef struct +{ + ip_address_t addr; + u32 bd; +} lisp_l2_arp_key_t; + typedef struct { u32 flags; @@ -338,6 +350,9 @@ int vnet_lisp_rloc_probe_enable_disable (u8 is_enable); int vnet_lisp_map_register_enable_disable (u8 is_enable); u8 vnet_lisp_map_register_state_get (void); u8 vnet_lisp_rloc_probe_state_get (void); +int vnet_lisp_add_del_l2_arp_entry (gid_address_t * key, u8 * mac, u8 is_add); +u32 *vnet_lisp_l2_arp_bds_get (void); +lisp_api_l2_arp_entry_t *vnet_lisp_l2_arp_entries_get_by_bd (u32 bd); map_records_arg_t *parse_map_reply (vlib_buffer_t * b); diff --git a/src/vnet/lisp-cp/gid_dictionary.c b/src/vnet/lisp-cp/gid_dictionary.c index b01bb0e0..80d59faf 100644 --- a/src/vnet/lisp-cp/gid_dictionary.c +++ b/src/vnet/lisp-cp/gid_dictionary.c @@ -138,6 +138,15 @@ gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid, arg); } +void +gid_dict_foreach_l2_arp_entry (gid_dictionary_t * db, void (*cb) + (BVT (clib_bihash_kv) * kvp, void *arg), + void *ht) +{ + gid_l2_arp_table_t *tab = &db->arp_table; + BV (clib_bihash_foreach_key_value_pair) (&tab->arp_lookup_table, cb, ht); +} + static void make_mac_sd_key (BVT (clib_bihash_kv) * kv, u32 vni, u8 src_mac[6], u8 dst_mac[6]) @@ -328,7 +337,30 @@ ip_sd_lookup (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst, return GID_LOOKUP_MISS; } -u32 +static void +make_arp_key (BVT (clib_bihash_kv) * kv, u32 bd, ip4_address_t * addr) +{ + kv->key[0] = (u64) bd; + kv->key[1] = (u64) addr->as_u32; + kv->key[2] = (u64) 0; +} + +static u64 +arp_lookup (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key) +{ + int rv; + BVT (clib_bihash_kv) kv, value; + + make_arp_key (&kv, bd, key); + rv = BV (clib_bihash_search_inline_2) (&db->arp_lookup_table, &kv, &value); + + if (rv == 0) + return value.value; + + return GID_LOOKUP_MISS_L2; +} + +u64 gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) { switch (gid_address_type (key)) @@ -358,6 +390,9 @@ gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) break; } break; + case GID_ADDR_ARP: + return arp_lookup (&db->arp_table, gid_address_arp_bd (key), + &gid_address_arp_ip4 (key)); default: clib_warning ("address type %d not supported!", gid_address_type (key)); break; @@ -825,21 +860,49 @@ add_del_sd (gid_dictionary_t * db, u32 vni, source_dest_t * key, u32 value, return ~0; } +static u32 +add_del_arp (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key, u64 value, + u8 is_add) +{ + BVT (clib_bihash_kv) kv, result; + u32 old_val = ~0; + + make_arp_key (&kv, bd, key); + if (BV (clib_bihash_search) (&db->arp_lookup_table, &kv, &result) == 0) + old_val = result.value; + + if (is_add) + { + kv.value = value; + BV (clib_bihash_add_del) (&db->arp_lookup_table, &kv, 1 /* is_add */ ); + db->count++; + } + else + { + BV (clib_bihash_add_del) (&db->arp_lookup_table, &kv, 0 /* is_add */ ); + db->count--; + } + return old_val; +} + u32 -gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u32 value, +gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u64 value, u8 is_add) { switch (gid_address_type (key)) { case GID_ADDR_IP_PREFIX: return add_del_ip (db, gid_address_vni (key), &gid_address_ippref (key), - 0, value, is_add); + 0, (u32) value, is_add); case GID_ADDR_MAC: return add_del_mac (&db->sd_mac_table, gid_address_vni (key), - gid_address_mac (key), 0, value, is_add); + gid_address_mac (key), 0, (u32) value, is_add); case GID_ADDR_SRC_DST: return add_del_sd (db, gid_address_vni (key), &gid_address_sd (key), - value, is_add); + (u32) value, is_add); + case GID_ADDR_ARP: + return add_del_arp (&db->arp_table, gid_address_arp_bd (key), + &gid_address_arp_ip4 (key), value, is_add); default: clib_warning ("address type %d not supported!", gid_address_type (key)); break; @@ -864,12 +927,30 @@ mac_lookup_init (gid_mac_table_t * db) db->mac_lookup_table_size); } +static void +arp_lookup_init (gid_l2_arp_table_t * db) +{ + if (db->arp_lookup_table_nbuckets == 0) + db->arp_lookup_table_nbuckets = ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS; + + db->arp_lookup_table_nbuckets = + 1 << max_log2 (db->arp_lookup_table_nbuckets); + + if (db->arp_lookup_table_size == 0) + db->arp_lookup_table_size = ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE; + + BV (clib_bihash_init) (&db->arp_lookup_table, "arp lookup table", + db->arp_lookup_table_nbuckets, + db->arp_lookup_table_size); +} + void gid_dictionary_init (gid_dictionary_t * db) { ip4_lookup_init (&db->dst_ip4_table); ip6_lookup_init (&db->dst_ip6_table); mac_lookup_init (&db->sd_mac_table); + arp_lookup_init (&db->arp_table); } /* diff --git a/src/vnet/lisp-cp/gid_dictionary.h b/src/vnet/lisp-cp/gid_dictionary.h index 825e9856..9612fb13 100644 --- a/src/vnet/lisp-cp/gid_dictionary.h +++ b/src/vnet/lisp-cp/gid_dictionary.h @@ -22,6 +22,7 @@ #include #define GID_LOOKUP_MISS ((u32)~0) +#define GID_LOOKUP_MISS_L2 ((u64)~0) /* Default size of the ip4 hash table */ #define IP4_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) @@ -35,6 +36,10 @@ #define MAC_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) #define MAC_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) +/* Default size of the ARP hash table */ +#define ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) +#define ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) + typedef void (*foreach_subprefix_match_cb_t) (u32, void *); typedef struct @@ -81,6 +86,17 @@ typedef struct gid_mac_table typedef struct { + BVT (clib_bihash) arp_lookup_table; + u32 arp_lookup_table_nbuckets; + uword arp_lookup_table_size; + u64 count; +} gid_l2_arp_table_t; + +typedef struct +{ + /** L2 ARP table */ + gid_l2_arp_table_t arp_table; + /** destination IP LPM ip4 lookup table */ gid_ip4_table_t dst_ip4_table; @@ -99,10 +115,10 @@ typedef struct } gid_dictionary_t; u32 -gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u32 value, +gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u64 value, u8 is_add); -u32 gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key); +u64 gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key); u32 gid_dictionary_sd_lookup (gid_dictionary_t * db, gid_address_t * dst, gid_address_t * src); @@ -112,6 +128,11 @@ void gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid, foreach_subprefix_match_cb_t cb, void *arg); +void +gid_dict_foreach_l2_arp_entry (gid_dictionary_t * db, void (*cb) + (BVT (clib_bihash_kv) * kvp, void *arg), + void *ht); + #endif /* VNET_LISP_GPE_GID_DICTIONARY_H_ */ /* diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c index 31a80081..85cefae0 100644 --- a/src/vnet/lisp-cp/lisp_types.c +++ b/src/vnet/lisp-cp/lisp_types.c @@ -256,6 +256,9 @@ format_gid_address (u8 * s, va_list * args) &gid_address_mac (a)); case GID_ADDR_NSH: return format (s, "%U", format_nsh_address, &gid_address_nsh (a)); + case GID_ADDR_ARP: + return format (s, "[%d, %U]", gid_address_arp_bd (a), + format_ip4_address, &gid_address_arp_ip4 (a)); default: clib_warning ("Can't format gid type %d", type); return 0; diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h index a65a479e..f5d2a676 100644 --- a/src/vnet/lisp-cp/lisp_types.h +++ b/src/vnet/lisp-cp/lisp_types.h @@ -90,6 +90,7 @@ typedef enum GID_ADDR_MAC, GID_ADDR_SRC_DST, GID_ADDR_NSH, + GID_ADDR_ARP, GID_ADDR_NO_ADDRESS, GID_ADDR_TYPES } gid_address_type_t; @@ -165,12 +166,22 @@ typedef struct u8 si; } nsh_t; +typedef struct +{ + ip4_address_t addr; + u32 bd; +} lcaf_arp_t; + +#define lcaf_arp_ip4(_a) (_a)->addr +#define lcaf_arp_bd(_a) (_a)->bd + typedef struct { /* the union needs to be at the beginning! */ union { source_dest_t sd; + lcaf_arp_t arp; vni_t uni; }; u8 type; @@ -189,6 +200,7 @@ typedef struct _gid_address_t lcaf_t lcaf; u8 mac[6]; source_dest_t sd; + lcaf_arp_t arp; nsh_t nsh; }; u8 type; @@ -257,6 +269,9 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); #define gid_address_sd_dst(_a) sd_dst(&gid_address_sd(_a)) #define gid_address_sd_src_type(_a) sd_src_type(&gid_address_sd(_a)) #define gid_address_sd_dst_type(_a) sd_dst_type(&gid_address_sd(_a)) +#define gid_address_arp(_a) (_a)->arp +#define gid_address_arp_ip4(_a) lcaf_arp_ip4(&gid_address_arp (_a)) +#define gid_address_arp_bd(_a) lcaf_arp_bd(&gid_address_arp (_a)) /* 'sub'address functions */ #define foreach_gid_address_type_fcns \ diff --git a/src/vnet/lisp-cp/one.api b/src/vnet/lisp-cp/one.api index 2fa1edf6..7d07cc47 100644 --- a/src/vnet/lisp-cp/one.api +++ b/src/vnet/lisp-cp/one.api @@ -348,6 +348,79 @@ autoreply manual_print manual_endian define one_add_del_remote_mapping vl_api_one_remote_locator_t rlocs[rloc_num]; }; +/** \brief Add/delete L2 ARP entries + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - add if non-zero; delete otherwise + @param bd - bridge domain + @param mac - MAC address + @param ip4 - IPv4 address +*/ +autoreply define one_add_del_l2_arp_entry +{ + u32 client_index; + u32 context; + u8 is_add; + u8 mac[6]; + u32 bd; + u32 ip4; +}; + +/** \brief Request for L2 ARP entries from specified bridge domain + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param bd - bridge domain +*/ +define one_l2_arp_entries_get +{ + u32 client_index; + u32 context; + u32 bd; +}; + +typeonly manual_print manual_endian define one_l2_arp_entry +{ + u8 mac[6]; + u32 ip4; +}; + +/** \brief Reply with L2 ARP entries from specified bridge domain + @param context - sender context, to match reply w/ request + @param retval - error code + @param count - number of elements in the list + @param vl_api_one_arp_entry_t - list of entries +*/ +manual_print manual_endian define one_l2_arp_entries_get_reply +{ + u32 context; + i32 retval; + u32 count; + vl_api_one_l2_arp_entry_t entries[count]; +}; + +/** \brief Request for list of bridge domains used by L2 ARP table + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define one_l2_arp_bd_get +{ + u32 client_index; + u32 context; +}; + +/** \brief Reply with list of bridge domains used by L2 ARP table + @param context - sender context, to match reply w/ request + @param count - number of elements in the list + @param bridge_domains - list of BDs +*/ +manual_print manual_endian define one_l2_arp_bd_get_reply +{ + u32 context; + i32 retval; + u32 count; + u32 bridge_domains[count]; +}; + /** \brief add or delete ONE adjacency adjacency @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/lisp-cp/one_api.c b/src/vnet/lisp-cp/one_api.c index 23549afa..724e58df 100644 --- a/src/vnet/lisp-cp/one_api.c +++ b/src/vnet/lisp-cp/one_api.c @@ -42,6 +42,11 @@ #define vl_api_one_add_del_remote_mapping_t_endian vl_noop_handler #define vl_api_one_add_del_remote_mapping_t_print vl_noop_handler +#define vl_api_one_l2_arp_entry_t_endian vl_noop_handler +#define vl_api_one_l2_arp_entry_t_print vl_noop_handler +#define vl_api_one_add_del_l2_arp_entry vl_noop_handler +#define vl_api_one_l2_arp_bd_get vl_noop_handler + #define vl_typedefs /* define message structures */ #include #undef vl_typedefs @@ -109,6 +114,9 @@ _(SHOW_ONE_STATS_ENABLE_DISABLE, show_one_stats_enable_disable) \ _(ONE_STATS_ENABLE_DISABLE, one_stats_enable_disable) \ _(ONE_STATS_DUMP, one_stats_dump) \ _(ONE_STATS_FLUSH, one_stats_flush) \ +_(ONE_L2_ARP_BD_GET, one_l2_arp_bd_get) \ +_(ONE_L2_ARP_ENTRIES_GET, one_l2_arp_entries_get) \ +_(ONE_ADD_DEL_L2_ARP_ENTRY, one_add_del_l2_arp_entry) \ static locator_t * @@ -1387,6 +1395,80 @@ vl_api_one_stats_dump_t_handler (vl_api_one_stats_dump_t * mp) } } +static void + vl_api_one_add_del_l2_arp_entry_t_handler + (vl_api_one_add_del_l2_arp_entry_t * mp) +{ + vl_api_one_add_del_l2_arp_entry_reply_t *rmp; + int rv = 0; + gid_address_t _arp, *arp = &_arp; + memset (arp, 0, sizeof (*arp)); + + gid_address_type (arp) = GID_ADDR_ARP; + gid_address_arp_bd (arp) = clib_net_to_host_u32 (mp->bd); + + /* vpp keeps ip4 addresses in network byte order */ + clib_memcpy (&gid_address_arp_ip4 (arp), &mp->ip4, 4); + + rv = vnet_lisp_add_del_l2_arp_entry (arp, mp->mac, mp->is_add); + + REPLY_MACRO (VL_API_ONE_ADD_DEL_L2_ARP_ENTRY_REPLY); +} + +static void +vl_api_one_l2_arp_bd_get_t_handler (vl_api_one_l2_arp_bd_get_t * mp) +{ + vl_api_one_l2_arp_bd_get_reply_t *rmp; + int rv = 0; + u32 i = 0; + hash_pair_t *p; + + u32 *bds = vnet_lisp_l2_arp_bds_get (); + u32 size = hash_elts (bds) * sizeof (u32); + + /* *INDENT-OFF* */ + REPLY_MACRO4 (VL_API_ONE_L2_ARP_BD_GET_REPLY, size, + { + rmp->count = clib_host_to_net_u32 (hash_elts (bds)); + hash_foreach_pair (p, bds, + ({ + rmp->bridge_domains[i++] = clib_host_to_net_u32 (p->key); + })); + }); + /* *INDENT-ON* */ + + hash_free (bds); +} + +static void +vl_api_one_l2_arp_entries_get_t_handler (vl_api_one_l2_arp_entries_get_t * mp) +{ + vl_api_one_l2_arp_entries_get_reply_t *rmp; + lisp_api_l2_arp_entry_t *entries = 0, *e; + u32 i = 0; + int rv = 0; + + u32 bd = clib_net_to_host_u32 (mp->bd); + + entries = vnet_lisp_l2_arp_entries_get_by_bd (bd); + u32 size = vec_len (entries) * sizeof (u32); + + /* *INDENT-OFF* */ + REPLY_MACRO4 (VL_API_ONE_L2_ARP_ENTRIES_GET_REPLY, size, + { + rmp->count = clib_host_to_net_u32 (vec_len (entries)); + vec_foreach (e, entries) + { + mac_copy (rmp->entries[i].mac, e->mac); + rmp->entries[i].ip4 = e->ip4; + i++; + } + }); + /* *INDENT-ON* */ + + vec_free (entries); +} + /* * one_api_hookup * Add vpe's API message handlers to the table. diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c index 109aca2e..db6a6c83 100644 --- a/src/vnet/lisp-cp/one_cli.c +++ b/src/vnet/lisp-cp/one_cli.c @@ -276,6 +276,106 @@ VLIB_CLI_COMMAND (one_eid_table_map_command) = { }; /* *INDENT-ON* */ +static clib_error_t * +lisp_add_del_l2_arp_entry_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = NULL; + int rc = 0; + u8 hw_addr[6], bd = 0; + ip4_address_t ip4; + u32 hw_addr_set = 0, ip_set = 0, is_add = 1; + gid_address_t _arp, *arp = &_arp; + + memset (&ip4, 0, sizeof (ip4)); + memset (hw_addr, 0, sizeof (hw_addr)); + memset (arp, 0, sizeof (*arp)); + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "mac %U", unformat_mac_address, hw_addr)) + hw_addr_set = 1; + else if (unformat (line_input, "ip %U", unformat_ip4_address, &ip4)) + ip_set = 1; + else if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "bd %d", &bd)) + ; + else + { + error = clib_error_return (0, "parse error"); + goto done; + } + } + + if (!ip_set || (!hw_addr_set && is_add)) + { + vlib_cli_output (vm, "expected IP and MAC addresses!"); + return 0; + } + + /* build GID address */ + gid_address_arp_ip4 (arp) = ip4; + gid_address_arp_bd (arp) = bd; + gid_address_type (arp) = GID_ADDR_ARP; + rc = vnet_lisp_add_del_l2_arp_entry (arp, hw_addr, is_add); + if (rc) + clib_warning ("Failed to %s l2 arp entry!", is_add ? "add" : "delete"); + +done: + unformat_free (line_input); + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_add_del_l2_arp_entry_command) = { + .path = "one l2 arp", + .short_help = "one l2 arp [del] bd mac ip ", + .function = lisp_add_del_l2_arp_entry_command_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +lisp_show_l2_arp_entries_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + u32 *ht = vnet_lisp_l2_arp_bds_get (); + lisp_api_l2_arp_entry_t *entries, *e; + hash_pair_t *p; + + /* *INDENT-OFF* */ + hash_foreach_pair (p, ht, + ({ + entries = vnet_lisp_l2_arp_entries_get_by_bd (p->key); + vlib_cli_output (vm, "Table: %d", p->key); + + vec_foreach (e, entries) + { + vlib_cli_output (vm, "\t%U -> %U", format_ip4_address, &e->ip4, + format_mac_address, e->mac); + } + vec_free (entries); + })); + /* *INDENT-ON* */ + + hash_free (ht); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_show_l2_arp_entries_command) = { + .path = "show one l2 arp entries", + .short_help = "Show ONE L2 ARP entries", + .function = lisp_show_l2_arp_entries_command_fn, +}; +/* *INDENT-ON* */ + /** * Handler for add/del remote mapping CLI. * -- cgit 1.2.3-korg From ef2a5bf0a31c9c0a94f9f497cb6353f46073e6ec Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Tue, 30 May 2017 07:14:46 +0200 Subject: LISP: add NSH support Change-Id: I971c110ed126f1a24a963f9d3b88cf8f8c308816 Signed-off-by: Filip Tehlar --- src/tests/vnet/lisp-cp/test_lisp_types.c | 76 ++++++++++++- src/vat/api_format.c | 180 +++++++++++++++++++++++++++++-- src/vnet/lisp-cp/control.c | 139 +++++++++++++++++++++--- src/vnet/lisp-cp/control.h | 4 + src/vnet/lisp-cp/gid_dictionary.c | 79 +++++++++++++- src/vnet/lisp-cp/gid_dictionary.h | 17 +++ src/vnet/lisp-cp/lisp_cp_messages.h | 31 ++++++ src/vnet/lisp-cp/lisp_types.c | 108 ++++++++++++++++--- src/vnet/lisp-cp/lisp_types.h | 10 +- src/vnet/lisp-cp/one.api | 49 +++++++++ src/vnet/lisp-cp/one_api.c | 105 +++++++++++++++++- src/vnet/lisp-cp/one_cli.c | 58 +++++++++- src/vnet/lisp-gpe/interface.c | 8 +- src/vnet/lisp-gpe/lisp_gpe.h | 3 + src/vpp/api/test_client.c | 3 +- 15 files changed, 826 insertions(+), 44 deletions(-) (limited to 'src/vnet/lisp-cp/lisp_types.h') diff --git a/src/tests/vnet/lisp-cp/test_lisp_types.c b/src/tests/vnet/lisp-cp/test_lisp_types.c index 21575015..7c55a9c1 100644 --- a/src/tests/vnet/lisp-cp/test_lisp_types.c +++ b/src/tests/vnet/lisp-cp/test_lisp_types.c @@ -90,7 +90,7 @@ static clib_error_t * test_gid_parse_ip_pref () { clib_error_t * error = 0; gid_address_t _gid_addr, * gid_addr = &_gid_addr; - gid_address_t _gid_addr_copy, * gid_addr_copy = &_gid_addr_copy; + gid_address_t _gid_addr_copy, * copy = &_gid_addr_copy; u8 data[] = { 0x00, 0x01, /* AFI = IPv4 */ @@ -99,8 +99,8 @@ static clib_error_t * test_gid_parse_ip_pref () u32 len = gid_address_parse (data, gid_addr); _assert (6 == len); - gid_address_copy (gid_addr_copy, gid_addr); - _assert (0 == gid_address_cmp (gid_addr_copy, gid_addr)); + gid_address_copy (copy, gid_addr); + _assert (0 == gid_address_cmp (copy, gid_addr)); done: return error; } @@ -127,6 +127,74 @@ done: return error; } +static clib_error_t * +test_gid_write_nsh (void) +{ + clib_error_t * error = 0; + + u8 * b = clib_mem_alloc(500); + memset(b, 0, 500); + + gid_address_t g = + { + .vni = 0, + .nsh.spi = 0x112233, + .nsh.si = 0x42, + .type = GID_ADDR_NSH, + }; + + u16 len = gid_address_put (b, &g); + + u8 expected[] = + { + 0x40, 0x03, 0x00, 0x00, /* AFI = LCAF*/ + 0x11, 0x00, 0x00, 0x04, /* type = SPI LCAF, length = 4 */ + + /* Service Path ID, Service index */ + 0x11, 0x22, 0x33, 0x42, /* SPI, SI */ + }; + + _assert (sizeof (expected) == len); + _assert (0 == memcmp (expected, b, len)); +done: + clib_mem_free (b); + return error; +} + +static clib_error_t * +test_gid_parse_nsh () +{ + clib_error_t * error = 0; + gid_address_t _gid_addr, * gid_addr = &_gid_addr; + gid_address_t _gid_addr_copy, * copy = &_gid_addr_copy; + + memset (gid_addr, 0, sizeof (gid_addr[0])); + memset (copy, 0, sizeof (copy[0])); + + u8 data[] = + { + 0x40, 0x03, 0x00, 0x00, /* AFI = LCAF*/ + 0x11, 0x00, 0x00, 0x04, /* type = SPI LCAF, length = 4 */ + + /* Service Path ID, Service index */ + 0x55, 0x99, 0x42, 0x09, /* SPI, SI */ + }; + + u32 len = gid_address_parse (data, gid_addr); + _assert (sizeof (data) == len); + gid_address_copy (copy, gid_addr); + _assert (0 == gid_address_cmp (gid_addr, copy)); + _assert (GID_ADDR_NSH == gid_address_type (copy)); + _assert (0 == gid_address_vni (copy)); + _assert (gid_address_nsh_spi (copy) == 0x559942); + _assert (gid_address_nsh_si (copy) == 0x09); + +done: + gid_address_free (copy); + gid_address_free (gid_addr); + return error; +} + static clib_error_t * test_gid_parse_lcaf () { clib_error_t * error = 0; @@ -555,6 +623,8 @@ done: _(gid_parse_ip_pref) \ _(gid_parse_mac) \ _(gid_parse_lcaf) \ + _(gid_parse_nsh) \ + _(gid_write_nsh) \ _(mac_address_write) \ _(gid_address_write) \ _(src_dst_serdes) \ diff --git a/src/vat/api_format.c b/src/vat/api_format.c index f33b4592..766624a0 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -2583,6 +2583,26 @@ static void vec_free (ls_name); } +typedef struct +{ + u32 spi; + u8 si; +} __attribute__ ((__packed__)) lisp_nsh_api_t; + +uword +unformat_nsh_address (unformat_input_t * input, va_list * args) +{ + lisp_nsh_api_t *nsh = va_arg (*args, lisp_nsh_api_t *); + return unformat (input, "SPI:%d SI:%d", &nsh->spi, &nsh->si); +} + +u8 * +format_nsh_address_vat (u8 * s, va_list * args) +{ + nsh_t *a = va_arg (*args, nsh_t *); + return format (s, "SPI:%d SI:%d", clib_net_to_host_u32 (a->spi), a->si); +} + static u8 * format_lisp_flat_eid (u8 * s, va_list * args) { @@ -2598,6 +2618,8 @@ format_lisp_flat_eid (u8 * s, va_list * args) return format (s, "%U/%d", format_ip6_address, eid, eid_len); case 2: return format (s, "%U", format_ethernet_address, eid); + case 3: + return format (s, "%U", format_nsh_address_vat, eid); } return 0; } @@ -2672,13 +2694,26 @@ vl_api_one_eid_table_details_t_handler_json (vl_api_one_eid_table_details_t clib_net_to_host_u32 (mp->locator_set_index)); vat_json_object_add_uint (node, "is_local", mp->is_local ? 1 : 0); - eid = format (0, "%U", format_lisp_eid_vat, - mp->eid_type, - mp->eid, - mp->eid_prefix_len, - mp->seid, mp->seid_prefix_len, mp->is_src_dst); - vec_add1 (eid, 0); - vat_json_object_add_string_copy (node, "eid", eid); + if (mp->eid_type == 3) + { + vat_json_node_t *nsh_json = vat_json_object_add (node, "eid"); + vat_json_init_object (nsh_json); + lisp_nsh_api_t *nsh = (lisp_nsh_api_t *) mp->eid; + vat_json_object_add_uint (nsh_json, "spi", + clib_net_to_host_u32 (nsh->spi)); + vat_json_object_add_uint (nsh_json, "si", nsh->si); + } + else + { + eid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, + mp->eid, + mp->eid_prefix_len, + mp->seid, mp->seid_prefix_len, mp->is_src_dst); + vec_add1 (eid, 0); + vat_json_object_add_string_copy (node, "eid", eid); + vec_free (eid); + } vat_json_object_add_uint (node, "vni", clib_net_to_host_u32 (mp->vni)); vat_json_object_add_uint (node, "ttl", clib_net_to_host_u32 (mp->ttl)); vat_json_object_add_uint (node, "authoritative", (mp->authoritative)); @@ -2689,7 +2724,6 @@ vl_api_one_eid_table_details_t_handler_json (vl_api_one_eid_table_details_t clib_net_to_host_u16 (mp->key_id)); vat_json_object_add_string_copy (node, "key", mp->key); } - vec_free (eid); } static void @@ -3665,6 +3699,52 @@ static void vam->result_ready = 1; } +static void + vl_api_show_one_nsh_mapping_reply_t_handler + (vl_api_show_one_nsh_mapping_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (0 <= retval) + { + print (vam->ofp, "%-20s%-16s", + mp->is_set ? "set" : "not-set", + mp->is_set ? (char *) mp->locator_set_name : ""); + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_one_nsh_mapping_reply_t_handler_json + (vl_api_show_one_nsh_mapping_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + u8 *status = 0; + + status = format (0, "%s", mp->is_set ? "yes" : "no"); + vec_add1 (status, 0); + + vat_json_init_object (&node); + vat_json_object_add_string_copy (&node, "is_set", status); + if (mp->is_set) + { + vat_json_object_add_string_copy (&node, "locator_set", + mp->locator_set_name); + } + + vec_free (status); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + static void vl_api_show_one_pitr_reply_t_handler (vl_api_show_one_pitr_reply_t * mp) { @@ -4672,6 +4752,7 @@ _(ONE_ADD_DEL_MAP_REQUEST_ITR_RLOCS_REPLY, \ one_add_del_map_request_itr_rlocs_reply) \ _(ONE_GET_MAP_REQUEST_ITR_RLOCS_REPLY, \ one_get_map_request_itr_rlocs_reply) \ +_(SHOW_ONE_NSH_MAPPING_REPLY, show_one_nsh_mapping_reply) \ _(SHOW_ONE_PITR_REPLY, show_one_pitr_reply) \ _(SHOW_ONE_USE_PETR_REPLY, show_one_use_petr_reply) \ _(SHOW_ONE_MAP_REQUEST_MODE_REPLY, show_one_map_request_mode_reply) \ @@ -14044,6 +14125,12 @@ unformat_lisp_eid_vat (unformat_input_t * input, va_list * args) { a->type = 2; /* mac type */ } + else if (unformat (input, "%U", unformat_nsh_address, a->addr)) + { + a->type = 3; /* NSH type */ + lisp_nsh_api_t *nsh = (lisp_nsh_api_t *) a->addr; + nsh->spi = clib_host_to_net_u32 (nsh->spi); + } else { return 0; @@ -14068,6 +14155,8 @@ lisp_eid_size_vat (u8 type) return 16; case 2: return 6; + case 3: + return 5; } return 0; } @@ -15166,6 +15255,50 @@ api_one_pitr_set_locator_set (vat_main_t * vam) #define api_lisp_pitr_set_locator_set api_one_pitr_set_locator_set +static int +api_one_nsh_set_locator_set (vat_main_t * vam) +{ + u8 ls_name_set = 0; + unformat_input_t *input = vam->input; + vl_api_one_nsh_set_locator_set_t *mp; + u8 is_add = 1; + u8 *ls_name = 0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "ls %s", &ls_name)) + ls_name_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!ls_name_set && is_add) + { + errmsg ("locator-set name not set!"); + return -99; + } + + M (ONE_NSH_SET_LOCATOR_SET, mp); + + mp->is_add = is_add; + clib_memcpy (mp->ls_name, ls_name, vec_len (ls_name)); + vec_free (ls_name); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + static int api_show_one_pitr (vat_main_t * vam) { @@ -15245,6 +15378,26 @@ api_one_use_petr (vat_main_t * vam) #define api_lisp_use_petr api_one_use_petr +static int +api_show_one_nsh_mapping (vat_main_t * vam) +{ + vl_api_show_one_use_petr_t *mp; + int ret; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s", "local ONE NSH mapping:"); + } + + M (SHOW_ONE_NSH_MAPPING, mp); + /* send it... */ + S (mp); + + /* Wait for a reply... */ + W (ret); + return ret; +} + static int api_show_one_use_petr (vat_main_t * vam) { @@ -16031,6 +16184,7 @@ api_one_eid_table_dump (vat_main_t * vam) u32 prefix_length = ~0, t, vni = 0; u8 filter = 0; int ret; + lisp_nsh_api_t nsh; while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { @@ -16051,6 +16205,11 @@ api_one_eid_table_dump (vat_main_t * vam) eid_set = 1; eid_type = 2; } + else if (unformat (i, "eid %U", unformat_nsh_address, &nsh)) + { + eid_set = 1; + eid_type = 3; + } else if (unformat (i, "vni %d", &t)) { vni = t; @@ -16097,6 +16256,9 @@ api_one_eid_table_dump (vat_main_t * vam) case 2: clib_memcpy (mp->eid, mac, sizeof (mac)); break; + case 3: + clib_memcpy (mp->eid, &nsh, sizeof (nsh)); + break; default: errmsg ("unknown EID type %d!", eid_type); return -99; @@ -19423,12 +19585,14 @@ _(one_eid_table_map_dump, "l2|l3") \ _(one_map_resolver_dump, "") \ _(one_map_server_dump, "") \ _(one_adjacencies_get, "vni ") \ +_(one_nsh_set_locator_set, "[del] ls ") \ _(show_one_rloc_probe_state, "") \ _(show_one_map_register_state, "") \ _(show_one_status, "") \ _(one_stats_dump, "") \ _(one_stats_flush, "") \ _(one_get_map_request_itr_rlocs, "") \ +_(show_one_nsh_mapping, "") \ _(show_one_pitr, "") \ _(show_one_use_petr, "") \ _(show_one_map_request_mode, "") \ diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 19bbd618..db78678d 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -28,6 +28,8 @@ #include #include +#define MAX_VALUE_U24 0xffffff + lisp_cp_main_t lisp_control_main; u8 *format_lisp_cp_input_trace (u8 * s, va_list * args); @@ -697,6 +699,20 @@ vnet_lisp_map_cache_add_del (vnet_lisp_add_del_mapping_args_t * a, mapping_t *m, *old_map; u32 **eid_indexes; + if (gid_address_type (&a->eid) == GID_ADDR_NSH) + { + if (gid_address_vni (&a->eid) != 0) + { + clib_warning ("Supported only default VNI for NSH!"); + return VNET_API_ERROR_INVALID_ARGUMENT; + } + if (gid_address_nsh_spi (&a->eid) > MAX_VALUE_U24) + { + clib_warning ("SPI is greater than 24bit!"); + return VNET_API_ERROR_INVALID_ARGUMENT; + } + } + mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->eid); old_map = mi != ~0 ? pool_elt_at_index (lcm->mapping_pool, mi) : 0; if (a->is_add) @@ -812,7 +828,7 @@ vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a, else if (GID_ADDR_MAC == type) dp_table = hash_get (lcm->bd_id_by_vni, vni); - if (!dp_table) + if (!dp_table && GID_ADDR_NSH != type) { clib_warning ("vni %d not associated to a %s!", vni, GID_ADDR_IP_PREFIX == type ? "vrf" : "bd"); @@ -1329,8 +1345,23 @@ vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a) { /* check if source eid has an associated mapping. If pitr mode is on, * just use the pitr's mapping */ - local_mi = lcm->lisp_pitr ? lcm->pitr_map_index : - gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->leid); + if (lcm->lisp_pitr) + local_mi = lcm->pitr_map_index; + else + { + if (gid_address_type (&a->reid) == GID_ADDR_NSH) + { + if (lcm->nsh_map_index == ~0) + local_mi = GID_LOOKUP_MISS; + else + local_mi = lcm->nsh_map_index; + } + else + { + local_mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, + &a->leid); + } + } if (GID_LOOKUP_MISS == local_mi) { @@ -1370,6 +1401,57 @@ vnet_lisp_set_map_request_mode (u8 mode) return 0; } +int +vnet_lisp_nsh_set_locator_set (u8 * locator_set_name, u8 is_add) +{ + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); + u32 locator_set_index = ~0; + mapping_t *m; + uword *p; + + if (vnet_lisp_enable_disable_status () == 0) + { + clib_warning ("LISP is disabled!"); + return VNET_API_ERROR_LISP_DISABLED; + } + + if (is_add) + { + if (lcm->nsh_map_index == (u32) ~ 0) + { + p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name); + if (!p) + { + clib_warning ("locator-set %v doesn't exist", locator_set_name); + return -1; + } + locator_set_index = p[0]; + + pool_get (lcm->mapping_pool, m); + memset (m, 0, sizeof *m); + m->locator_set_index = locator_set_index; + m->local = 1; + m->nsh_set = 1; + lcm->nsh_map_index = m - lcm->mapping_pool; + + if (~0 == vnet_lisp_gpe_add_nsh_iface (lgm)) + return -1; + } + } + else + { + if (lcm->nsh_map_index != (u32) ~ 0) + { + /* remove NSH mapping */ + pool_put_index (lcm->mapping_pool, lcm->nsh_map_index); + lcm->nsh_map_index = ~0; + vnet_lisp_gpe_del_nsh_iface (lgm); + } + } + return 0; +} + int vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add) { @@ -2667,7 +2749,7 @@ _send_encapsulated_map_request (lisp_cp_main_t * lcm, } /* get locator-set for seid */ - if (!lcm->lisp_pitr) + if (!lcm->lisp_pitr && gid_address_type (deid) != GID_ADDR_NSH) { map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid); if (map_index == ~0) @@ -2690,9 +2772,24 @@ _send_encapsulated_map_request (lisp_cp_main_t * lcm, } else { - map_index = lcm->pitr_map_index; - map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index); - ls_index = map->locator_set_index; + if (lcm->lisp_pitr) + { + map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index); + ls_index = map->locator_set_index; + } + else + { + if (lcm->nsh_map_index == (u32) ~ 0) + { + clib_warning ("No locator-set defined for NSH!"); + return -1; + } + else + { + map = pool_elt_at_index (lcm->mapping_pool, lcm->nsh_map_index); + ls_index = map->locator_set_index; + } + } } /* overwrite locator set if map-request itr-rlocs configured */ @@ -2843,6 +2940,7 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, gid_address_t * src, gid_address_t * dst, u16 type) { + ethernet_header_t *eh; u32 vni = 0; memset (src, 0, sizeof (*src)); @@ -2873,7 +2971,6 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, } else if (LISP_AFI_MAC == type) { - ethernet_header_t *eh; ethernet_arp_header_t *ah; eh = vlib_buffer_get_current (b); @@ -2906,8 +3003,19 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, } else if (LISP_AFI_LCAF == type) { - /* Eventually extend this to support NSH and other */ - ASSERT (0); + lisp_nsh_hdr_t *nh; + eh = vlib_buffer_get_current (b); + + if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_NSH) + { + nh = (lisp_nsh_hdr_t *) (((u8 *) eh) + sizeof (*eh)); + u32 spi = clib_net_to_host_u32 (nh->spi_si << 8); + u8 si = (u8) clib_net_to_host_u32 (nh->spi_si); + gid_address_nsh_spi (dst) = spi; + gid_address_nsh_si (dst) = si; + + gid_address_type (dst) = GID_ADDR_NSH; + } } } @@ -3009,8 +3117,14 @@ lisp_cp_lookup_inline (vlib_main_t * vm, } else { - si = gid_dictionary_lookup (&lcm->mapping_index_by_gid, - &src); + if (GID_ADDR_NSH != gid_address_type (&dst)) + { + si = gid_dictionary_lookup (&lcm->mapping_index_by_gid, + &src); + } + else + si = lcm->nsh_map_index; + if (~0 != si) { dp_add_fwd_entry_from_mt (si, di); @@ -3862,6 +3976,7 @@ lisp_cp_init (vlib_main_t * vm) u64 now = clib_cpu_time_now (); timing_wheel_init (&lcm->wheel, now, vm->clib_time.clocks_per_second); + lcm->nsh_map_index = ~0; return 0; } diff --git a/src/vnet/lisp-cp/control.h b/src/vnet/lisp-cp/control.h index feb8cfa4..ad90b526 100644 --- a/src/vnet/lisp-cp/control.h +++ b/src/vnet/lisp-cp/control.h @@ -211,6 +211,9 @@ typedef struct /* LISP PITR mode */ u8 lisp_pitr; + /* mapping index for NSH */ + u32 nsh_map_index; + /* map request mode */ u8 map_request_mode; @@ -353,6 +356,7 @@ u8 vnet_lisp_rloc_probe_state_get (void); int vnet_lisp_add_del_l2_arp_entry (gid_address_t * key, u8 * mac, u8 is_add); u32 *vnet_lisp_l2_arp_bds_get (void); lisp_api_l2_arp_entry_t *vnet_lisp_l2_arp_entries_get_by_bd (u32 bd); +int vnet_lisp_nsh_set_locator_set (u8 * locator_set_name, u8 is_add); map_records_arg_t *parse_map_reply (vlib_buffer_t * b); diff --git a/src/vnet/lisp-cp/gid_dictionary.c b/src/vnet/lisp-cp/gid_dictionary.c index 80d59faf..cf9a741a 100644 --- a/src/vnet/lisp-cp/gid_dictionary.c +++ b/src/vnet/lisp-cp/gid_dictionary.c @@ -345,6 +345,14 @@ make_arp_key (BVT (clib_bihash_kv) * kv, u32 bd, ip4_address_t * addr) kv->key[2] = (u64) 0; } +static void +make_nsh_key (BVT (clib_bihash_kv) * kv, u32 vni, u32 spi, u8 si) +{ + kv->key[0] = (u64) vni; + kv->key[1] = (u64) spi; + kv->key[2] = (u64) si; +} + static u64 arp_lookup (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key) { @@ -360,6 +368,21 @@ arp_lookup (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key) return GID_LOOKUP_MISS_L2; } +static u32 +nsh_lookup (gid_nsh_table_t * db, u32 vni, u32 spi, u8 si) +{ + int rv; + BVT (clib_bihash_kv) kv, value; + + make_nsh_key (&kv, vni, spi, si); + rv = BV (clib_bihash_search_inline_2) (&db->nsh_lookup_table, &kv, &value); + + if (rv == 0) + return value.value; + + return GID_LOOKUP_MISS; +} + u64 gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) { @@ -393,6 +416,9 @@ gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) case GID_ADDR_ARP: return arp_lookup (&db->arp_table, gid_address_arp_bd (key), &gid_address_arp_ip4 (key)); + case GID_ADDR_NSH: + return nsh_lookup (&db->nsh_table, gid_address_vni (key), + gid_address_nsh_spi (key), gid_address_nsh_si (key)); default: clib_warning ("address type %d not supported!", gid_address_type (key)); break; @@ -432,6 +458,9 @@ gid_dictionary_sd_lookup (gid_dictionary_t * db, gid_address_t * dst, break; } break; + case GID_ADDR_NSH: + return gid_dictionary_lookup (db, dst); + break; default: clib_warning ("address type %d not supported!", gid_address_type (dst)); break; @@ -860,7 +889,7 @@ add_del_sd (gid_dictionary_t * db, u32 vni, source_dest_t * key, u32 value, return ~0; } -static u32 +static u64 add_del_arp (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key, u64 value, u8 is_add) { @@ -885,6 +914,31 @@ add_del_arp (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key, u64 value, return old_val; } +static u32 +add_del_nsh (gid_nsh_table_t * db, u32 vni, u32 spi, u8 si, u32 value, + u8 is_add) +{ + BVT (clib_bihash_kv) kv, result; + u32 old_val = ~0; + + make_nsh_key (&kv, vni, spi, si); + if (BV (clib_bihash_search) (&db->nsh_lookup_table, &kv, &result) == 0) + old_val = result.value; + + if (is_add) + { + kv.value = value; + BV (clib_bihash_add_del) (&db->nsh_lookup_table, &kv, 1 /* is_add */ ); + db->count++; + } + else + { + BV (clib_bihash_add_del) (&db->nsh_lookup_table, &kv, 0 /* is_add */ ); + db->count--; + } + return old_val; +} + u32 gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u64 value, u8 is_add) @@ -903,6 +957,11 @@ gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u64 value, case GID_ADDR_ARP: return add_del_arp (&db->arp_table, gid_address_arp_bd (key), &gid_address_arp_ip4 (key), value, is_add); + case GID_ADDR_NSH: + return add_del_nsh (&db->nsh_table, gid_address_vni (key), + gid_address_nsh_spi (key), gid_address_nsh_si (key), + value, is_add); + default: clib_warning ("address type %d not supported!", gid_address_type (key)); break; @@ -944,6 +1003,23 @@ arp_lookup_init (gid_l2_arp_table_t * db) db->arp_lookup_table_size); } +static void +nsh_lookup_init (gid_nsh_table_t * db) +{ + if (db->nsh_lookup_table_nbuckets == 0) + db->nsh_lookup_table_nbuckets = MAC_LOOKUP_DEFAULT_HASH_NUM_BUCKETS; + + db->nsh_lookup_table_nbuckets = + 1 << max_log2 (db->nsh_lookup_table_nbuckets); + + if (db->nsh_lookup_table_size == 0) + db->nsh_lookup_table_size = MAC_LOOKUP_DEFAULT_HASH_MEMORY_SIZE; + + BV (clib_bihash_init) (&db->nsh_lookup_table, "nsh lookup table", + db->nsh_lookup_table_nbuckets, + db->nsh_lookup_table_size); +} + void gid_dictionary_init (gid_dictionary_t * db) { @@ -951,6 +1027,7 @@ gid_dictionary_init (gid_dictionary_t * db) ip6_lookup_init (&db->dst_ip6_table); mac_lookup_init (&db->sd_mac_table); arp_lookup_init (&db->arp_table); + nsh_lookup_init (&db->nsh_table); } /* diff --git a/src/vnet/lisp-cp/gid_dictionary.h b/src/vnet/lisp-cp/gid_dictionary.h index 9612fb13..51806bd6 100644 --- a/src/vnet/lisp-cp/gid_dictionary.h +++ b/src/vnet/lisp-cp/gid_dictionary.h @@ -40,6 +40,10 @@ #define ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) #define ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) +/* Default size of the NSH hash table */ +#define NSH_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) +#define NSH_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) + typedef void (*foreach_subprefix_match_cb_t) (u32, void *); typedef struct @@ -84,6 +88,16 @@ typedef struct gid_mac_table u64 count; } gid_mac_table_t; +typedef struct gid_nsh_table +{ + BVT (clib_bihash) nsh_lookup_table; + + /* nsh lookup table config parameters */ + u32 nsh_lookup_table_nbuckets; + uword nsh_lookup_table_size; + u64 count; +} gid_nsh_table_t; + typedef struct { BVT (clib_bihash) arp_lookup_table; @@ -97,6 +111,9 @@ typedef struct /** L2 ARP table */ gid_l2_arp_table_t arp_table; + /** NSH lookup table */ + gid_nsh_table_t nsh_table; + /** destination IP LPM ip4 lookup table */ gid_ip4_table_t dst_ip4_table; diff --git a/src/vnet/lisp-cp/lisp_cp_messages.h b/src/vnet/lisp-cp/lisp_cp_messages.h index 278f60e1..69510a0e 100644 --- a/src/vnet/lisp-cp/lisp_cp_messages.h +++ b/src/vnet/lisp-cp/lisp_cp_messages.h @@ -473,6 +473,22 @@ typedef struct _lcaf_src_dst_hdr_t #define LCAF_SD_SRC_ML(_h) (_h)->src_mask_len #define LCAF_SD_DST_ML(_h) (_h)->dst_mask_len +/* + * SPI LCAF + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Service Path ID | Service index | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct _lcaf_spi_hdr_t +{ + u32 spi_si; +} __attribute__ ((__packed__)) lcaf_spi_hdr_t; + +#define LCAF_SPI_SI(_h) (_h)->spi_si + /* * The Map-Register message format is: * @@ -602,6 +618,21 @@ typedef struct #define MNOTIFY_AUTH_DATA_LEN(h_) (MREG_HDR_CAST(h_))->auth_data_len #define MNOTIFY_DATA(h_) (MREG_HDR_CAST(h_))->data +/* + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Ver|O|C|R|R|R|R|R|R| Length | MD type=0x1 | Next Protocol | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Service Path Identifer | Service Index | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +typedef struct +{ + u32 header; + u32 spi_si; +} __attribute__ ((__packed__)) lisp_nsh_hdr_t; + #endif /* VNET_LISP_GPE_LISP_CP_MESSAGES_H_ */ /* diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c index 85cefae0..e50c3aa1 100644 --- a/src/vnet/lisp-cp/lisp_types.c +++ b/src/vnet/lisp-cp/lisp_types.c @@ -31,16 +31,28 @@ typedef int (*cmp_fct) (void *, void *); size_to_write_fct size_to_write_fcts[GID_ADDR_TYPES] = { ip_prefix_size_to_write, lcaf_size_to_write, mac_size_to_write, - sd_size_to_write, nsh_size_to_write + sd_size_to_write, nsh_size_to_write, 0 /* arp */ , no_addr_size_to_write }; + serdes_fct write_fcts[GID_ADDR_TYPES] = - { ip_prefix_write, lcaf_write, mac_write, sd_write, nsh_write }; + { ip_prefix_write, lcaf_write, mac_write, sd_write, nsh_write, 0 /* arp */ , + no_addr_write +}; + cast_fct cast_fcts[GID_ADDR_TYPES] = - { ip_prefix_cast, lcaf_cast, mac_cast, sd_cast, nsh_cast }; + { ip_prefix_cast, lcaf_cast, mac_cast, sd_cast, nsh_cast, 0 /* arp */ , + no_addr_cast +}; + addr_len_fct addr_len_fcts[GID_ADDR_TYPES] = - { ip_prefix_length, lcaf_length, mac_length, sd_length, nsh_length }; + { ip_prefix_length, lcaf_length, mac_length, sd_length, nsh_length, + 0 /* arp */ , no_addr_length +}; + copy_fct copy_fcts[GID_ADDR_TYPES] = - { ip_prefix_copy, lcaf_copy, mac_copy, sd_copy, nsh_copy }; + { ip_prefix_copy, lcaf_copy, mac_copy, sd_copy, nsh_copy, 0 /* arp */ , + no_addr_copy +}; #define foreach_lcaf_type \ _(1, no_addr) \ @@ -55,7 +67,12 @@ copy_fct copy_fcts[GID_ADDR_TYPES] = _(0, NULL) \ _(0, NULL) \ _(0, NULL) \ - _(1, sd) + _(1, sd) \ + _(0, NULL) \ + _(0, NULL) \ + _(0, NULL) \ + _(0, NULL) \ + _(1, nsh) #define _(cond, name) \ u16 name ## _write (u8 * p, void * a); \ @@ -254,11 +271,12 @@ format_gid_address (u8 * s, va_list * args) case GID_ADDR_MAC: return format (s, "[%d] %U", gid_address_vni (a), format_mac_address, &gid_address_mac (a)); - case GID_ADDR_NSH: - return format (s, "%U", format_nsh_address, &gid_address_nsh (a)); case GID_ADDR_ARP: return format (s, "[%d, %U]", gid_address_arp_bd (a), format_ip4_address, &gid_address_arp_ip4 (a)); + case GID_ADDR_NSH: + return format (s, "%U", format_nsh_address, &gid_address_nsh (a)); + default: clib_warning ("Can't format gid type %d", type); return 0; @@ -287,7 +305,7 @@ unformat_fid_address (unformat_input_t * i, va_list * args) else if (unformat (i, "%U", unformat_nsh_address, &nsh)) { fid_addr_type (a) = FID_ADDR_NSH; - nsh_copy (&fid_addr_nsh (a), mac); + nsh_copy (&fid_addr_nsh (a), &nsh); } else return 0; @@ -673,6 +691,38 @@ do { \ dst += _sum; \ } while (0); +void +nsh_free (void *a) +{ + /* nothing to do */ +} + +u16 +nsh_parse (u8 * p, void *a) +{ + lcaf_spi_hdr_t *h = (lcaf_spi_hdr_t *) p; + gid_address_t *g = a; + + gid_address_type (g) = GID_ADDR_NSH; + gid_address_nsh_spi (g) = clib_net_to_host_u32 (LCAF_SPI_SI (h)) >> 8; + gid_address_nsh_si (g) = (u8) clib_net_to_host_u32 (LCAF_SPI_SI (h)); + + return sizeof (lcaf_spi_hdr_t); +} + +int +nsh_cmp (void *a1, void *a2) +{ + nsh_t *n1 = a1; + nsh_t *n2 = a2; + + if (n1->spi != n2->spi) + return 1; + if (n1->si != n2->si) + return 1; + return 0; +} + u16 sd_parse (u8 * p, void *a) { @@ -1094,6 +1144,12 @@ mac_cast (gid_address_t * a) return &gid_address_mac (a); } +void * +no_addr_cast (gid_address_t * a) +{ + return (void *) a; +} + void * sd_cast (gid_address_t * a) { @@ -1227,8 +1283,33 @@ sd_write (u8 * p, void *a) u16 nsh_write (u8 * p, void *a) { - clib_warning ("not done"); - return 0; + lcaf_spi_hdr_t spi; + lcaf_hdr_t lcaf; + gid_address_t *g = a; + u16 size = 0; + + ASSERT (gid_address_type (g) == GID_ADDR_NSH); + + memset (&lcaf, 0, sizeof (lcaf)); + memset (&spi, 0, sizeof (spi)); + + LCAF_TYPE (&lcaf) = LCAF_NSH; + LCAF_LENGTH (&lcaf) = clib_host_to_net_u16 (sizeof (lcaf_spi_hdr_t)); + + u32 s = clib_host_to_net_u32 (gid_address_nsh_spi (g) << 8 | + gid_address_nsh_si (g)); + LCAF_SPI_SI (&spi) = s; + + *(u16 *) p = clib_host_to_net_u16 (LISP_AFI_LCAF); + size += sizeof (u16); + + clib_memcpy (p + size, &lcaf, sizeof (lcaf)); + size += sizeof (lcaf); + + clib_memcpy (p + size, &spi, sizeof (spi)); + size += sizeof (spi); + + return size; } u16 @@ -1354,7 +1435,7 @@ mac_size_to_write (void *a) u16 nsh_size_to_write (void *a) { - return sizeof (u16) + 4; + return sizeof (u16) + sizeof (lcaf_hdr_t) + sizeof (lcaf_spi_hdr_t); } u8 @@ -1581,6 +1662,9 @@ gid_address_cmp (gid_address_t * a1, gid_address_t * a2) case GID_ADDR_SRC_DST: cmp = sd_cmp (&gid_address_sd (a1), &gid_address_sd (a2)); break; + case GID_ADDR_NSH: + cmp = nsh_cmp (&gid_address_nsh (a1), &gid_address_nsh (a2)); + break; default: break; } diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h index f5d2a676..b7ad0f27 100644 --- a/src/vnet/lisp-cp/lisp_types.h +++ b/src/vnet/lisp-cp/lisp_types.h @@ -102,6 +102,7 @@ typedef enum LCAF_AFI_LIST_TYPE, LCAF_INSTANCE_ID, LCAF_SOURCE_DEST = 12, + LCAF_NSH = 17, LCAF_TYPES } lcaf_type_t; @@ -166,6 +167,9 @@ typedef struct u8 si; } nsh_t; +#define nsh_spi(_a) (_a)->spi +#define nsh_si(_a) (_a)->si + typedef struct { ip4_address_t addr; @@ -258,6 +262,8 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); #define gid_address_lcaf(_a) (_a)->lcaf #define gid_address_mac(_a) (_a)->mac #define gid_address_nsh(_a) (_a)->nsh +#define gid_address_nsh_spi(_a) nsh_spi(&gid_address_nsh(_a)) +#define gid_address_nsh_si(_a) nsh_si(&gid_address_nsh(_a)) #define gid_address_vni(_a) (_a)->vni #define gid_address_vni_mask(_a) (_a)->vni_mask #define gid_address_sd_dst_ippref(_a) sd_dst_ippref(&(_a)->sd) @@ -275,6 +281,7 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); /* 'sub'address functions */ #define foreach_gid_address_type_fcns \ + _(no_addr) \ _(ip_prefix) \ _(lcaf) \ _(mac) \ @@ -350,7 +357,8 @@ typedef struct /* valid only for remote mappings */ u8 is_static:1; u8 pitr_set:1; - u8 rsvd:4; + u8 nsh_set:1; + u8 rsvd:3; u8 *key; diff --git a/src/vnet/lisp-cp/one.api b/src/vnet/lisp-cp/one.api index 7d07cc47..31811a34 100644 --- a/src/vnet/lisp-cp/one.api +++ b/src/vnet/lisp-cp/one.api @@ -146,6 +146,20 @@ autoreply define one_enable_disable u8 is_en; }; +/** \brief configure or delete ONE NSH mapping + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param ls_name - locator set name + @param is_add - add locator set if non-zero; delete otherwise +*/ +autoreply define one_nsh_set_locator_set +{ + u32 client_index; + u32 context; + u8 is_add; + u8 ls_name[64]; +}; + /** \brief configure or disable ONE PITR node @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -325,6 +339,12 @@ typeonly manual_endian manual_print define one_remote_locator 0 : ipv4 1 : ipv6 2 : mac + 3 : NSH : both information (service path ID and service index) are + encoded in 'eid' field in a following way: + + |4 B |1 B | + ----------- + |SPI | SI | @param deid - dst EID @param seid - src EID, valid only if is_src_dst is enabled @param rloc_num - number of remote locators @@ -596,6 +616,12 @@ define one_eid_table_details 0: EID is IPv4 1: EID is IPv6 2: EID is ethernet address + 3 : NSH : both information (service path ID and service index) are + encoded in 'eid' field in a following way: + + |4 B |1 B | + ----------- + |SPI | SI | @param eid - endpoint identifier @param filter - filter type; Support values: @@ -787,6 +813,29 @@ define one_get_map_request_itr_rlocs_reply u8 locator_set_name[64]; }; +/** \brief Request for ONE NSH mapping + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define show_one_nsh_mapping +{ + u32 client_index; + u32 context; +}; + +/** \brief Reply for ONE NSH mapping + @param context - sender context, to match reply w/ request + @param is_set - is ONE NSH mapping set + @param locator_set_name - name of the locator_set if NSH mapping is set +*/ +define show_one_nsh_mapping_reply +{ + u32 context; + i32 retval; + u8 is_set; + u8 locator_set_name[64]; +}; + /** \brief Request for ONE PITR status @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/lisp-cp/one_api.c b/src/vnet/lisp-cp/one_api.c index 724e58df..18235fa4 100644 --- a/src/vnet/lisp-cp/one_api.c +++ b/src/vnet/lisp-cp/one_api.c @@ -90,6 +90,7 @@ _(ONE_MAP_REGISTER_ENABLE_DISABLE, one_map_register_enable_disable) \ _(ONE_ADD_DEL_REMOTE_MAPPING, one_add_del_remote_mapping) \ _(ONE_ADD_DEL_ADJACENCY, one_add_del_adjacency) \ _(ONE_PITR_SET_LOCATOR_SET, one_pitr_set_locator_set) \ +_(ONE_NSH_SET_LOCATOR_SET, one_nsh_set_locator_set) \ _(ONE_MAP_REQUEST_MODE, one_map_request_mode) \ _(ONE_EID_TABLE_ADD_DEL_MAP, one_eid_table_add_del_map) \ _(ONE_LOCATOR_SET_DUMP, one_locator_set_dump) \ @@ -100,6 +101,7 @@ _(ONE_MAP_SERVER_DUMP, one_map_server_dump) \ _(ONE_EID_TABLE_MAP_DUMP, one_eid_table_map_dump) \ _(ONE_EID_TABLE_VNI_DUMP, one_eid_table_vni_dump) \ _(ONE_ADJACENCIES_GET, one_adjacencies_get) \ +_(SHOW_ONE_NSH_MAPPING, show_one_nsh_mapping) \ _(SHOW_ONE_RLOC_PROBE_STATE, show_one_rloc_probe_state) \ _(SHOW_ONE_MAP_REGISTER_STATE, show_one_map_register_state) \ _(SHOW_ONE_STATUS, show_one_status) \ @@ -225,10 +227,18 @@ vl_api_one_add_del_locator_t_handler (vl_api_one_add_del_locator_t * mp) REPLY_MACRO (VL_API_ONE_ADD_DEL_LOCATOR_REPLY); } +typedef struct +{ + u32 spi; + u8 si; +} __attribute__ ((__packed__)) lisp_nsh_api_t; + static int unformat_one_eid_api (gid_address_t * dst, u32 vni, u8 type, void *src, u8 len) { + lisp_nsh_api_t *nsh; + switch (type) { case 0: /* ipv4 */ @@ -247,6 +257,12 @@ unformat_one_eid_api (gid_address_t * dst, u32 vni, u8 type, void *src, gid_address_type (dst) = GID_ADDR_MAC; clib_memcpy (&gid_address_mac (dst), src, 6); break; + case 3: /* NSH */ + gid_address_type (dst) = GID_ADDR_NSH; + nsh = src; + gid_address_nsh_spi (dst) = clib_net_to_host_u32 (nsh->spi); + gid_address_nsh_si (dst) = nsh->si; + break; default: /* unknown type */ return VNET_API_ERROR_INVALID_VALUE; @@ -276,6 +292,12 @@ vl_api_one_add_del_local_eid_t_handler (vl_api_one_add_del_local_eid_t * mp) if (rv) goto out; + if (gid_address_type (eid) == GID_ADDR_NSH) + { + rv = VNET_API_ERROR_INVALID_VALUE; + goto out; + } + name = format (0, "%s", mp->locator_set_name); p = hash_get_mem (lcm->locator_set_index_by_name, name); if (!p) @@ -408,6 +430,21 @@ vl_api_one_map_request_mode_t_handler (vl_api_one_map_request_mode_t * mp) REPLY_MACRO (VL_API_ONE_MAP_REQUEST_MODE_REPLY); } +static void +vl_api_one_nsh_set_locator_set_t_handler (vl_api_one_nsh_set_locator_set_t + * mp) +{ + vl_api_one_nsh_set_locator_set_reply_t *rmp; + int rv = 0; + u8 *ls_name = 0; + + ls_name = format (0, "%s", mp->ls_name); + rv = vnet_lisp_nsh_set_locator_set (ls_name, mp->is_add); + vec_free (ls_name); + + REPLY_MACRO (VL_API_ONE_PITR_SET_LOCATOR_SET_REPLY); +} + static void vl_api_one_pitr_set_locator_set_t_handler (vl_api_one_pitr_set_locator_set_t * mp) @@ -781,7 +818,7 @@ send_one_eid_table_details (mapping_t * mapit, u8 *mac = 0; ip_prefix_t *ip_prefix = NULL; - if (mapit->pitr_set) + if (mapit->pitr_set || mapit->nsh_set) return; switch (filter) @@ -851,6 +888,13 @@ send_one_eid_table_details (mapping_t * mapit, rmp->eid_type = 2; /* l2 mac type */ clib_memcpy (rmp->eid, mac, 6); break; + case GID_ADDR_NSH: + rmp->eid_type = 3; /* NSH type */ + lisp_nsh_api_t nsh; + nsh.spi = clib_host_to_net_u32 (gid_address_nsh_spi (gid)); + nsh.si = gid_address_nsh_si (gid); + clib_memcpy (rmp->eid, &nsh, sizeof (nsh)); + break; default: ASSERT (0); } @@ -1071,6 +1115,7 @@ one_adjacency_copy (vl_api_one_adjacency_t * dst, lisp_adjacency_t * adjs) lisp_adjacency_t *adj; vl_api_one_adjacency_t a; u32 i, n = vec_len (adjs); + lisp_nsh_api_t nsh; for (i = 0; i < n; i++) { @@ -1100,6 +1145,15 @@ one_adjacency_copy (vl_api_one_adjacency_t * dst, lisp_adjacency_t * adjs) mac_copy (a.reid, gid_address_mac (&adj->reid)); mac_copy (a.leid, gid_address_mac (&adj->leid)); break; + case GID_ADDR_NSH: + a.eid_type = 3; /* NSH type */ + nsh.spi = clib_host_to_net_u32 (gid_address_nsh_spi (&adj->reid)); + nsh.si = gid_address_nsh_si (&adj->reid); + clib_memcpy (a.reid, &nsh, sizeof (nsh)); + + nsh.spi = clib_host_to_net_u32 (gid_address_nsh_spi (&adj->leid)); + nsh.si = gid_address_nsh_si (&adj->leid); + clib_memcpy (a.leid, &nsh, sizeof (nsh)); default: ASSERT (0); } @@ -1255,6 +1309,55 @@ static void vec_free (tmp_str); } +static void +vl_api_show_one_nsh_mapping_t_handler (vl_api_show_one_nsh_mapping_t * mp) +{ + unix_shared_memory_queue_t *q = NULL; + vl_api_show_one_nsh_mapping_reply_t *rmp = NULL; + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + mapping_t *m; + locator_set_t *ls = 0; + u8 *tmp_str = 0; + u8 is_set = 0; + int rv = 0; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + { + return; + } + + if (lcm->nsh_map_index == (u32) ~ 0) + { + tmp_str = format (0, "N/A"); + } + else + { + m = pool_elt_at_index (lcm->mapping_pool, lcm->nsh_map_index); + if (~0 != m->locator_set_index) + { + ls = + pool_elt_at_index (lcm->locator_set_pool, m->locator_set_index); + tmp_str = format (0, "%s", ls->name); + is_set = 1; + } + else + { + tmp_str = format (0, "N/A"); + } + } + vec_add1 (tmp_str, 0); + + /* *INDENT-OFF* */ + REPLY_MACRO2(VL_API_SHOW_ONE_NSH_MAPPING_REPLY, + ({ + rmp->is_set = is_set; + strncpy((char *) rmp->locator_set_name, (char *) tmp_str, + ARRAY_LEN(rmp->locator_set_name) - 1); + })); + /* *INDENT-ON* */ +} + static void vl_api_show_one_pitr_t_handler (vl_api_show_one_pitr_t * mp) { diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c index db6a6c83..e3fbf5a1 100644 --- a/src/vnet/lisp-cp/one_cli.c +++ b/src/vnet/lisp-cp/one_cli.c @@ -721,6 +721,62 @@ VLIB_CLI_COMMAND (one_show_map_resolvers_command) = { }; /* *INDENT-ON* */ +static clib_error_t * +lisp_nsh_set_locator_set_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + u8 locator_name_set = 0; + u8 *locator_set_name = 0; + u8 is_add = 1; + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = 0; + int rv = 0; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "ls %_%v%_", &locator_set_name)) + locator_name_set = 1; + else if (unformat (line_input, "disable")) + is_add = 0; + else + { + error = clib_error_return (0, "parse error"); + goto done; + } + } + + if (!locator_name_set) + { + clib_warning ("No locator set specified!"); + goto done; + } + + rv = vnet_lisp_nsh_set_locator_set (locator_set_name, is_add); + if (0 != rv) + { + error = clib_error_return (0, "failed to %s NSH mapping!", + is_add ? "add" : "delete"); + } + +done: + vec_free (locator_set_name); + unformat_free (line_input); + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_nsh_set_locator_set_command) = { + .path = "one nsh-mapping", + .short_help = "one nsh-mapping [del] ls ", + .function = lisp_nsh_set_locator_set_command_fn, +}; +/* *INDENT-ON* */ + static clib_error_t * lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm, @@ -923,7 +979,7 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ pool_foreach (mapit, lcm->mapping_pool, ({ - if (mapit->pitr_set) + if (mapit->pitr_set || mapit->nsh_set) continue; locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool, diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c index 94703abc..52b939f0 100644 --- a/src/vnet/lisp-gpe/interface.c +++ b/src/vnet/lisp-gpe/interface.c @@ -742,7 +742,7 @@ lisp_gpe_del_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id) * @return sw_if_index. */ u32 -lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm) +vnet_lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm) { vnet_main_t *vnm = lgm->vnet_main; tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces; @@ -782,7 +782,7 @@ lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm) * */ void -lisp_gpe_del_nsh_iface (lisp_gpe_main_t * lgm) +vnet_lisp_gpe_del_nsh_iface (lisp_gpe_main_t * lgm) { tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces; uword *hip; @@ -851,7 +851,7 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, { if (is_add) { - if (~0 == lisp_gpe_add_nsh_iface (&lisp_gpe_main)) + if (~0 == vnet_lisp_gpe_add_nsh_iface (&lisp_gpe_main)) { error = clib_error_return (0, "NSH interface not created"); goto done; @@ -859,7 +859,7 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, } else { - lisp_gpe_del_nsh_iface (&lisp_gpe_main); + vnet_lisp_gpe_del_nsh_iface (&lisp_gpe_main); } goto done; } diff --git a/src/vnet/lisp-gpe/lisp_gpe.h b/src/vnet/lisp-gpe/lisp_gpe.h index 660f8a66..5eafdd55 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.h +++ b/src/vnet/lisp-gpe/lisp_gpe.h @@ -324,6 +324,9 @@ vnet_api_error_t vnet_lisp_stats_enable_disable (u8 enable); lisp_api_stats_t *vnet_lisp_get_stats (void); int vnet_lisp_flush_stats (void); int vnet_gpe_add_del_native_fwd_rpath (vnet_gpe_native_fwd_rpath_args_t * a); +u32 vnet_lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm); +void vnet_lisp_gpe_del_nsh_iface (lisp_gpe_main_t * lgm); + #endif /* included_vnet_lisp_gpe_h */ /* diff --git a/src/vpp/api/test_client.c b/src/vpp/api/test_client.c index 231b3c18..844b9702 100644 --- a/src/vpp/api/test_client.c +++ b/src/vpp/api/test_client.c @@ -245,6 +245,7 @@ static void vl_api_ip_neighbor_add_del_reply_t_handler fformat (stdout, "ip neighbor add del reply %d\n", ntohl (mp->retval)); } +#if 0 static void vl_api_vnet_interface_counters_t_handler (vl_api_vnet_interface_counters_t * mp) @@ -332,6 +333,7 @@ vl_api_vnet_interface_counters_t_handler (vl_api_vnet_interface_counters_t * } } } +#endif /* Format an IP4 address. */ u8 * @@ -578,7 +580,6 @@ _(WANT_STATS_REPLY, want_stats_reply) \ _(WANT_OAM_EVENTS_REPLY, want_oam_events_reply) \ _(OAM_EVENT, oam_event) \ _(OAM_ADD_DEL_REPLY, oam_add_del_reply) \ -_(VNET_INTERFACE_COUNTERS, vnet_interface_counters) \ _(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \ _(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \ _(IP_ADD_DEL_ROUTE_REPLY, ip_add_del_route_reply) \ -- cgit 1.2.3-korg From 809bc74b5b73634678e6f1444344fd1c0a89e877 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Mon, 14 Aug 2017 19:15:36 +0200 Subject: LISP: re-fetch mapping before it expires Change-Id: I0581a1bddad55d8d573c546ec84b0b2760abab3d Signed-off-by: Filip Tehlar --- src/vnet/lisp-cp/control.c | 322 +++++++++++++++++++---------- src/vnet/lisp-cp/control.h | 8 +- src/vnet/lisp-cp/lisp_api.c | 15 +- src/vnet/lisp-cp/lisp_cli.c | 15 +- src/vnet/lisp-cp/lisp_types.h | 6 +- src/vnet/lisp-cp/one_api.c | 15 +- src/vnet/lisp-cp/one_cli.c | 15 +- src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c | 60 ++++-- src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h | 10 + src/vnet/lisp-gpe/lisp_gpe_sub_interface.c | 2 +- 10 files changed, 330 insertions(+), 138 deletions(-) (limited to 'src/vnet/lisp-cp/lisp_types.h') diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 59a45ed8..c811e789 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -30,9 +30,14 @@ #define MAX_VALUE_U24 0xffffff +/* mapping timer control constants (in seconds) */ +#define TIME_UNTIL_REFETCH_OR_DELETE 20 +#define MAPPING_TIMEOUT (((m->ttl) * 60) - TIME_UNTIL_REFETCH_OR_DELETE) + lisp_cp_main_t lisp_control_main; u8 *format_lisp_cp_input_trace (u8 * s, va_list * args); +static void *send_map_request_thread_fn (void *arg); typedef enum { @@ -1102,7 +1107,7 @@ remove_overlapping_sub_prefixes (lisp_cp_main_t * lcm, gid_address_t * eid, if (vnet_lisp_add_del_adjacency (adj_args)) clib_warning ("failed to del adjacency!"); - vnet_lisp_add_del_mapping (e, 0, 0, 0, 0, 0 /* is add */ , 0, 0); + vnet_lisp_del_mapping (e, NULL); } vec_free (a.eids_to_be_deleted); @@ -1129,24 +1134,19 @@ is_local_ip (lisp_cp_main_t * lcm, ip_address_t * addr) } /** - * Adds/removes/updates mapping. Does not program forwarding. + * Adds/updates mapping. Does not program forwarding. * - * @param eid end-host identifier + * @param a parameters of the new mapping * @param rlocs vector of remote locators - * @param action action for negative map-reply - * @param is_add add mapping if non-zero, delete otherwise - * @param res_map_index the map-index that was created/updated/removed. It is - * set to ~0 if no action is taken. - * @param is_static used for distinguishing between statically learned - remote mappings and mappings obtained from MR + * @param res_map_index index of the newly created mapping + * @param locators_changed indicator if locators were updated in the mapping * @return return code */ int -vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action, - u8 authoritative, u32 ttl, u8 is_add, u8 is_static, - u32 * res_map_index) +vnet_lisp_add_mapping (vnet_lisp_add_del_mapping_args_t * a, + locator_t * rlocs, + u32 * res_map_index, u8 * is_updated) { - vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args; vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args; lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); u32 mi, ls_index = 0, dst_map_index; @@ -1161,115 +1161,138 @@ vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action, if (res_map_index) res_map_index[0] = ~0; + if (is_updated) + is_updated[0] = 0; - memset (m_args, 0, sizeof (m_args[0])); memset (ls_args, 0, sizeof (ls_args[0])); ls_args->locators = rlocs; - - mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, eid); + mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->eid); old_map = ((u32) ~ 0 != mi) ? pool_elt_at_index (lcm->mapping_pool, mi) : 0; - if (is_add) - { - /* check if none of the locators match localy configured address */ - vec_foreach (loc, rlocs) + /* check if none of the locators match localy configured address */ + vec_foreach (loc, rlocs) + { + ip_prefix_t *p = &gid_address_ippref (&loc->address); + if (is_local_ip (lcm, &ip_prefix_addr (p))) { - ip_prefix_t *p = &gid_address_ippref (&loc->address); - if (is_local_ip (lcm, &ip_prefix_addr (p))) - { - clib_warning ("RLOC %U matches a local address!", - format_gid_address, &loc->address); - return VNET_API_ERROR_LISP_RLOC_LOCAL; - } + clib_warning ("RLOC %U matches a local address!", + format_gid_address, &loc->address); + return VNET_API_ERROR_LISP_RLOC_LOCAL; } + } - /* overwrite: if mapping already exists, decide if locators should be - * updated and be done */ - if (old_map && gid_address_cmp (&old_map->eid, eid) == 0) + /* overwrite: if mapping already exists, decide if locators should be + * updated and be done */ + if (old_map && gid_address_cmp (&old_map->eid, &a->eid) == 0) + { + if (!a->is_static && (old_map->is_static || old_map->local)) { - if (!is_static && (old_map->is_static || old_map->local)) - { - /* do not overwrite local or static remote mappings */ - clib_warning ("mapping %U rejected due to collision with local " - "or static remote mapping!", format_gid_address, - eid); - return 0; - } - - locator_set_t *old_ls; - - /* update mapping attributes */ - old_map->action = action; - old_map->authoritative = authoritative; - old_map->ttl = ttl; - - old_ls = pool_elt_at_index (lcm->locator_set_pool, - old_map->locator_set_index); - if (compare_locators (lcm, old_ls->locator_indices, - ls_args->locators)) - { - /* set locator-set index to overwrite */ - ls_args->is_add = 1; - ls_args->index = old_map->locator_set_index; - vnet_lisp_add_del_locator_set (ls_args, 0); - if (res_map_index) - res_map_index[0] = mi; - } + /* do not overwrite local or static remote mappings */ + clib_warning ("mapping %U rejected due to collision with local " + "or static remote mapping!", format_gid_address, + &a->eid); + return 0; } - /* new mapping */ - else - { - remove_overlapping_sub_prefixes (lcm, eid, 0 == ls_args->locators); - ls_args->is_add = 1; - ls_args->index = ~0; + locator_set_t *old_ls; - vnet_lisp_add_del_locator_set (ls_args, &ls_index); + /* update mapping attributes */ + old_map->action = a->action; + if (old_map->action != a->action && NULL != is_updated) + is_updated[0] = 1; - /* add mapping */ - gid_address_copy (&m_args->eid, eid); - m_args->is_add = 1; - m_args->action = action; - m_args->locator_set_index = ls_index; - m_args->is_static = is_static; - m_args->ttl = ttl; - vnet_lisp_map_cache_add_del (m_args, &dst_map_index); + old_map->authoritative = a->authoritative; + old_map->ttl = a->ttl; - if (res_map_index) - res_map_index[0] = dst_map_index; + old_ls = pool_elt_at_index (lcm->locator_set_pool, + old_map->locator_set_index); + if (compare_locators (lcm, old_ls->locator_indices, ls_args->locators)) + { + /* set locator-set index to overwrite */ + ls_args->is_add = 1; + ls_args->index = old_map->locator_set_index; + vnet_lisp_add_del_locator_set (ls_args, 0); + if (is_updated) + is_updated[0] = 1; } + if (res_map_index) + res_map_index[0] = mi; } + /* new mapping */ else { - if (old_map == 0 || gid_address_cmp (&old_map->eid, eid) != 0) - { - clib_warning ("cannot delete mapping for eid %U", - format_gid_address, eid); - return -1; - } - - m_args->is_add = 0; - gid_address_copy (&m_args->eid, eid); - m_args->locator_set_index = old_map->locator_set_index; + remove_overlapping_sub_prefixes (lcm, &a->eid, 0 == ls_args->locators); - /* delete mapping associated from map-cache */ - vnet_lisp_map_cache_add_del (m_args, 0); + ls_args->is_add = 1; + ls_args->index = ~0; - ls_args->is_add = 0; - ls_args->index = old_map->locator_set_index; - /* delete locator set */ - vnet_lisp_add_del_locator_set (ls_args, 0); + vnet_lisp_add_del_locator_set (ls_args, &ls_index); - /* delete timer associated to the mapping if any */ - if (old_map->timer_set) - mapping_delete_timer (lcm, mi); + /* add mapping */ + a->is_add = 1; + a->locator_set_index = ls_index; + vnet_lisp_map_cache_add_del (a, &dst_map_index); - /* return old mapping index */ if (res_map_index) - res_map_index[0] = mi; + res_map_index[0] = dst_map_index; + } + + /* success */ + return 0; +} + +/** + * Removes a mapping. Does not program forwarding. + * + * @param eid end-host indetifier + * @param res_map_index index of the removed mapping + * @return return code + */ +int +vnet_lisp_del_mapping (gid_address_t * eid, u32 * res_map_index) +{ + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args; + vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args; + mapping_t *old_map; + u32 mi; + + memset (m_args, 0, sizeof (m_args[0])); + if (res_map_index) + res_map_index[0] = ~0; + + mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, eid); + old_map = ((u32) ~ 0 != mi) ? pool_elt_at_index (lcm->mapping_pool, mi) : 0; + + if (old_map == 0 || gid_address_cmp (&old_map->eid, eid) != 0) + { + clib_warning ("cannot delete mapping for eid %U", + format_gid_address, eid); + return -1; } + m_args->is_add = 0; + gid_address_copy (&m_args->eid, eid); + m_args->locator_set_index = old_map->locator_set_index; + + /* delete mapping associated from map-cache */ + vnet_lisp_map_cache_add_del (m_args, 0); + + ls_args->is_add = 0; + ls_args->index = old_map->locator_set_index; + + /* delete locator set */ + vnet_lisp_add_del_locator_set (ls_args, 0); + + /* delete timer associated to the mapping if any */ + if (old_map->timer_set) + mapping_delete_timer (lcm, mi); + + /* return old mapping index */ + if (res_map_index) + res_map_index[0] = mi; + /* success */ return 0; } @@ -3372,8 +3395,7 @@ remove_expired_mapping (lisp_cp_main_t * lcm, u32 mi) if (vnet_lisp_add_del_adjacency (adj_args)) clib_warning ("failed to del adjacency!"); - vnet_lisp_add_del_mapping (&m->eid, 0, 0, 0, ~0, 0 /* is_add */ , - 0 /* is_static */ , 0); + vnet_lisp_del_mapping (&m->eid, NULL); mapping_delete_timer (lcm, mi); } @@ -3392,6 +3414,73 @@ mapping_start_expiration_timer (lisp_cp_main_t * lcm, u32 mi, timing_wheel_insert (&lcm->wheel, exp_clock_time, mi); } +static void +process_expired_mapping (lisp_cp_main_t * lcm, u32 mi) +{ + int rv; + vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a; + mapping_t *m = pool_elt_at_index (lcm->mapping_pool, mi); + uword *fei; + fwd_entry_t *fe; + vlib_counter_t c; + u8 have_stats = 0; + + if (m->delete_after_expiration) + { + remove_expired_mapping (lcm, mi); + return; + } + + fei = hash_get (lcm->fwd_entry_by_mapping_index, mi); + if (!fei) + return; + + fe = pool_elt_at_index (lcm->fwd_entry_pool, fei[0]); + + memset (a, 0, sizeof (*a)); + a->rmt_eid = fe->reid; + if (fe->is_src_dst) + a->lcl_eid = fe->leid; + a->vni = gid_address_vni (&fe->reid); + + rv = vnet_lisp_gpe_get_fwd_stats (a, &c); + if (0 == rv) + have_stats = 1; + + if (m->almost_expired) + { + m->almost_expired = 0; /* reset flag */ + if (have_stats) + { + if (m->packets != c.packets) + { + /* mapping is in use, re-fetch */ + map_request_args_t mr_args; + memset (&mr_args, 0, sizeof (mr_args)); + mr_args.seid = fe->leid; + mr_args.deid = fe->reid; + + send_map_request_thread_fn (&mr_args); + } + else + remove_expired_mapping (lcm, mi); + } + else + remove_expired_mapping (lcm, mi); + } + else + { + m->almost_expired = 1; + mapping_start_expiration_timer (lcm, mi, TIME_UNTIL_REFETCH_OR_DELETE); + + if (have_stats) + /* save counter */ + m->packets = c.packets; + else + m->delete_after_expiration = 1; + } +} + static void map_records_arg_free (map_records_arg_t * a) { @@ -3414,6 +3503,7 @@ process_map_reply (map_records_arg_t * a) pending_map_request_t *pmr; u64 *noncep; uword *pmr_index; + u8 is_changed = 0; if (a->is_rloc_probe) goto done; @@ -3429,26 +3519,36 @@ process_map_reply (map_records_arg_t * a) vec_foreach (m, a->mappings) { + vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args; + memset (m_args, 0, sizeof (m_args[0])); + gid_address_copy (&m_args->eid, &m->eid); + m_args->action = m->action; + m_args->authoritative = m->authoritative; + m_args->ttl = m->ttl; + m_args->is_static = 0; + /* insert/update mappings cache */ - vnet_lisp_add_del_mapping (&m->eid, m->locators, m->action, - m->authoritative, m->ttl, - 1, 0 /* is_static */ , &dst_map_index); + vnet_lisp_add_mapping (m_args, m->locators, &dst_map_index, &is_changed); if (dst_map_index == (u32) ~ 0) continue; - /* try to program forwarding only if mapping saved or updated */ - vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args; - memset (adj_args, 0, sizeof (adj_args[0])); + if (is_changed) + { + /* try to program forwarding only if mapping saved or updated */ + vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args; + memset (adj_args, 0, sizeof (adj_args[0])); - gid_address_copy (&adj_args->leid, &pmr->src); - gid_address_copy (&adj_args->reid, &m->eid); - adj_args->is_add = 1; - if (vnet_lisp_add_del_adjacency (adj_args)) - clib_warning ("failed to add adjacency!"); + gid_address_copy (&adj_args->leid, &pmr->src); + gid_address_copy (&adj_args->reid, &m->eid); + adj_args->is_add = 1; + + if (vnet_lisp_add_del_adjacency (adj_args)) + clib_warning ("failed to add adjacency!"); + } if ((u32) ~ 0 != m->ttl) - mapping_start_expiration_timer (lcm, dst_map_index, m->ttl * 60); + mapping_start_expiration_timer (lcm, dst_map_index, MAPPING_TIMEOUT); } /* remove pending map request entry */ @@ -4379,7 +4479,7 @@ send_map_resolver_service (vlib_main_t * vm, u32 *mi = 0; vec_foreach (mi, expired) { - remove_expired_mapping (lcm, mi[0]); + process_expired_mapping (lcm, mi[0]); } _vec_len (expired) = 0; } diff --git a/src/vnet/lisp-cp/control.h b/src/vnet/lisp-cp/control.h index 7b0380fb..a3e2fc25 100644 --- a/src/vnet/lisp-cp/control.h +++ b/src/vnet/lisp-cp/control.h @@ -329,9 +329,11 @@ vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a, u32 * map_index_result); int -vnet_lisp_add_del_mapping (gid_address_t * deid, locator_t * dlocs, u8 action, - u8 authoritative, u32 ttl, u8 is_add, u8 is_static, - u32 * res_map_index); +vnet_lisp_add_mapping (vnet_lisp_add_del_mapping_args_t * a, + locator_t * rlocs, u32 * res_map_index, + u8 * is_changed); + +int vnet_lisp_del_mapping (gid_address_t * eid, u32 * res_map_index); typedef struct { diff --git a/src/vnet/lisp-cp/lisp_api.c b/src/vnet/lisp-cp/lisp_api.c index 6c82d4cf..f7c41971 100644 --- a/src/vnet/lisp-cp/lisp_api.c +++ b/src/vnet/lisp-cp/lisp_api.c @@ -521,8 +521,19 @@ static void /* NOTE: for now this works as a static remote mapping, i.e., * not authoritative and ttl infinite. */ - rv = vnet_lisp_add_del_mapping (eid, rlocs, mp->action, 0, ~0, - mp->is_add, 1 /* is_static */ , 0); + if (mp->is_add) + { + vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args; + memset (m_args, 0, sizeof (m_args[0])); + gid_address_copy (&m_args->eid, eid); + m_args->action = mp->action; + m_args->is_static = 1; + m_args->ttl = ~0; + m_args->authoritative = 0; + rv = vnet_lisp_add_mapping (m_args, rlocs, NULL, NULL); + } + else + rv = vnet_lisp_del_mapping (eid, NULL); if (mp->del_all) vnet_lisp_clear_all_remote_adjacencies (); diff --git a/src/vnet/lisp-cp/lisp_cli.c b/src/vnet/lisp-cp/lisp_cli.c index 05df9fb6..50904601 100644 --- a/src/vnet/lisp-cp/lisp_cli.c +++ b/src/vnet/lisp-cp/lisp_cli.c @@ -394,8 +394,19 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm, /* add as static remote mapping, i.e., not authoritative and infinite * ttl */ - rv = vnet_lisp_add_del_mapping (&eid, rlocs, action, 0, ~0, is_add, - 1 /* is_static */ , 0); + if (is_add) + { + vnet_lisp_add_del_mapping_args_t _map_args, *map_args = &_map_args; + memset (map_args, 0, sizeof (map_args[0])); + gid_address_copy (&map_args->eid, &eid); + map_args->action = action; + map_args->is_static = 1; + map_args->authoritative = 0; + map_args->ttl = ~0; + rv = vnet_lisp_add_mapping (map_args, rlocs, NULL, NULL); + } + else + rv = vnet_lisp_del_mapping (&eid, NULL); if (rv) clib_warning ("failed to %s remote mapping!", is_add ? "add" : "delete"); diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h index b7ad0f27..b17110f6 100644 --- a/src/vnet/lisp-cp/lisp_types.h +++ b/src/vnet/lisp-cp/lisp_types.h @@ -358,12 +358,14 @@ typedef struct u8 is_static:1; u8 pitr_set:1; u8 nsh_set:1; - u8 rsvd:3; - + u8 almost_expired:1; + u8 delete_after_expiration:1; + u8 rsvd:1; u8 *key; lisp_key_type_t key_id; u8 timer_set; + counter_t packets; } mapping_t; uword diff --git a/src/vnet/lisp-cp/one_api.c b/src/vnet/lisp-cp/one_api.c index 620d56fb..b8e3f704 100644 --- a/src/vnet/lisp-cp/one_api.c +++ b/src/vnet/lisp-cp/one_api.c @@ -620,8 +620,19 @@ static void /* NOTE: for now this works as a static remote mapping, i.e., * not authoritative and ttl infinite. */ - rv = vnet_lisp_add_del_mapping (eid, rlocs, mp->action, 0, ~0, - mp->is_add, 1 /* is_static */ , 0); + if (mp->is_add) + { + vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args; + memset (m_args, 0, sizeof (m_args[0])); + gid_address_copy (&m_args->eid, eid); + m_args->action = mp->action; + m_args->is_static = 1; + m_args->ttl = ~0; + m_args->authoritative = 0; + rv = vnet_lisp_add_mapping (m_args, rlocs, NULL, NULL); + } + else + rv = vnet_lisp_del_mapping (eid, NULL); if (mp->del_all) vnet_lisp_clear_all_remote_adjacencies (); diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c index e165f71c..3e0c4c0a 100644 --- a/src/vnet/lisp-cp/one_cli.c +++ b/src/vnet/lisp-cp/one_cli.c @@ -487,8 +487,19 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm, /* add as static remote mapping, i.e., not authoritative and infinite * ttl */ - rv = vnet_lisp_add_del_mapping (&eid, rlocs, action, 0, ~0, is_add, - 1 /* is_static */ , 0); + if (is_add) + { + vnet_lisp_add_del_mapping_args_t _map_args, *map_args = &_map_args; + memset (map_args, 0, sizeof (map_args[0])); + gid_address_copy (&map_args->eid, &eid); + map_args->action = action; + map_args->is_static = 1; + map_args->authoritative = 0; + map_args->ttl = ~0; + rv = vnet_lisp_add_mapping (map_args, rlocs, NULL, NULL); + } + else + rv = vnet_lisp_del_mapping (&eid, NULL); if (rv) clib_warning ("failed to %s remote mapping!", is_add ? "add" : "delete"); diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c index ac048149..d7d3cb86 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c +++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c @@ -193,12 +193,15 @@ ip_src_dst_fib_del_route (u32 src_fib_index, * @param[in] src_fib_index The index/ID of the SRC FIB * @param[in] src_prefix Source IP prefix. * @param[in] src_dpo The DPO the route will link to. + * + * @return fib index of the inserted prefix */ -static void +static fib_node_index_t ip_src_fib_add_route_w_dpo (u32 src_fib_index, const ip_prefix_t * src_prefix, const dpo_id_t * src_dpo) { + fib_node_index_t fei = ~0; fib_prefix_t src_fib_prefix; ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix); @@ -213,11 +216,13 @@ ip_src_fib_add_route_w_dpo (u32 src_fib_index, if (FIB_NODE_INDEX_INVALID == src_fei || !fib_entry_is_sourced (src_fei, FIB_SOURCE_LISP)) { - fib_table_entry_special_dpo_add (src_fib_index, - &src_fib_prefix, - FIB_SOURCE_LISP, - FIB_ENTRY_FLAG_EXCLUSIVE, src_dpo); + fei = fib_table_entry_special_dpo_add (src_fib_index, + &src_fib_prefix, + FIB_SOURCE_LISP, + FIB_ENTRY_FLAG_EXCLUSIVE, + src_dpo); } + return fei; } static fib_route_path_t * @@ -262,7 +267,7 @@ lisp_gpe_mk_fib_paths (const lisp_fwd_path_t * paths) * @param[in] paths The paths from which to construct the * load balance */ -static void +static fib_node_index_t ip_src_fib_add_route (u32 src_fib_index, const ip_prefix_t * src_prefix, const lisp_fwd_path_t * paths) @@ -274,10 +279,11 @@ ip_src_fib_add_route (u32 src_fib_index, rpaths = lisp_gpe_mk_fib_paths (paths); - fib_table_entry_update (src_fib_index, - &src_fib_prefix, - FIB_SOURCE_LISP, FIB_ENTRY_FLAG_NONE, rpaths); + fib_node_index_t fib_entry_index = + fib_table_entry_update (src_fib_index, &src_fib_prefix, FIB_SOURCE_LISP, + FIB_ENTRY_FLAG_NONE, rpaths); vec_free (rpaths); + return fib_entry_index; } static void @@ -311,9 +317,11 @@ gpe_native_fwd_add_del_lfe (lisp_gpe_fwd_entry_t * lfe, u8 is_add) } } -static void +static index_t create_fib_entries (lisp_gpe_fwd_entry_t * lfe) { + fib_node_index_t fi; + fib_entry_t *fe; lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); dpo_proto_t dproto; ip_prefix_t ippref; @@ -361,13 +369,15 @@ create_fib_entries (lisp_gpe_fwd_entry_t * lfe) dpo_copy (&dpo, drop_dpo_get (dproto)); break; } - ip_src_fib_add_route_w_dpo (lfe->src_fib_index, &ippref, &dpo); + fi = ip_src_fib_add_route_w_dpo (lfe->src_fib_index, &ippref, &dpo); dpo_reset (&dpo); } else { - ip_src_fib_add_route (lfe->src_fib_index, &ippref, lfe->paths); + fi = ip_src_fib_add_route (lfe->src_fib_index, &ippref, lfe->paths); } + fe = fib_entry_get (fi); + return fe->fe_lb.dpoi_index; } static void @@ -546,7 +556,7 @@ add_ip_fwd_entry (lisp_gpe_main_t * lgm, lfe->action = a->action; } - create_fib_entries (lfe); + lfe->dpoi_index = create_fib_entries (lfe); return (0); } @@ -793,6 +803,7 @@ lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe) lisp_l2_fib_add_del_entry (lfe->l2.eid_bd_index, fid_addr_mac (&lfe->key->lcl), fid_addr_mac (&lfe->key->rmt), &dpo, 1); + lfe->dpoi_index = dpo.dpoi_index; dpo_reset (&dpo); } @@ -1538,6 +1549,29 @@ vnet_lisp_gpe_fwd_entries_get_by_vni (u32 vni) return entries; } +int +vnet_lisp_gpe_get_fwd_stats (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, + vlib_counter_t * c) +{ + lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); + lisp_gpe_fwd_entry_t *lfe; + lisp_gpe_fwd_entry_key_t unused; + + lfe = find_fwd_entry (lgm, a, &unused); + if (NULL == lfe) + return -1; + + if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE == lfe->type) + return -1; + + if (~0 == lfe->dpoi_index) + return -1; + + vlib_get_combined_counter (&load_balance_main.lbm_to_counters, + lfe->dpoi_index, c); + return 0; +} + VLIB_INIT_FUNCTION (lisp_gpe_fwd_entry_init); /* diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h index 15803516..dfdb8b91 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h +++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h @@ -198,6 +198,12 @@ typedef struct lisp_gpe_fwd_entry_t_ */ negative_fwd_actions_e action; }; + + /** + * used for getting load balance statistics + */ + index_t dpoi_index; + } lisp_gpe_fwd_entry_t; extern int @@ -219,6 +225,10 @@ vnet_lisp_gpe_add_fwd_counters (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, u32 fwd_entry_index); extern u32 *vnet_lisp_gpe_get_fwd_entry_vnis (void); +int +vnet_lisp_gpe_get_fwd_stats (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, + vlib_counter_t * c); + #endif /* diff --git a/src/vnet/lisp-gpe/lisp_gpe_sub_interface.c b/src/vnet/lisp-gpe/lisp_gpe_sub_interface.c index 7146b380..b234d9dc 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_sub_interface.c +++ b/src/vnet/lisp-gpe/lisp_gpe_sub_interface.c @@ -192,7 +192,7 @@ lisp_gpe_sub_interface_unlock (index_t l3si) lisp_gpe_sub_interface_unset_table (l3s->sw_if_index, l3s->eid_table_id); - lisp_gpe_tenant_l3_iface_unlock (clib_net_to_host_u32 (l3s->key->vni)); + lisp_gpe_tenant_l3_iface_unlock (l3s->key->vni); vnet_sw_interface_set_flags (vnet_get_main (), l3s->sw_if_index, 0); vnet_delete_sub_interface (l3s->sw_if_index); -- cgit 1.2.3-korg From 058799951d062bbbe4df8df101b4db5bc7797b8f Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Tue, 5 Sep 2017 15:46:09 +0200 Subject: LISP: support for neighbor discovery Change-Id: I0f1a051dd3b5786dc7c457bc6fc7ce4fcd0f530c Signed-off-by: Filip Tehlar --- src/vat/api_format.c | 233 +++++++++++++++++++++++++++++++++++++ src/vnet/lisp-cp/control.c | 236 +++++++++++++++++++++++++++++--------- src/vnet/lisp-cp/control.h | 8 ++ src/vnet/lisp-cp/gid_dictionary.c | 82 +++++++------ src/vnet/lisp-cp/gid_dictionary.h | 24 ++-- src/vnet/lisp-cp/lisp_types.c | 5 +- src/vnet/lisp-cp/lisp_types.h | 26 +++-- src/vnet/lisp-cp/one_api.c | 77 ++++++++++++- src/vnet/lisp-cp/one_cli.c | 36 ++++++ 9 files changed, 617 insertions(+), 110 deletions(-) (limited to 'src/vnet/lisp-cp/lisp_types.h') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index ff3354c9..520ae4f6 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -3392,6 +3392,71 @@ end: vam->result_ready = 1; } +static void + vl_api_one_ndp_entries_get_reply_t_handler + (vl_api_one_ndp_entries_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + + for (i = 0; i < n; i++) + print (vam->ofp, "%U -> %U", format_ip6_address, &mp->entries[i].ip6, + format_ethernet_address, mp->entries[i].mac); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_one_ndp_entries_get_reply_t_handler_json + (vl_api_one_ndp_entries_get_reply_t * mp) +{ + u8 *s = 0; + vat_main_t *vam = &vat_main; + vat_json_node_t *e = 0, root; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + vl_api_one_ndp_entry_t *arp_entry; + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + vat_json_init_array (&root); + + for (i = 0; i < n; i++) + { + e = vat_json_array_add (&root); + arp_entry = &mp->entries[i]; + + vat_json_init_object (e); + s = format (0, "%U", format_ethernet_address, arp_entry->mac); + vec_add1 (s, 0); + + vat_json_object_add_string_copy (e, "mac", s); + vec_free (s); + + s = format (0, "%U", format_ip6_address, &arp_entry->ip6); + vec_add1 (s, 0); + vat_json_object_add_string_copy (e, "ip6", s); + vec_free (s); + } + + vat_json_print (vam->ofp, &root); + vat_json_free (&root); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + static void vl_api_one_l2_arp_entries_get_reply_t_handler (vl_api_one_l2_arp_entries_get_reply_t * mp) @@ -3457,6 +3522,57 @@ end: vam->result_ready = 1; } +static void +vl_api_one_ndp_bd_get_reply_t_handler (vl_api_one_ndp_bd_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + + for (i = 0; i < n; i++) + { + print (vam->ofp, "%d", clib_net_to_host_u32 (mp->bridge_domains[i])); + } + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_one_ndp_bd_get_reply_t_handler_json + (vl_api_one_ndp_bd_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t root; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + vat_json_init_array (&root); + + for (i = 0; i < n; i++) + { + vat_json_array_add_uint (&root, + clib_net_to_host_u32 (mp->bridge_domains[i])); + } + + vat_json_print (vam->ofp, &root); + vat_json_free (&root); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + static void vl_api_one_l2_arp_bd_get_reply_t_handler (vl_api_one_l2_arp_bd_get_reply_t * mp) @@ -4590,6 +4706,10 @@ static void vl_api_flow_classify_details_t_handler_json #define vl_api_one_l2_arp_entries_get_reply_t_endian vl_noop_handler #define vl_api_one_l2_arp_entries_get_reply_t_print vl_noop_handler #define vl_api_one_l2_arp_bd_get_reply_t_endian vl_noop_handler +#define vl_api_one_ndp_bd_get_reply_t_endian vl_noop_handler +#define vl_api_one_ndp_bd_get_reply_t_print vl_noop_handler +#define vl_api_one_ndp_entries_get_reply_t_print vl_noop_handler +#define vl_api_one_ndp_entries_get_reply_t_endian vl_noop_handler /* * Generate boilerplate reply handlers, which @@ -4706,6 +4826,7 @@ _(one_eid_table_add_del_map_reply) \ _(one_use_petr_reply) \ _(one_stats_enable_disable_reply) \ _(one_add_del_l2_arp_entry_reply) \ +_(one_add_del_ndp_entry_reply) \ _(one_stats_flush_reply) \ _(gpe_enable_disable_reply) \ _(gpe_set_encap_mode_reply) \ @@ -4950,6 +5071,9 @@ _(ONE_STATS_FLUSH_REPLY, one_stats_flush_reply) \ _(ONE_STATS_ENABLE_DISABLE_REPLY, one_stats_enable_disable_reply) \ _(SHOW_ONE_STATS_ENABLE_DISABLE_REPLY, \ show_one_stats_enable_disable_reply) \ +_(ONE_ADD_DEL_NDP_ENTRY_REPLY, one_add_del_ndp_entry_reply) \ +_(ONE_NDP_BD_GET_REPLY, one_ndp_bd_get_reply) \ +_(ONE_NDP_ENTRIES_GET_REPLY, one_ndp_entries_get_reply) \ _(ONE_ADD_DEL_L2_ARP_ENTRY_REPLY, one_add_del_l2_arp_entry_reply) \ _(ONE_L2_ARP_BD_GET_REPLY, one_l2_arp_bd_get_reply) \ _(ONE_L2_ARP_ENTRIES_GET_REPLY, one_l2_arp_entries_get_reply) \ @@ -15413,6 +15537,58 @@ api_show_one_rloc_probe_state (vat_main_t * vam) #define api_show_lisp_rloc_probe_state api_show_one_rloc_probe_state +static int +api_one_add_del_ndp_entry (vat_main_t * vam) +{ + vl_api_one_add_del_ndp_entry_t *mp; + unformat_input_t *input = vam->input; + u8 is_add = 1; + u8 mac_set = 0; + u8 bd_set = 0; + u8 ip_set = 0; + u8 mac[6] = { 0, }; + u8 ip6[16] = { 0, }; + u32 bd = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "mac %U", unformat_ethernet_address, mac)) + mac_set = 1; + else if (unformat (input, "ip %U", unformat_ip6_address, ip6)) + ip_set = 1; + else if (unformat (input, "bd %d", &bd)) + bd_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!bd_set || !ip_set || (!mac_set && is_add)) + { + errmsg ("Missing BD, IP or MAC!"); + return -99; + } + + M (ONE_ADD_DEL_NDP_ENTRY, mp); + mp->is_add = is_add; + clib_memcpy (mp->mac, mac, 6); + mp->bd = clib_host_to_net_u32 (bd); + clib_memcpy (mp->ip6, ip6, sizeof (mp->ip6)); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + static int api_one_add_del_l2_arp_entry (vat_main_t * vam) { @@ -15464,6 +15640,60 @@ api_one_add_del_l2_arp_entry (vat_main_t * vam) return ret; } +static int +api_one_ndp_bd_get (vat_main_t * vam) +{ + vl_api_one_ndp_bd_get_t *mp; + int ret; + + M (ONE_NDP_BD_GET, mp); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + +static int +api_one_ndp_entries_get (vat_main_t * vam) +{ + vl_api_one_ndp_entries_get_t *mp; + unformat_input_t *input = vam->input; + u8 bd_set = 0; + u32 bd = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "bd %d", &bd)) + bd_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!bd_set) + { + errmsg ("Expected bridge domain!"); + return -99; + } + + M (ONE_NDP_ENTRIES_GET, mp); + mp->bd = clib_host_to_net_u32 (bd); + + /* send */ + S (mp); + + /* wait for reply */ + W (ret); + return ret; +} + static int api_one_l2_arp_bd_get (vat_main_t * vam) { @@ -20411,6 +20641,9 @@ _(one_locator_set_dump, "[local | remote]") \ _(one_locator_dump, "ls_index | ls_name ") \ _(one_eid_table_dump, "[eid / | ] [vni] " \ "[local] | [remote]") \ +_(one_add_del_ndp_entry, "[del] mac bd ip6 ") \ +_(one_ndp_bd_get, "") \ +_(one_ndp_entries_get, "bd ") \ _(one_add_del_l2_arp_entry, "[del] mac bd ip4 ") \ _(one_l2_arp_bd_get, "") \ _(one_l2_arp_entries_get, "bd ") \ diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 74597a6b..7aa3b419 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -908,7 +908,11 @@ static void add_l2_arp_bd (BVT (clib_bihash_kv) * kvp, void *arg) { u32 **ht = arg; - u32 bd = (u32) kvp->key[0]; + u32 version = (u32) kvp->key[0]; + if (IP6 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); hash_set (ht[0], bd, 0); } @@ -918,8 +922,31 @@ vnet_lisp_l2_arp_bds_get (void) lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); u32 *bds = 0; - gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid, - add_l2_arp_bd, &bds); + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_l2_arp_bd, &bds); + return bds; +} + +static void +add_ndp_bd (BVT (clib_bihash_kv) * kvp, void *arg) +{ + u32 **ht = arg; + u32 version = (u32) kvp->key[0]; + if (IP4 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); + hash_set (ht[0], bd, 0); +} + +u32 * +vnet_lisp_ndp_bds_get (void) +{ + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + u32 *bds = 0; + + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_ndp_bd, &bds); return bds; } @@ -927,15 +954,21 @@ typedef struct { void *vector; u32 bd; -} lisp_add_l2_arp_args_t; +} lisp_add_l2_arp_ndp_args_t; static void add_l2_arp_entry (BVT (clib_bihash_kv) * kvp, void *arg) { - lisp_add_l2_arp_args_t *a = arg; + lisp_add_l2_arp_ndp_args_t *a = arg; lisp_api_l2_arp_entry_t **vector = a->vector, e; - if ((u32) kvp->key[0] == a->bd) + u32 version = (u32) kvp->key[0]; + if (IP6 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); + + if (bd == a->bd) { mac_copy (e.mac, (void *) &kvp->value); e.ip4 = (u32) kvp->key[1]; @@ -948,13 +981,48 @@ vnet_lisp_l2_arp_entries_get_by_bd (u32 bd) { lisp_api_l2_arp_entry_t *entries = 0; lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); - lisp_add_l2_arp_args_t a; + lisp_add_l2_arp_ndp_args_t a; + + a.vector = &entries; + a.bd = bd; + + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_l2_arp_entry, &a); + return entries; +} + +static void +add_ndp_entry (BVT (clib_bihash_kv) * kvp, void *arg) +{ + lisp_add_l2_arp_ndp_args_t *a = arg; + lisp_api_ndp_entry_t **vector = a->vector, e; + + u32 version = (u32) kvp->key[0]; + if (IP4 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); + + if (bd == a->bd) + { + mac_copy (e.mac, (void *) &kvp->value); + clib_memcpy (e.ip6, &kvp->key[1], 16); + vec_add1 (vector[0], e); + } +} + +lisp_api_ndp_entry_t * +vnet_lisp_ndp_entries_get_by_bd (u32 bd) +{ + lisp_api_ndp_entry_t *entries = 0; + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + lisp_add_l2_arp_ndp_args_t a; a.vector = &entries; a.bd = bd; - gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid, - add_l2_arp_entry, &a); + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_ndp_entry, &a); return entries; } @@ -2236,7 +2304,9 @@ vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a) #define foreach_lisp_cp_lookup_error \ _(DROP, "drop") \ _(MAP_REQUESTS_SENT, "map-request sent") \ -_(ARP_REPLY_TX, "ARP replies sent") +_(ARP_REPLY_TX, "ARP replies sent") \ +_(NDP_NEIGHBOR_ADVERTISEMENT_TX, \ + "neighbor advertisement sent") static char *lisp_cp_lookup_error_strings[] = { #define _(sym,string) string, @@ -2255,7 +2325,7 @@ typedef enum typedef enum { LISP_CP_LOOKUP_NEXT_DROP, - LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX, + LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX, LISP_CP_LOOKUP_N_NEXT, } lisp_cp_lookup_next_t; @@ -3069,6 +3139,7 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, { ethernet_header_t *eh; u32 vni = 0; + icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt; memset (src, 0, sizeof (*src)); memset (dst, 0, sizeof (*dst)); @@ -3116,6 +3187,33 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, } else { + if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_IP6) + { + ip6_header_t *ip; + ip = (ip6_header_t *) (eh + 1); + + if (IP_PROTOCOL_ICMP6 == ip->protocol) + { + icmp6_neighbor_solicitation_or_advertisement_header_t *ndh; + ndh = ip6_next_header (ip); + if (ndh->icmp.type == ICMP6_neighbor_solicitation) + { + opt = (void *) (ndh + 1); + if ((opt->header.type != + ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address) + || (opt->header.n_data_u64s != 1)) + return; /* source link layer address option not present */ + + gid_address_type (dst) = GID_ADDR_NDP; + gid_address_ndp_bd (dst) = + lisp_get_bd_from_buffer_eth (b); + ip_address_set (&gid_address_arp_ndp_ip (dst), + &ndh->target_address, IP6); + return; + } + } + } + gid_address_type (src) = GID_ADDR_MAC; gid_address_type (dst) = GID_ADDR_MAC; mac_copy (&gid_address_mac (src), eh->src_address); @@ -3151,6 +3249,7 @@ lisp_cp_lookup_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, int overlay) { + icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt; u32 *from, *to_next, di, si; lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); u32 pkts_mapped = 0, next_index; @@ -3174,6 +3273,9 @@ lisp_cp_lookup_inline (vlib_main_t * vm, ethernet_arp_header_t *arp0; ethernet_header_t *eth0; vnet_hw_interface_t *hw_if0; + ethernet_header_t *eh0; + icmp6_neighbor_solicitation_or_advertisement_header_t *ndh; + ip6_header_t *ip0; pi0 = from[0]; from += 1; @@ -3190,41 +3292,70 @@ lisp_cp_lookup_inline (vlib_main_t * vm, if (gid_address_type (&dst) == GID_ADDR_ARP) { mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst); - if (GID_LOOKUP_MISS_L2 != mac0) - { - /* send ARP reply */ - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0; - - hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0); - - eth0 = vlib_buffer_get_current (b0); - arp0 = (ethernet_arp_header_t *) (((u8 *) eth0) - + sizeof (*eth0)); - arp0->opcode = - clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply); - arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0]; - clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, - (u8 *) & mac0, 6); - clib_memcpy (&arp0->ip4_over_ethernet[0].ip4, - &gid_address_arp_ip4 (&dst), 4); - - /* Hardware must be ethernet-like. */ - ASSERT (vec_len (hw_if0->hw_address) == 6); - - clib_memcpy (eth0->dst_address, eth0->src_address, 6); - clib_memcpy (eth0->src_address, hw_if0->hw_address, 6); - - b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX]; - next0 = LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX; - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, - n_left_to_next, pi0, - next0); - continue; - } - goto done; + if (GID_LOOKUP_MISS_L2 == mac0) + goto drop; + + /* send ARP reply */ + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0; + + hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0); + + eth0 = vlib_buffer_get_current (b0); + arp0 = (ethernet_arp_header_t *) (((u8 *) eth0) + + sizeof (*eth0)); + arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply); + arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0]; + clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, + (u8 *) & mac0, 6); + clib_memcpy (&arp0->ip4_over_ethernet[0].ip4, + &gid_address_arp_ip4 (&dst), 4); + + /* Hardware must be ethernet-like. */ + ASSERT (vec_len (hw_if0->hw_address) == 6); + + clib_memcpy (eth0->dst_address, eth0->src_address, 6); + clib_memcpy (eth0->src_address, hw_if0->hw_address, 6); + + b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX]; + next0 = LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX; + goto enqueue; + } + else if (gid_address_type (&dst) == GID_ADDR_NDP) + { + mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst); + if (GID_LOOKUP_MISS_L2 == mac0) + goto drop; + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0; + + eh0 = vlib_buffer_get_current (b0); + ip0 = (ip6_header_t *) (eh0 + 1); + ndh = ip6_next_header (ip0); + int bogus_length; + ip0->dst_address = ip0->src_address; + ip0->src_address = ndh->target_address; + ip0->hop_limit = 255; + opt = (void *) (ndh + 1); + opt->header.type = + ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address; + clib_memcpy (opt->ethernet_address, (u8 *) & mac0, 6); + ndh->icmp.type = ICMP6_neighbor_advertisement; + ndh->advertisement_flags = clib_host_to_net_u32 + (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED | + ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE); + ndh->icmp.checksum = 0; + ndh->icmp.checksum = + ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, + &bogus_length); + clib_memcpy (eh0->dst_address, eh0->src_address, 6); + clib_memcpy (eh0->src_address, (u8 *) & mac0, 6); + b0->error = + node->errors + [LISP_CP_LOOKUP_ERROR_NDP_NEIGHBOR_ADVERTISEMENT_TX]; + next0 = LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX; + goto enqueue; } /* if we have remote mapping for destination already in map-chache @@ -3267,8 +3398,10 @@ lisp_cp_lookup_inline (vlib_main_t * vm, pkts_mapped++; } - done: + drop: b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP]; + next0 = LISP_CP_LOOKUP_NEXT_DROP; + enqueue: if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0, @@ -3281,7 +3414,6 @@ lisp_cp_lookup_inline (vlib_main_t * vm, } gid_address_free (&dst); gid_address_free (&src); - next0 = LISP_CP_LOOKUP_NEXT_DROP; vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, pi0, next0); @@ -3339,7 +3471,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -3359,7 +3491,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip6_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -3379,7 +3511,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -3399,7 +3531,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_nsh_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ diff --git a/src/vnet/lisp-cp/control.h b/src/vnet/lisp-cp/control.h index 12bfcb51..d40f6f53 100644 --- a/src/vnet/lisp-cp/control.h +++ b/src/vnet/lisp-cp/control.h @@ -103,6 +103,12 @@ typedef struct u32 ip4; } lisp_api_l2_arp_entry_t; +typedef struct +{ + u8 mac[6]; + u8 ip6[16]; +} lisp_api_ndp_entry_t; + typedef enum { MR_MODE_DST_ONLY = 0, @@ -395,6 +401,8 @@ int vnet_lisp_map_register_set_ttl (u32 ttl); u32 vnet_lisp_map_register_get_ttl (void); int vnet_lisp_map_register_fallback_threshold_set (u32 value); u32 vnet_lisp_map_register_fallback_threshold_get (void); +u32 *vnet_lisp_ndp_bds_get (void); +lisp_api_ndp_entry_t *vnet_lisp_ndp_entries_get_by_bd (u32 bd); map_records_arg_t *parse_map_reply (vlib_buffer_t * b); diff --git a/src/vnet/lisp-cp/gid_dictionary.c b/src/vnet/lisp-cp/gid_dictionary.c index cf9a741a..c3b93301 100644 --- a/src/vnet/lisp-cp/gid_dictionary.c +++ b/src/vnet/lisp-cp/gid_dictionary.c @@ -139,12 +139,13 @@ gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid, } void -gid_dict_foreach_l2_arp_entry (gid_dictionary_t * db, void (*cb) - (BVT (clib_bihash_kv) * kvp, void *arg), - void *ht) +gid_dict_foreach_l2_arp_ndp_entry (gid_dictionary_t * db, void (*cb) + (BVT (clib_bihash_kv) * kvp, void *arg), + void *ht) { - gid_l2_arp_table_t *tab = &db->arp_table; - BV (clib_bihash_foreach_key_value_pair) (&tab->arp_lookup_table, cb, ht); + gid_l2_arp_ndp_table_t *tab = &db->arp_ndp_table; + BV (clib_bihash_foreach_key_value_pair) (&tab->arp_ndp_lookup_table, cb, + ht); } static void @@ -338,11 +339,19 @@ ip_sd_lookup (gid_dictionary_t * db, u32 vni, ip_prefix_t * dst, } static void -make_arp_key (BVT (clib_bihash_kv) * kv, u32 bd, ip4_address_t * addr) +make_arp_ndp_key (BVT (clib_bihash_kv) * kv, u32 bd, ip_address_t * addr) { - kv->key[0] = (u64) bd; - kv->key[1] = (u64) addr->as_u32; - kv->key[2] = (u64) 0; + kv->key[0] = ((u64) bd << 32) | (u32) ip_addr_version (addr); + if (ip_addr_version (addr) == IP4) + { + kv->key[1] = (u64) addr->ip.v4.as_u32; + kv->key[2] = (u64) 0; + } + else + { + kv->key[1] = (u64) addr->ip.v6.as_u64[0]; + kv->key[2] = (u64) addr->ip.v6.as_u64[1]; + } } static void @@ -354,13 +363,14 @@ make_nsh_key (BVT (clib_bihash_kv) * kv, u32 vni, u32 spi, u8 si) } static u64 -arp_lookup (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key) +arp_ndp_lookup (gid_l2_arp_ndp_table_t * db, u32 bd, ip_address_t * key) { int rv; BVT (clib_bihash_kv) kv, value; - make_arp_key (&kv, bd, key); - rv = BV (clib_bihash_search_inline_2) (&db->arp_lookup_table, &kv, &value); + make_arp_ndp_key (&kv, bd, key); + rv = BV (clib_bihash_search_inline_2) (&db->arp_ndp_lookup_table, &kv, + &value); if (rv == 0) return value.value; @@ -414,8 +424,9 @@ gid_dictionary_lookup (gid_dictionary_t * db, gid_address_t * key) } break; case GID_ADDR_ARP: - return arp_lookup (&db->arp_table, gid_address_arp_bd (key), - &gid_address_arp_ip4 (key)); + case GID_ADDR_NDP: + return arp_ndp_lookup (&db->arp_ndp_table, gid_address_arp_ndp_bd (key), + &gid_address_arp_ndp_ip (key)); case GID_ADDR_NSH: return nsh_lookup (&db->nsh_table, gid_address_vni (key), gid_address_nsh_spi (key), gid_address_nsh_si (key)); @@ -890,25 +901,27 @@ add_del_sd (gid_dictionary_t * db, u32 vni, source_dest_t * key, u32 value, } static u64 -add_del_arp (gid_l2_arp_table_t * db, u32 bd, ip4_address_t * key, u64 value, - u8 is_add) +add_del_arp_ndp (gid_l2_arp_ndp_table_t * db, u32 bd, ip_address_t * key, + u64 value, u8 is_add) { BVT (clib_bihash_kv) kv, result; u32 old_val = ~0; - make_arp_key (&kv, bd, key); - if (BV (clib_bihash_search) (&db->arp_lookup_table, &kv, &result) == 0) + make_arp_ndp_key (&kv, bd, key); + if (BV (clib_bihash_search) (&db->arp_ndp_lookup_table, &kv, &result) == 0) old_val = result.value; if (is_add) { kv.value = value; - BV (clib_bihash_add_del) (&db->arp_lookup_table, &kv, 1 /* is_add */ ); + BV (clib_bihash_add_del) (&db->arp_ndp_lookup_table, &kv, + 1 /* is_add */ ); db->count++; } else { - BV (clib_bihash_add_del) (&db->arp_lookup_table, &kv, 0 /* is_add */ ); + BV (clib_bihash_add_del) (&db->arp_ndp_lookup_table, &kv, + 0 /* is_add */ ); db->count--; } return old_val; @@ -955,8 +968,10 @@ gid_dictionary_add_del (gid_dictionary_t * db, gid_address_t * key, u64 value, return add_del_sd (db, gid_address_vni (key), &gid_address_sd (key), (u32) value, is_add); case GID_ADDR_ARP: - return add_del_arp (&db->arp_table, gid_address_arp_bd (key), - &gid_address_arp_ip4 (key), value, is_add); + case GID_ADDR_NDP: + return add_del_arp_ndp (&db->arp_ndp_table, + gid_address_arp_ndp_bd (key), + &gid_address_arp_ndp_ip (key), value, is_add); case GID_ADDR_NSH: return add_del_nsh (&db->nsh_table, gid_address_vni (key), gid_address_nsh_spi (key), gid_address_nsh_si (key), @@ -987,20 +1002,21 @@ mac_lookup_init (gid_mac_table_t * db) } static void -arp_lookup_init (gid_l2_arp_table_t * db) +arp_ndp_lookup_init (gid_l2_arp_ndp_table_t * db) { - if (db->arp_lookup_table_nbuckets == 0) - db->arp_lookup_table_nbuckets = ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS; + if (db->arp_ndp_lookup_table_nbuckets == 0) + db->arp_ndp_lookup_table_nbuckets = + ARP_NDP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS; - db->arp_lookup_table_nbuckets = - 1 << max_log2 (db->arp_lookup_table_nbuckets); + db->arp_ndp_lookup_table_nbuckets = + 1 << max_log2 (db->arp_ndp_lookup_table_nbuckets); - if (db->arp_lookup_table_size == 0) - db->arp_lookup_table_size = ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE; + if (db->arp_ndp_lookup_table_size == 0) + db->arp_ndp_lookup_table_size = ARP_NDP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE; - BV (clib_bihash_init) (&db->arp_lookup_table, "arp lookup table", - db->arp_lookup_table_nbuckets, - db->arp_lookup_table_size); + BV (clib_bihash_init) (&db->arp_ndp_lookup_table, "arp ndp lookup table", + db->arp_ndp_lookup_table_nbuckets, + db->arp_ndp_lookup_table_size); } static void @@ -1026,7 +1042,7 @@ gid_dictionary_init (gid_dictionary_t * db) ip4_lookup_init (&db->dst_ip4_table); ip6_lookup_init (&db->dst_ip6_table); mac_lookup_init (&db->sd_mac_table); - arp_lookup_init (&db->arp_table); + arp_ndp_lookup_init (&db->arp_ndp_table); nsh_lookup_init (&db->nsh_table); } diff --git a/src/vnet/lisp-cp/gid_dictionary.h b/src/vnet/lisp-cp/gid_dictionary.h index 51806bd6..3f8500e5 100644 --- a/src/vnet/lisp-cp/gid_dictionary.h +++ b/src/vnet/lisp-cp/gid_dictionary.h @@ -36,9 +36,9 @@ #define MAC_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) #define MAC_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) -/* Default size of the ARP hash table */ -#define ARP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) -#define ARP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) +/* Default size of the ARP/NDP hash table */ +#define ARP_NDP_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) +#define ARP_NDP_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20) /* Default size of the NSH hash table */ #define NSH_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) @@ -100,16 +100,16 @@ typedef struct gid_nsh_table typedef struct { - BVT (clib_bihash) arp_lookup_table; - u32 arp_lookup_table_nbuckets; - uword arp_lookup_table_size; + BVT (clib_bihash) arp_ndp_lookup_table; + u32 arp_ndp_lookup_table_nbuckets; + uword arp_ndp_lookup_table_size; u64 count; -} gid_l2_arp_table_t; +} gid_l2_arp_ndp_table_t; typedef struct { - /** L2 ARP table */ - gid_l2_arp_table_t arp_table; + /** L2 ARP/NDP table */ + gid_l2_arp_ndp_table_t arp_ndp_table; /** NSH lookup table */ gid_nsh_table_t nsh_table; @@ -146,9 +146,9 @@ gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid, foreach_subprefix_match_cb_t cb, void *arg); void -gid_dict_foreach_l2_arp_entry (gid_dictionary_t * db, void (*cb) - (BVT (clib_bihash_kv) * kvp, void *arg), - void *ht); +gid_dict_foreach_l2_arp_ndp_entry (gid_dictionary_t * db, void (*cb) + (BVT (clib_bihash_kv) * kvp, void *arg), + void *ht); #endif /* VNET_LISP_GPE_GID_DICTIONARY_H_ */ diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c index 622f39af..05f046fa 100644 --- a/src/vnet/lisp-cp/lisp_types.c +++ b/src/vnet/lisp-cp/lisp_types.c @@ -279,8 +279,9 @@ format_gid_address (u8 * s, va_list * args) return format (s, "[%d] %U", gid_address_vni (a), format_mac_address, &gid_address_mac (a)); case GID_ADDR_ARP: - return format (s, "[%d, %U]", gid_address_arp_bd (a), - format_ip4_address, &gid_address_arp_ip4 (a)); + case GID_ADDR_NDP: + return format (s, "[%d, %U]", gid_address_arp_ndp_bd (a), + format_ip_address, &gid_address_arp_ndp_ip (a)); case GID_ADDR_NSH: return format (s, "%U", format_nsh_address, &gid_address_nsh (a)); diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h index b17110f6..4a919e79 100644 --- a/src/vnet/lisp-cp/lisp_types.h +++ b/src/vnet/lisp-cp/lisp_types.h @@ -91,6 +91,7 @@ typedef enum GID_ADDR_SRC_DST, GID_ADDR_NSH, GID_ADDR_ARP, + GID_ADDR_NDP, GID_ADDR_NO_ADDRESS, GID_ADDR_TYPES } gid_address_type_t; @@ -172,12 +173,15 @@ typedef struct typedef struct { - ip4_address_t addr; + ip_address_t addr; u32 bd; -} lcaf_arp_t; +} lcaf_arp_ndp_t; -#define lcaf_arp_ip4(_a) (_a)->addr -#define lcaf_arp_bd(_a) (_a)->bd +#define lcaf_arp_ndp_ip(_a) (_a)->addr +#define lcaf_arp_ndp_ip_ver(_a) ip_addr_version(&lcaf_arp_ndp_ip(_a)) +#define lcaf_arp_ndp_ip4(_a) ip_addr_v4(&lcaf_arp_ndp_ip(_a)) +#define lcaf_arp_ndp_ip6(_a) ip_addr_v6(&lcaf_arp_ndp_ip(_a)) +#define lcaf_arp_ndp_bd(_a) (_a)->bd typedef struct { @@ -185,7 +189,7 @@ typedef struct union { source_dest_t sd; - lcaf_arp_t arp; + lcaf_arp_ndp_t arp_ndp; vni_t uni; }; u8 type; @@ -204,7 +208,7 @@ typedef struct _gid_address_t lcaf_t lcaf; u8 mac[6]; source_dest_t sd; - lcaf_arp_t arp; + lcaf_arp_ndp_t arp_ndp; nsh_t nsh; }; u8 type; @@ -275,9 +279,13 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); #define gid_address_sd_dst(_a) sd_dst(&gid_address_sd(_a)) #define gid_address_sd_src_type(_a) sd_src_type(&gid_address_sd(_a)) #define gid_address_sd_dst_type(_a) sd_dst_type(&gid_address_sd(_a)) -#define gid_address_arp(_a) (_a)->arp -#define gid_address_arp_ip4(_a) lcaf_arp_ip4(&gid_address_arp (_a)) -#define gid_address_arp_bd(_a) lcaf_arp_bd(&gid_address_arp (_a)) +#define gid_address_arp_ndp(_a) (_a)->arp_ndp +#define gid_address_arp_ndp_bd(_a) lcaf_arp_ndp_bd(&gid_address_arp_ndp(_a)) +#define gid_address_arp_ndp_ip(_a) lcaf_arp_ndp_ip(&gid_address_arp_ndp(_a)) +#define gid_address_arp_ip4(_a) lcaf_arp_ndp_ip4(&gid_address_arp_ndp(_a)) +#define gid_address_ndp_ip6(_a) lcaf_arp_ndp_ip6(&gid_address_arp_ndp(_a)) +#define gid_address_ndp_bd gid_address_arp_ndp_bd +#define gid_address_arp_bd gid_address_arp_ndp_bd /* 'sub'address functions */ #define foreach_gid_address_type_fcns \ diff --git a/src/vnet/lisp-cp/one_api.c b/src/vnet/lisp-cp/one_api.c index 7c8ba63f..96b3d2c0 100644 --- a/src/vnet/lisp-cp/one_api.c +++ b/src/vnet/lisp-cp/one_api.c @@ -130,7 +130,9 @@ _(ONE_STATS_FLUSH, one_stats_flush) \ _(ONE_L2_ARP_BD_GET, one_l2_arp_bd_get) \ _(ONE_L2_ARP_ENTRIES_GET, one_l2_arp_entries_get) \ _(ONE_ADD_DEL_L2_ARP_ENTRY, one_add_del_l2_arp_entry) \ - +_(ONE_ADD_DEL_NDP_ENTRY, one_add_del_ndp_entry) \ +_(ONE_NDP_BD_GET, one_ndp_bd_get) \ +_(ONE_NDP_ENTRIES_GET, one_ndp_entries_get) \ static locator_t * unformat_one_locs (vl_api_one_remote_locator_t * rmt_locs, u32 rloc_num) @@ -1563,13 +1565,55 @@ static void gid_address_arp_bd (arp) = clib_net_to_host_u32 (mp->bd); /* vpp keeps ip4 addresses in network byte order */ - clib_memcpy (&gid_address_arp_ip4 (arp), &mp->ip4, 4); + ip_address_set (&gid_address_arp_ndp_ip (arp), &mp->ip4, IP4); rv = vnet_lisp_add_del_l2_arp_entry (arp, mp->mac, mp->is_add); REPLY_MACRO (VL_API_ONE_ADD_DEL_L2_ARP_ENTRY_REPLY); } +static void +vl_api_one_add_del_ndp_entry_t_handler (vl_api_one_add_del_ndp_entry_t * mp) +{ + vl_api_one_add_del_ndp_entry_reply_t *rmp; + int rv = 0; + gid_address_t _g, *g = &_g; + memset (g, 0, sizeof (*g)); + + gid_address_type (g) = GID_ADDR_NDP; + gid_address_ndp_bd (g) = clib_net_to_host_u32 (mp->bd); + ip_address_set (&gid_address_arp_ndp_ip (g), mp->ip6, IP6); + + rv = vnet_lisp_add_del_l2_arp_entry (g, mp->mac, mp->is_add); + + REPLY_MACRO (VL_API_ONE_ADD_DEL_NDP_ENTRY_REPLY); +} + +static void +vl_api_one_ndp_bd_get_t_handler (vl_api_one_ndp_bd_get_t * mp) +{ + vl_api_one_ndp_bd_get_reply_t *rmp; + int rv = 0; + u32 i = 0; + hash_pair_t *p; + + u32 *bds = vnet_lisp_ndp_bds_get (); + u32 size = hash_elts (bds) * sizeof (u32); + + /* *INDENT-OFF* */ + REPLY_MACRO4 (VL_API_ONE_NDP_BD_GET_REPLY, size, + { + rmp->count = clib_host_to_net_u32 (hash_elts (bds)); + hash_foreach_pair (p, bds, + ({ + rmp->bridge_domains[i++] = clib_host_to_net_u32 (p->key); + })); + }); + /* *INDENT-ON* */ + + hash_free (bds); +} + static void vl_api_one_l2_arp_bd_get_t_handler (vl_api_one_l2_arp_bd_get_t * mp) { @@ -1653,6 +1697,35 @@ static void /* *INDENT-ON* */ } +static void +vl_api_one_ndp_entries_get_t_handler (vl_api_one_ndp_entries_get_t * mp) +{ + vl_api_one_ndp_entries_get_reply_t *rmp = 0; + lisp_api_ndp_entry_t *entries = 0, *e; + u32 i = 0; + int rv = 0; + + u32 bd = clib_net_to_host_u32 (mp->bd); + + entries = vnet_lisp_ndp_entries_get_by_bd (bd); + u32 size = vec_len (entries) * sizeof (vl_api_one_ndp_entry_t); + + /* *INDENT-OFF* */ + REPLY_MACRO4 (VL_API_ONE_NDP_ENTRIES_GET_REPLY, size, + { + rmp->count = clib_host_to_net_u32 (vec_len (entries)); + vec_foreach (e, entries) + { + mac_copy (rmp->entries[i].mac, e->mac); + clib_memcpy (rmp->entries[i].ip6, e->ip6, 16); + i++; + } + }); + /* *INDENT-ON* */ + + vec_free (entries); +} + /* * one_api_hookup * Add vpe's API message handlers to the table. diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c index 3e0c4c0a..1e52c9af 100644 --- a/src/vnet/lisp-cp/one_cli.c +++ b/src/vnet/lisp-cp/one_cli.c @@ -376,6 +376,42 @@ VLIB_CLI_COMMAND (one_show_l2_arp_entries_command) = { }; /* *INDENT-ON* */ +static clib_error_t * +lisp_show_ndp_entries_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + u32 *ht = vnet_lisp_ndp_bds_get (); + lisp_api_ndp_entry_t *entries, *e; + hash_pair_t *p; + + /* *INDENT-OFF* */ + hash_foreach_pair (p, ht, + ({ + entries = vnet_lisp_ndp_entries_get_by_bd (p->key); + vlib_cli_output (vm, "Table: %d", p->key); + + vec_foreach (e, entries) + { + vlib_cli_output (vm, "\t%U -> %U", format_ip6_address, &e->ip6, + format_mac_address, e->mac); + } + vec_free (entries); + })); + /* *INDENT-ON* */ + + hash_free (ht); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (one_show_ndp_entries_command) = { + .path = "show one ndp entries", + .short_help = "Show ONE NDP entries", + .function = lisp_show_ndp_entries_command_fn, +}; +/* *INDENT-ON* */ + /** * Handler for add/del remote mapping CLI. * -- cgit 1.2.3-korg