From: Eyal Bari Date: Mon, 4 Jun 2018 09:25:05 +0000 (+0300) Subject: vxlan:use bihash_24_8 for ipv6 lookup X-Git-Tag: v18.07-rc1~49 X-Git-Url: https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commitdiff_plain;h=0fa56788f71d570ce585027e2acdf19e82e6d433 vxlan:use bihash_24_8 for ipv6 lookup * added the fib index into the key * conform coding style for vxlan.h * added "show vxlan tunnel raw" command to dump bihash Change-Id: Icc96e41abb648e96de5b4605b035f68f9e20f8a9 Signed-off-by: Eyal Bari --- diff --git a/src/vnet/vxlan/decap.c b/src/vnet/vxlan/decap.c index abd7bad0ed8..79d63613ec1 100644 --- a/src/vnet/vxlan/decap.c +++ b/src/vnet/vxlan/decap.c @@ -49,17 +49,17 @@ static u8 * format_vxlan_rx_trace (u8 * s, va_list * args) } always_inline u32 -validate_vxlan_fib (vlib_buffer_t *b, vxlan_tunnel_t *t, u32 is_ip4) +buf_fib_index (vlib_buffer_t *b, u32 is_ip4) { - u32 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX]; + u32 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX]; + if (sw_if_index != (u32) ~ 0) + return sw_if_index; u32 * fib_index_by_sw_if_index = is_ip4 ? ip4_main.fib_index_by_sw_if_index : ip6_main.fib_index_by_sw_if_index; - u32 tx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX]; - u32 fib_index = (tx_sw_if_index == (u32) ~ 0) ? - vec_elt (fib_index_by_sw_if_index, sw_if_index) : tx_sw_if_index; + sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX]; - return (fib_index == t->encap_fib_index); + return vec_elt (fib_index_by_sw_if_index, sw_if_index); } typedef struct @@ -68,15 +68,9 @@ typedef struct u32 tunnel_index; }last_tunnel_cache4; -typedef struct -{ - vxlan6_tunnel_key_t key6; - u32 tunnel_index; -}last_tunnel_cache6; - always_inline vxlan_tunnel_t * vxlan4_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache4 * cache, - ip4_header_t * ip4_0, vxlan_header_t * vxlan0, + u32 fib_index, ip4_header_t * ip4_0, vxlan_header_t * vxlan0, vxlan_tunnel_t ** stats_t0) { /* Make sure VXLAN tunnel exist according to packet SIP and VNI */ @@ -96,6 +90,9 @@ vxlan4_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache4 * cache, } vxlan_tunnel_t * t0 = pool_elt_at_index (vxm->tunnels, cache->tunnel_index); + if (PREDICT_FALSE (fib_index != t0->encap_fib_index)) + return 0; + /* Validate VXLAN tunnel SIP against packet DIP */ if (PREDICT_TRUE (ip4_0->dst_address.as_u32 == t0->src.ip4.as_u32)) *stats_t0 = t0; @@ -116,27 +113,32 @@ vxlan4_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache4 * cache, return t0; } +typedef vxlan6_tunnel_key_t last_tunnel_cache6; + always_inline vxlan_tunnel_t * vxlan6_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache6 * cache, - ip6_header_t * ip6_0, vxlan_header_t * vxlan0, + u32 fib_index, ip6_header_t * ip6_0, vxlan_header_t * vxlan0, vxlan_tunnel_t ** stats_t0) { /* Make sure VXLAN tunnel exist according to packet SIP and VNI */ - vxlan6_tunnel_key_t key6_0 = { - .src = ip6_0->src_address, - .vni = vxlan0->vni_reserved, + + vxlan6_tunnel_key_t key6 = { + .key = { + [0] = ip6_0->src_address.as_u64[0], + [1] = ip6_0->src_address.as_u64[1], + [2] = (((u64) fib_index) << 32) | vxlan0->vni_reserved + } }; - if (PREDICT_FALSE (memcmp(&key6_0, &cache->key6, sizeof key6_0) != 0)) + if (PREDICT_FALSE (BV (clib_bihash_key_compare) (key6.key, cache->key) == 0)) { - uword * p = hash_get_mem (vxm->vxlan6_tunnel_by_key, &key6_0); - if (PREDICT_FALSE (p == NULL)) + int rv = BV (clib_bihash_search_inline) (&vxm->vxlan6_tunnel_by_key, &key6); + if (PREDICT_FALSE (rv != 0)) return 0; - cache->key6 = key6_0; - cache->tunnel_index = p[0]; + *cache = key6; } - vxlan_tunnel_t * t0 = pool_elt_at_index (vxm->tunnels, cache->tunnel_index); + vxlan_tunnel_t * t0 = pool_elt_at_index (vxm->tunnels, cache->value); /* Validate VXLAN tunnel SIP against packet DIP */ if (PREDICT_TRUE (ip6_address_is_equal (&ip6_0->dst_address, &t0->src.ip6))) @@ -147,12 +149,14 @@ vxlan6_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache6 * cache, if (PREDICT_TRUE (!ip6_address_is_multicast (&ip6_0->dst_address))) return 0; - key6_0.src = ip6_0->dst_address; /* Make sure mcast VXLAN tunnel exist by packet DIP and VNI */ - uword * p = hash_get_mem (vxm->vxlan6_tunnel_by_key, &key6_0); - if (PREDICT_FALSE (p == NULL)) + key6.key[0] = ip6_0->dst_address.as_u64[0]; + key6.key[1] = ip6_0->dst_address.as_u64[1]; + int rv = BV (clib_bihash_search_inline) (&vxm->vxlan6_tunnel_by_key, &key6); + if (PREDICT_FALSE (rv != 0)) return 0; - *stats_t0 = pool_elt_at_index (vxm->tunnels, p[0]); + + *stats_t0 = pool_elt_at_index (vxm->tunnels, key6.value); } return t0; @@ -170,14 +174,14 @@ vxlan_input (vlib_main_t * vm, vlib_combined_counter_main_t * rx_counter = im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX; vlib_combined_counter_main_t * drop_counter = im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_DROP; last_tunnel_cache4 last4 = { .tunnel_index = ~0 }; - last_tunnel_cache6 last6 = { .tunnel_index = ~0 }; + last_tunnel_cache6 last6; u32 pkts_decapsulated = 0; u32 thread_index = vlib_get_thread_index(); if (is_ip4) last4.key4.as_u64 = ~0; else - memset (&last6.key6, 0xff, sizeof last6.key6); + memset (&last6, 0xff, sizeof last6); u32 next_index = node->cached_next_index; @@ -236,17 +240,20 @@ vxlan_input (vlib_main_t * vm, vlib_buffer_advance (b0, sizeof *vxlan0); vlib_buffer_advance (b1, sizeof *vxlan1); + u32 fi0 = buf_fib_index(b0, is_ip4); + u32 fi1 = buf_fib_index(b1, is_ip4); + vxlan_tunnel_t * t0, * stats_t0; vxlan_tunnel_t * t1, * stats_t1; if (is_ip4) { - t0 = vxlan4_find_tunnel (vxm, &last4, ip4_0, vxlan0, &stats_t0); - t1 = vxlan4_find_tunnel (vxm, &last4, ip4_1, vxlan1, &stats_t1); + t0 = vxlan4_find_tunnel (vxm, &last4, fi0, ip4_0, vxlan0, &stats_t0); + t1 = vxlan4_find_tunnel (vxm, &last4, fi1, ip4_1, vxlan1, &stats_t1); } else { - t0 = vxlan6_find_tunnel (vxm, &last6, ip6_0, vxlan0, &stats_t0); - t1 = vxlan6_find_tunnel (vxm, &last6, ip6_1, vxlan1, &stats_t1); + t0 = vxlan6_find_tunnel (vxm, &last6, fi0, ip6_0, vxlan0, &stats_t0); + t1 = vxlan6_find_tunnel (vxm, &last6, fi1, ip6_1, vxlan1, &stats_t1); } u32 len0 = vlib_buffer_length_in_chain (vm, b0); @@ -255,8 +262,7 @@ vxlan_input (vlib_main_t * vm, u32 next0, next1; u8 error0 = 0, error1 = 0; /* Validate VXLAN tunnel encap-fib index agaist packet */ - if (PREDICT_FALSE (t0 == 0 || validate_vxlan_fib (b0, t0, is_ip4) == 0 || - vxlan0->flags != VXLAN_FLAGS_I)) + if (PREDICT_FALSE (t0 == 0 || vxlan0->flags != VXLAN_FLAGS_I)) { next0 = VXLAN_INPUT_NEXT_DROP; @@ -286,8 +292,7 @@ vxlan_input (vlib_main_t * vm, } /* Validate VXLAN tunnel encap-fib index agaist packet */ - if (PREDICT_FALSE (t1 == 0 || validate_vxlan_fib (b1, t1, is_ip4) == 0 || - vxlan1->flags != VXLAN_FLAGS_I)) + if (PREDICT_FALSE (t1 == 0 || vxlan1->flags != VXLAN_FLAGS_I)) { next1 = VXLAN_INPUT_NEXT_DROP; @@ -362,19 +367,20 @@ vxlan_input (vlib_main_t * vm, /* pop (ip, udp, vxlan) */ vlib_buffer_advance (b0, sizeof(*vxlan0)); + u32 fi0 = buf_fib_index(b0, is_ip4); + vxlan_tunnel_t * t0, * stats_t0; if (is_ip4) - t0 = vxlan4_find_tunnel (vxm, &last4, ip4_0, vxlan0, &stats_t0); + t0 = vxlan4_find_tunnel (vxm, &last4, fi0, ip4_0, vxlan0, &stats_t0); else - t0 = vxlan6_find_tunnel (vxm, &last6, ip6_0, vxlan0, &stats_t0); + t0 = vxlan6_find_tunnel (vxm, &last6, fi0, ip6_0, vxlan0, &stats_t0); uword len0 = vlib_buffer_length_in_chain (vm, b0); u32 next0; u8 error0 = 0; /* Validate VXLAN tunnel encap-fib index agaist packet */ - if (PREDICT_FALSE (t0 == 0 || validate_vxlan_fib (b0, t0, is_ip4) == 0 || - vxlan0->flags != VXLAN_FLAGS_I)) + if (PREDICT_FALSE (t0 == 0 || vxlan0->flags != VXLAN_FLAGS_I)) { next0 = VXLAN_INPUT_NEXT_DROP; diff --git a/src/vnet/vxlan/vxlan.c b/src/vnet/vxlan/vxlan.c index 6b0b6c43840..d5938616912 100644 --- a/src/vnet/vxlan/vxlan.c +++ b/src/vnet/vxlan/vxlan.c @@ -383,9 +383,16 @@ int vnet_vxlan_add_del_tunnel } else { - key6.src = a->dst.ip6; - key6.vni = clib_host_to_net_u32 (a->vni << 8); - p = hash_get_mem (vxm->vxlan6_tunnel_by_key, &key6); + key6.key[0] = a->dst.ip6.as_u64[0]; + key6.key[1] = a->dst.ip6.as_u64[1]; + key6.key[2] = (((u64) a->encap_fib_index) << 32) + | clib_host_to_net_u32 (a->vni << 8); + int rv = + BV (clib_bihash_search_inline) (&vxm->vxlan6_tunnel_by_key, &key6); + if (PREDICT_FALSE (rv != 0)) + p = 0; + else + p = &key6.value; } if (a->is_add) @@ -433,7 +440,15 @@ int vnet_vxlan_add_del_tunnel /* copy the key */ if (is_ip6) - hash_set_mem_alloc (&vxm->vxlan6_tunnel_by_key, &key6, dev_instance); + { + key6.value = (u64) dev_instance; + if (BV (clib_bihash_add_del) (&vxm->vxlan6_tunnel_by_key, + &key6, 1 /*add */ )) + { + pool_put (vxm->tunnels, t); + return VNET_API_ERROR_INVALID_REGISTRATION; + } + } else hash_set (vxm->vxlan4_tunnel_by_key, key4.as_u64, dev_instance); @@ -574,7 +589,8 @@ int vnet_vxlan_add_del_tunnel if (!is_ip6) hash_unset (vxm->vxlan4_tunnel_by_key, key4.as_u64); else - hash_unset_mem_free (&vxm->vxlan6_tunnel_by_key, &key6); + BV (clib_bihash_add_del) (&vxm->vxlan6_tunnel_by_key, &key6, + 0 /*del */ ); if (!ip46_address_is_multicast (&t->dst)) { @@ -655,7 +671,7 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, u32 decap_next_index = VXLAN_INPUT_NEXT_L2_INPUT; u32 vni = 0; u32 table_id; - clib_error_t *error = NULL; + clib_error_t *parse_error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -693,13 +709,6 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, { encap_fib_index = fib_table_find (fib_ip_proto (ipv6_set), table_id); - if (encap_fib_index == ~0) - { - error = - clib_error_return (0, "nonexistent encap-vrf-id %d", - table_id); - break; - } } else if (unformat (line_input, "decap-next %U", unformat_decap_next, &decap_next_index, ipv4_set)) @@ -708,16 +717,19 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, ; else { - error = clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + parse_error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); break; } } unformat_free (line_input); - if (error) - return error; + if (parse_error) + return parse_error; + + if (encap_fib_index == ~0) + return clib_error_return (0, "nonexistent encap-vrf-id %d", table_id); if (src_set == 0) return clib_error_return (0, "tunnel src address not specified"); @@ -783,7 +795,7 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, (0, "vnet_vxlan_add_del_tunnel returned %d", rv); } - return error; + return 0; } /*? @@ -825,8 +837,29 @@ show_vxlan_tunnel_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { + unformat_input_t _line_input, *line_input = &_line_input; vxlan_main_t *vxm = &vxlan_main; vxlan_tunnel_t *t; + int raw = 0; + clib_error_t *parse_error = NULL; + + /* 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, "raw")) + raw = 1; + else + parse_error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + } + + unformat_free (line_input); + + if (parse_error) + return parse_error; if (pool_elts (vxm->tunnels) == 0) vlib_cli_output (vm, "No vxlan tunnels configured..."); @@ -838,6 +871,11 @@ show_vxlan_tunnel_command_fn (vlib_main_t * vm, })); /* *INDENT-ON* */ + if (raw) + vlib_cli_output (vm, "Raw IPv6 Hash Table:\n%U\n", + BV (format_bihash), &vxm->vxlan6_tunnel_by_key, + 1 /* verbose */ ); + return 0; } @@ -853,7 +891,7 @@ show_vxlan_tunnel_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_vxlan_tunnel_command, static) = { .path = "show vxlan tunnel", - .short_help = "show vxlan tunnel", + .short_help = "show vxlan tunnel [raw]", .function = show_vxlan_tunnel_command_fn, }; /* *INDENT-ON* */ @@ -1145,6 +1183,9 @@ VLIB_CLI_COMMAND (vxlan_offload_command, static) = { }; /* *INDENT-ON* */ +#define VXLAN_HASH_NUM_BUCKETS (2 * 1024) +#define VXLAN_HASH_MEMORY_SIZE (1 << 20) + clib_error_t * vxlan_init (vlib_main_t * vm) { @@ -1157,9 +1198,8 @@ vxlan_init (vlib_main_t * vm) &vxm->flow_id_start); /* initialize the ip6 hash */ - vxm->vxlan6_tunnel_by_key = hash_create_mem (0, - sizeof (vxlan6_tunnel_key_t), - sizeof (uword)); + BV (clib_bihash_init) (&vxm->vxlan6_tunnel_by_key, "vxlan6", + VXLAN_HASH_NUM_BUCKETS, VXLAN_HASH_MEMORY_SIZE); vxm->vtep6 = hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword)); vxm->mcast_shared = hash_create_mem (0, sizeof (ip46_address_t), diff --git a/src/vnet/vxlan/vxlan.h b/src/vnet/vxlan/vxlan.h index 0f226aa3e72..21b7650f454 100644 --- a/src/vnet/vxlan/vxlan.h +++ b/src/vnet/vxlan/vxlan.h @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -30,47 +31,47 @@ #include #include +/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { - ip4_header_t ip4; /* 20 bytes */ - udp_header_t udp; /* 8 bytes */ - vxlan_header_t vxlan; /* 8 bytes */ + ip4_header_t ip4; /* 20 bytes */ + udp_header_t udp; /* 8 bytes */ + vxlan_header_t vxlan; /* 8 bytes */ }) ip4_vxlan_header_t; typedef CLIB_PACKED (struct { - ip6_header_t ip6; /* 40 bytes */ - udp_header_t udp; /* 8 bytes */ - vxlan_header_t vxlan; /* 8 bytes */ + ip6_header_t ip6; /* 40 bytes */ + udp_header_t udp; /* 8 bytes */ + vxlan_header_t vxlan; /* 8 bytes */ }) ip6_vxlan_header_t; -typedef CLIB_PACKED(struct { - /* - * Key fields: ip src and vxlan vni on incoming VXLAN packet - * all fields in NET byte order - */ - union { - struct { +typedef CLIB_PACKED (union { + /* + * Key fields: remote ip, vni on incoming VXLAN packet + * all fields in NET byte order + */ + struct + { u32 src; - u32 vni; /* shifted left 8 bits */ + u32 vni; /* shifted left 8 bits */ }; - u64 as_u64; - }; + u64 as_u64; }) vxlan4_tunnel_key_t; -typedef CLIB_PACKED(struct { - /* - * Key fields: ip src and vxlan vni on incoming VXLAN packet - * all fields in NET byte order - */ - ip6_address_t src; - u32 vni; /* shifted left 8 bits */ -}) vxlan6_tunnel_key_t; - -typedef struct { +/* +* Key fields: remote ip, vni and fib index on incoming VXLAN packet +* ip, vni fields in NET byte order +* fib index field in host byte order +*/ +typedef BVT (clib_bihash_kv) vxlan6_tunnel_key_t; +/* *INDENT-ON* */ + +typedef struct +{ /* Required for pool_get_aligned */ - CLIB_CACHE_LINE_ALIGN_MARK(cacheline0); + CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); /* FIB DPO for IP forwarding of VXLAN encap packet */ - dpo_id_t next_dpo; + dpo_id_t next_dpo; /* vxlan VNI in HOST byte order */ u32 vni; @@ -112,53 +113,56 @@ typedef struct { */ u32 sibling_index; - u32 flow_index; /* infra flow index */ - u32 dev_instance; /* Real device instance in tunnel vector */ - u32 user_instance; /* Instance name being shown to user */ + u32 flow_index; /* infra flow index */ + u32 dev_instance; /* Real device instance in tunnel vector */ + u32 user_instance; /* Instance name being shown to user */ - vnet_declare_rewrite (VLIB_BUFFER_PRE_DATA_SIZE); + vnet_declare_rewrite (VLIB_BUFFER_PRE_DATA_SIZE); } vxlan_tunnel_t; #define foreach_vxlan_input_next \ _(DROP, "error-drop") \ _(L2_INPUT, "l2-input") -typedef enum { +typedef enum +{ #define _(s,n) VXLAN_INPUT_NEXT_##s, foreach_vxlan_input_next #undef _ - VXLAN_INPUT_N_NEXT, + VXLAN_INPUT_N_NEXT, } vxlan_input_next_t; -typedef enum { +typedef enum +{ #define vxlan_error(n,s) VXLAN_ERROR_##n, #include #undef vxlan_error VXLAN_N_ERROR, } vxlan_input_error_t; -typedef struct { +typedef struct +{ /* vector of encap tunnel instances */ - vxlan_tunnel_t * tunnels; + vxlan_tunnel_t *tunnels; /* lookup tunnel by key */ - uword * vxlan4_tunnel_by_key; /* keyed on ipv4.dst + vni */ - uword * vxlan6_tunnel_by_key; /* keyed on ipv6.dst + vni */ + uword *vxlan4_tunnel_by_key; /* keyed on ipv4.dst + vni */ + BVT (clib_bihash) vxlan6_tunnel_by_key; /* keyed on ipv6.dst + fib + vni */ /* local VTEP IPs ref count used by vxlan-bypass node to check if received VXLAN packet DIP matches any local VTEP address */ - uword * vtep4; /* local ip4 VTEPs keyed on their ip4 addr */ - uword * vtep6; /* local ip6 VTEPs keyed on their ip6 addr */ + uword *vtep4; /* local ip4 VTEPs keyed on their ip4 addr */ + uword *vtep6; /* local ip6 VTEPs keyed on their ip6 addr */ /* mcast shared info */ - uword * mcast_shared; /* keyed on mcast ip46 addr */ + uword *mcast_shared; /* keyed on mcast ip46 addr */ /* Mapping from sw_if_index to tunnel index */ - u32 * tunnel_index_by_sw_if_index; + u32 *tunnel_index_by_sw_if_index; /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; /* Record used instances */ uword *instance_used; @@ -173,9 +177,10 @@ extern vlib_node_registration_t vxlan4_encap_node; extern vlib_node_registration_t vxlan6_encap_node; extern vlib_node_registration_t vxlan4_flow_input_node; -u8 * format_vxlan_encap_trace (u8 * s, va_list * args); +u8 *format_vxlan_encap_trace (u8 * s, va_list * args); -typedef struct { +typedef struct +{ u8 is_add; /* we normally use is_ip4, but since this adds to the @@ -189,19 +194,19 @@ typedef struct { u32 vni; } vnet_vxlan_add_del_tunnel_args_t; -int vnet_vxlan_add_del_tunnel -(vnet_vxlan_add_del_tunnel_args_t *a, u32 * sw_if_indexp); +int vnet_vxlan_add_del_tunnel + (vnet_vxlan_add_del_tunnel_args_t * a, u32 * sw_if_indexp); -void vnet_int_vxlan_bypass_mode -(u32 sw_if_index, u8 is_ip6, u8 is_enable); +void vnet_int_vxlan_bypass_mode (u32 sw_if_index, u8 is_ip6, u8 is_enable); -int vnet_vxlan_add_del_rx_flow -(u32 hw_if_index, u32 t_imdex, int is_add); +int vnet_vxlan_add_del_rx_flow (u32 hw_if_index, u32 t_imdex, int is_add); u32 vnet_vxlan_get_tunnel_index (u32 sw_if_index); #endif /* included_vnet_vxlan_h */ /* + * fd.io coding-style-patch-verification: ON + * * Local Variables: * eval: (c-set-style "gnu") * End: