diff options
Diffstat (limited to 'src/vnet/ip')
-rw-r--r-- | src/vnet/ip/ip.api | 53 | ||||
-rw-r--r-- | src/vnet/ip/ip4.h | 24 | ||||
-rw-r--r-- | src/vnet/ip/ip4_forward.c | 498 | ||||
-rw-r--r-- | src/vnet/ip/ip4_input.c | 4 | ||||
-rw-r--r-- | src/vnet/ip/ip6.h | 27 | ||||
-rw-r--r-- | src/vnet/ip/ip6_forward.c | 83 | ||||
-rw-r--r-- | src/vnet/ip/ip6_input.c | 43 | ||||
-rw-r--r-- | src/vnet/ip/ip6_neighbor.c | 134 | ||||
-rw-r--r-- | src/vnet/ip/ip_api.c | 210 | ||||
-rw-r--r-- | src/vnet/ip/lookup.c | 171 | ||||
-rw-r--r-- | src/vnet/ip/lookup.h | 82 |
11 files changed, 840 insertions, 489 deletions
diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api index 5371696c339..65f6e7a79ed 100644 --- a/src/vnet/ip/ip.api +++ b/src/vnet/ip/ip.api @@ -395,6 +395,41 @@ define ip_add_del_route_reply i32 retval; }; +/** \brief Add / del route request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - software index of the new vlan's parent interface + @param vrf_id - fib table /vrf associated with the route + + FIXME +*/ +define ip_mroute_add_del +{ + u32 client_index; + u32 context; + u32 next_hop_sw_if_index; + u32 table_id; + u32 entry_flags; + u32 itf_flags; + u16 grp_address_length; + u8 create_vrf_if_needed; + u8 is_add; + u8 is_ipv6; + u8 is_local; + u8 grp_address[16]; + u8 src_address[16]; +}; + +/** \brief Reply for add / del mroute request + @param context - returned sender context, to match reply w/ request + @param retval - return code +*/ +define ip_mroute_add_del_reply +{ + u32 context; + i32 retval; +}; + define ip_address_details { u32 client_index; @@ -424,6 +459,24 @@ define ip_dump u8 is_ipv6; }; +define mfib_signal_dump +{ + u32 client_index; + u32 context; +}; + +define mfib_signal_details +{ + u32 client_index; + u32 context; + u32 sw_if_index; + u32 table_id; + u16 grp_address_len; + u8 grp_address[16]; + u8 src_address[16]; + u16 ip_packet_len; + u8 ip_packet_data[256]; +}; /* * Local Variables: diff --git a/src/vnet/ip/ip4.h b/src/vnet/ip/ip4.h index cc33dff468f..b184fbaef42 100644 --- a/src/vnet/ip/ip4.h +++ b/src/vnet/ip/ip4.h @@ -68,6 +68,18 @@ typedef struct ip4_fib_t } ip4_fib_t; +typedef struct ip4_mfib_t +{ + /* Hash table for each prefix length mapping. */ + uword *fib_entry_by_dst_address[65]; + + /* Table ID (hash key) for this FIB. */ + u32 table_id; + + /* Index into FIB vector. */ + u32 index; +} ip4_mfib_t; + struct ip4_main_t; typedef void (ip4_add_del_interface_address_function_t) @@ -99,11 +111,17 @@ typedef struct ip4_main_t /** Vector of FIBs. */ struct fib_table_t_ *fibs; + /** Vector of MFIBs. */ + struct mfib_table_t_ *mfibs; + u32 fib_masks[33]; /** Table index indexed by software interface. */ u32 *fib_index_by_sw_if_index; + /** Table index indexed by software interface. */ + u32 *mfib_index_by_sw_if_index; + /* IP4 enabled count by software interface */ u8 *ip_enabled_by_sw_if_index; @@ -111,6 +129,10 @@ typedef struct ip4_main_t ID space is not necessarily dense; index space is dense. */ uword *fib_index_by_table_id; + /** Hash table mapping table id to multicast fib index. + ID space is not necessarily dense; index space is dense. */ + uword *mfib_index_by_table_id; + /** Functions to call when interface address changes. */ ip4_add_del_interface_address_callback_t * add_del_interface_address_callbacks; @@ -140,7 +162,9 @@ extern ip4_main_t ip4_main; /** Global ip4 input node. Errors get attached to ip4 input node. */ extern vlib_node_registration_t ip4_input_node; extern vlib_node_registration_t ip4_lookup_node; +extern vlib_node_registration_t ip4_local_node; extern vlib_node_registration_t ip4_rewrite_node; +extern vlib_node_registration_t ip4_rewrite_mcast_node; extern vlib_node_registration_t ip4_rewrite_local_node; extern vlib_node_registration_t ip4_arp_node; extern vlib_node_registration_t ip4_glean_node; diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index 87b345bd3f5..8081b34b3dc 100644 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -50,6 +50,7 @@ #include <vnet/fib/ip4_fib.h> #include <vnet/dpo/load_balance.h> #include <vnet/dpo/classify_dpo.h> +#include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */ /** * @file @@ -714,16 +715,17 @@ ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index, ip_interface_address_t *ia = 0; ip4_address_t *result = 0; - foreach_ip_interface_address (lm, ia, sw_if_index, - 1 /* honor unnumbered */ , - ( - { - ip4_address_t * a = - ip_interface_address_get_address (lm, ia); - result = a; - break; - } - )); + /* *INDENT-OFF* */ + foreach_ip_interface_address + (lm, ia, sw_if_index, + 1 /* honor unnumbered */ , + ({ + ip4_address_t * a = + ip_interface_address_get_address (lm, ia); + result = a; + break; + })); + /* *INDENT-OFF* */ if (result_ia) *result_ia = result ? ia : 0; return result; @@ -748,9 +750,19 @@ ip4_add_interface_routes (u32 sw_if_index, { fib_node_index_t fei; - fei = fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), FIB_PROTOCOL_IP4, NULL, /* No next-hop address */ - sw_if_index, ~0, // invalid FIB index - 1, NULL, // no out-label stack + fei = fib_table_entry_update_one_path (fib_index, &pfx, + FIB_SOURCE_INTERFACE, + (FIB_ENTRY_FLAG_CONNECTED | + FIB_ENTRY_FLAG_ATTACHED), + FIB_PROTOCOL_IP4, + /* No next-hop address */ + NULL, + sw_if_index, + // invalid FIB index + ~0, + 1, + // no out-label stack + NULL, FIB_ROUTE_PATH_FLAG_NONE); a->neighbor_probe_adj_index = fib_entry_get_adj (fei); } @@ -778,8 +790,16 @@ ip4_add_interface_routes (u32 sw_if_index, } } - fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), FIB_PROTOCOL_IP4, &pfx.fp_addr, sw_if_index, ~0, // invalid FIB index - 1, NULL, // no out-label stack + fib_table_entry_update_one_path (fib_index, &pfx, + FIB_SOURCE_INTERFACE, + (FIB_ENTRY_FLAG_CONNECTED | + FIB_ENTRY_FLAG_LOCAL), + FIB_PROTOCOL_IP4, + &pfx.fp_addr, + sw_if_index, + // invalid FIB index + ~0, + 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); } @@ -827,9 +847,10 @@ ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable) vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index, !is_enable, 0, 0); - vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", sw_if_index, - !is_enable, 0, 0); + vnet_feature_enable_disable ("ip4-multicast", + "ip4-mfib-forward-lookup", + sw_if_index, is_enable, 0, 0); } static clib_error_t * @@ -855,36 +876,37 @@ ip4_add_del_interface_address_internal (vlib_main_t * vm, * subnets on interfaces. Easy fix - disallow overlapping subnets, like * most routers do. */ + /* *INDENT-OFF* */ if (!is_del) { /* When adding an address check that it does not conflict with an existing address. */ ip_interface_address_t *ia; - foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index, - 0 /* honor unnumbered */ , - ( - { - ip4_address_t * x = - ip_interface_address_get_address - (&im->lookup_main, ia); - if (ip4_destination_matches_route - (im, address, x, ia->address_length) - || - ip4_destination_matches_route (im, - x, - address, - address_length)) - return - clib_error_create - ("failed to add %U which conflicts with %U for interface %U", - format_ip4_address_and_length, address, - address_length, - format_ip4_address_and_length, x, - ia->address_length, - format_vnet_sw_if_index_name, vnm, - sw_if_index);} - )); + foreach_ip_interface_address + (&im->lookup_main, ia, sw_if_index, + 0 /* honor unnumbered */ , + ({ + ip4_address_t * x = + ip_interface_address_get_address + (&im->lookup_main, ia); + if (ip4_destination_matches_route + (im, address, x, ia->address_length) || + ip4_destination_matches_route (im, + x, + address, + address_length)) + return + clib_error_create + ("failed to add %U which conflicts with %U for interface %U", + format_ip4_address_and_length, address, + address_length, + format_ip4_address_and_length, x, + ia->address_length, + format_vnet_sw_if_index_name, vnm, + sw_if_index); + })); } + /* *INDENT-ON* */ elts_before = pool_elts (lm->if_address_pool); @@ -918,9 +940,10 @@ done: } clib_error_t * -ip4_add_del_interface_address (vlib_main_t * vm, u32 sw_if_index, - ip4_address_t * address, u32 address_length, - u32 is_del) +ip4_add_del_interface_address (vlib_main_t * vm, + u32 sw_if_index, + ip4_address_t * address, + u32 address_length, u32 is_del) { return ip4_add_del_interface_address_internal (vm, sw_if_index, address, address_length, is_del); @@ -1027,13 +1050,13 @@ VNET_FEATURE_INIT (ip4_vpath_mc, static) = { .arc_name = "ip4-multicast", .node_name = "vpath-input-ip4", - .runs_before = VNET_FEATURES ("ip4-lookup-multicast"), + .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"), }; VNET_FEATURE_INIT (ip4_lookup_mc, static) = { .arc_name = "ip4-multicast", - .node_name = "ip4-lookup-multicast", + .node_name = "ip4-mfib-forward-lookup", .runs_before = VNET_FEATURES ("ip4-drop"), }; @@ -1083,6 +1106,7 @@ ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add) /* Fill in lookup tables with default table (0). */ vec_validate (im->fib_index_by_sw_if_index, sw_if_index); + vec_validate (im->mfib_index_by_sw_if_index, sw_if_index); vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index, is_add, 0, 0); @@ -1123,6 +1147,7 @@ ip4_lookup_init (vlib_main_t * vm) /* Create FIB with index 0 and table id of 0. */ fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0); + mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0); { pg_node_t *pn; @@ -1341,27 +1366,35 @@ ip4_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT); } +/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip4_drop_node, static) = { - .function = ip4_drop,.name = "ip4-drop",.vector_size = - sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes = - 1,.next_nodes = - { - [0] = "error-drop",} -,}; + .function = ip4_drop,. + name = "ip4-drop", + .vector_size = sizeof (u32), + .format_trace = format_ip4_forward_next_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "error-drop", + }, +}; VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop); VLIB_REGISTER_NODE (ip4_punt_node, static) = { - .function = ip4_punt,.name = "ip4-punt",.vector_size = - sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes = - 1,.next_nodes = - { - [0] = "error-punt",} -,}; + .function = ip4_punt, + .name = "ip4-punt", + .vector_size = sizeof (u32), + .format_trace = format_ip4_forward_next_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "error-punt", + }, +}; VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt); +/* *INDENT-ON */ /* Compute TCP/UDP/ICMP4 checksum in software. */ u16 @@ -1500,13 +1533,15 @@ ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]); - fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ? - fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX]; + fib_index0 = + (vnet_buffer (p0)->sw_if_index[VLIB_TX] == + (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX]; fib_index1 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p1)->sw_if_index[VLIB_RX]); - fib_index1 = (vnet_buffer (p1)->sw_if_index[VLIB_TX] == (u32) ~ 0) ? - fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX]; + fib_index1 = + (vnet_buffer (p1)->sw_if_index[VLIB_TX] == + (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX]; mtrie0 = &ip4_fib_get (fib_index0)->mtrie; mtrie1 = &ip4_fib_get (fib_index1)->mtrie; @@ -1726,8 +1761,9 @@ ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]); - fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ? - fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX]; + fib_index0 = + (vnet_buffer (p0)->sw_if_index[VLIB_TX] == + (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX]; mtrie0 = &ip4_fib_get (fib_index0)->mtrie; @@ -1838,10 +1874,11 @@ ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) return frame->n_vectors; } -VLIB_REGISTER_NODE (ip4_local_node, static) = +VLIB_REGISTER_NODE (ip4_local_node) = { .function = ip4_local,.name = "ip4-local",.vector_size = - sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes = + sizeof (u32),.format_trace = + format_ip4_forward_next_trace,.n_next_nodes = IP_LOCAL_N_NEXT,.next_nodes = { [IP_LOCAL_NEXT_DROP] = "error-drop", @@ -2022,8 +2059,8 @@ ip4_arp_inline (vlib_main_t * vm, * Can happen if the control-plane is programming tables * with traffic flowing; at least that's today's lame excuse. */ - if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN) || - (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP)) + if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN) + || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP)) { p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ]; } @@ -2196,15 +2233,17 @@ ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index) { vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE; return clib_error_return - (0, "no matching interface address for destination %U (interface %U)", - format_ip4_address, dst, - format_vnet_sw_if_index_name, vnm, sw_if_index); + (0, + "no matching interface address for destination %U (interface %U)", + format_ip4_address, dst, format_vnet_sw_if_index_name, vnm, + sw_if_index); } adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index); h = - vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, + vlib_packet_template_get_packet (vm, + &im->ip4_arp_request_packet_template, &bi); hi = vnet_get_sup_hw_interface (vnm, sw_if_index); @@ -2243,7 +2282,7 @@ typedef enum always_inline uword ip4_rewrite_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame, int is_midchain) + vlib_frame_t * frame, int is_midchain, int is_mcast) { ip_lookup_main_t *lm = &ip4_main.lookup_main; u32 *from = vlib_frame_vector_args (frame); @@ -2457,6 +2496,14 @@ ip4_rewrite_inline (vlib_main_t * vm, adj0->sub_type.midchain.fixup_func (vm, adj0, p0); adj1->sub_type.midchain.fixup_func (vm, adj1, p1); } + if (is_mcast) + { + /* + * copy bytes from the IP address into the MAC rewrite + */ + vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1); + vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1, 1); + } vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, n_left_to_next, @@ -2530,6 +2577,13 @@ ip4_rewrite_inline (vlib_main_t * vm, /* Guess we are only writing on simple Ethernet header. */ vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t)); + if (is_mcast) + { + /* + * copy bytes from the IP address into the MAC rewrite + */ + vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1); + } /* Update packet buffer attributes/set output interface. */ rw_len0 = adj0[0].rewrite_header.data_bytes; @@ -2624,36 +2678,58 @@ static uword ip4_rewrite (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip4_rewrite_inline (vm, node, frame, 0); + return ip4_rewrite_inline (vm, node, frame, 0, 0); } static uword ip4_midchain (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip4_rewrite_inline (vm, node, frame, 1); + return ip4_rewrite_inline (vm, node, frame, 1, 0); } - -VLIB_REGISTER_NODE (ip4_rewrite_node) = +static uword +ip4_rewrite_mcast (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) { - .function = ip4_rewrite,.name = "ip4-rewrite",.vector_size = - sizeof (u32),.format_trace = format_ip4_rewrite_trace,.n_next_nodes = - 2,.next_nodes = - { - [IP4_REWRITE_NEXT_DROP] = "error-drop", - [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",} -,}; + return ip4_rewrite_inline (vm, node, frame, 0, 1); +} -VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite); +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (ip4_rewrite_node) = { + .function = ip4_rewrite, + .name = "ip4-rewrite", + .vector_size = sizeof (u32), + + .format_trace = format_ip4_rewrite_trace, + + .n_next_nodes = 2, + .next_nodes = { + [IP4_REWRITE_NEXT_DROP] = "error-drop", + [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error", + }, +}; +VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite) -VLIB_REGISTER_NODE (ip4_midchain_node) = -{ -.function = ip4_midchain,.name = "ip4-midchain",.vector_size = - sizeof (u32),.format_trace = format_ip4_forward_next_trace,.sibling_of = - "ip4-rewrite",}; +VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = { + .function = ip4_rewrite_mcast, + .name = "ip4-rewrite-mcast", + .vector_size = sizeof (u32), + .format_trace = format_ip4_rewrite_trace, + .sibling_of = "ip4-rewrite", +}; +VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast) + +VLIB_REGISTER_NODE (ip4_midchain_node) = { + .function = ip4_midchain, + .name = "ip4-midchain", + .vector_size = sizeof (u32), + .format_trace = format_ip4_forward_next_trace, + .sibling_of = "ip4-rewrite", +}; VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain); +/* *INDENT-ON */ static clib_error_t * add_del_interface_table (vlib_main_t * vm, @@ -2695,6 +2771,11 @@ add_del_interface_table (vlib_main_t * vm, // vec_validate (im->fib_index_by_sw_if_index, sw_if_index); im->fib_index_by_sw_if_index[sw_if_index] = fib_index; + + fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, + table_id); + vec_validate (im->mfib_index_by_sw_if_index, sw_if_index); + im->mfib_index_by_sw_if_index[sw_if_index] = fib_index; } done: @@ -2730,243 +2811,6 @@ VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = }; /* *INDENT-ON* */ - -static uword -ip4_lookup_multicast (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - ip4_main_t *im = &ip4_main; - vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters; - u32 n_left_from, n_left_to_next, *from, *to_next; - ip_lookup_next_t next; - u32 cpu_index = os_get_cpu_number (); - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next = node->cached_next_index; - - while (n_left_from > 0) - { - vlib_get_next_frame (vm, node, next, to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - vlib_buffer_t *p0, *p1; - u32 pi0, pi1, lb_index0, lb_index1, wrong_next; - ip_lookup_next_t next0, next1; - ip4_header_t *ip0, *ip1; - u32 fib_index0, fib_index1; - const dpo_id_t *dpo0, *dpo1; - const load_balance_t *lb0, *lb1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t *p2, *p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD); - CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD); - } - - pi0 = to_next[0] = from[0]; - pi1 = to_next[1] = from[1]; - - p0 = vlib_get_buffer (vm, pi0); - p1 = vlib_get_buffer (vm, pi1); - - ip0 = vlib_buffer_get_current (p0); - ip1 = vlib_buffer_get_current (p1); - - fib_index0 = - vec_elt (im->fib_index_by_sw_if_index, - vnet_buffer (p0)->sw_if_index[VLIB_RX]); - fib_index1 = - vec_elt (im->fib_index_by_sw_if_index, - vnet_buffer (p1)->sw_if_index[VLIB_RX]); - fib_index0 = - (vnet_buffer (p0)->sw_if_index[VLIB_TX] == - (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX]; - fib_index1 = - (vnet_buffer (p1)->sw_if_index[VLIB_TX] == - (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX]; - - lb_index0 = ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), - &ip0->dst_address); - lb_index1 = ip4_fib_table_lookup_lb (ip4_fib_get (fib_index1), - &ip1->dst_address); - - lb0 = load_balance_get (lb_index0); - lb1 = load_balance_get (lb_index1); - - ASSERT (lb0->lb_n_buckets > 0); - ASSERT (is_pow2 (lb0->lb_n_buckets)); - ASSERT (lb1->lb_n_buckets > 0); - ASSERT (is_pow2 (lb1->lb_n_buckets)); - - vnet_buffer (p0)->ip.flow_hash = ip4_compute_flow_hash - (ip0, lb0->lb_hash_config); - - vnet_buffer (p1)->ip.flow_hash = ip4_compute_flow_hash - (ip1, lb1->lb_hash_config); - - dpo0 = load_balance_get_bucket_i (lb0, - (vnet_buffer (p0)->ip.flow_hash & - (lb0->lb_n_buckets_minus_1))); - dpo1 = load_balance_get_bucket_i (lb1, - (vnet_buffer (p1)->ip.flow_hash & - (lb1->lb_n_buckets_minus_1))); - - next0 = dpo0->dpoi_next_node; - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; - next1 = dpo1->dpoi_next_node; - vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index; - - if (1) /* $$$$$$ HACK FIXME */ - vlib_increment_combined_counter - (cm, cpu_index, lb_index0, 1, - vlib_buffer_length_in_chain (vm, p0)); - if (1) /* $$$$$$ HACK FIXME */ - vlib_increment_combined_counter - (cm, cpu_index, lb_index1, 1, - vlib_buffer_length_in_chain (vm, p1)); - - from += 2; - to_next += 2; - n_left_to_next -= 2; - n_left_from -= 2; - - wrong_next = (next0 != next) + 2 * (next1 != next); - if (PREDICT_FALSE (wrong_next != 0)) - { - switch (wrong_next) - { - case 1: - /* A B A */ - to_next[-2] = pi1; - to_next -= 1; - n_left_to_next += 1; - vlib_set_next_frame_buffer (vm, node, next0, pi0); - break; - - case 2: - /* A A B */ - to_next -= 1; - n_left_to_next += 1; - vlib_set_next_frame_buffer (vm, node, next1, pi1); - break; - - case 3: - /* A B C */ - to_next -= 2; - n_left_to_next += 2; - vlib_set_next_frame_buffer (vm, node, next0, pi0); - vlib_set_next_frame_buffer (vm, node, next1, pi1); - if (next0 == next1) - { - /* A B B */ - vlib_put_next_frame (vm, node, next, n_left_to_next); - next = next1; - vlib_get_next_frame (vm, node, next, to_next, - n_left_to_next); - } - } - } - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - vlib_buffer_t *p0; - ip4_header_t *ip0; - u32 pi0, lb_index0; - ip_lookup_next_t next0; - u32 fib_index0; - const dpo_id_t *dpo0; - const load_balance_t *lb0; - - pi0 = from[0]; - to_next[0] = pi0; - - p0 = vlib_get_buffer (vm, pi0); - - ip0 = vlib_buffer_get_current (p0); - - fib_index0 = vec_elt (im->fib_index_by_sw_if_index, - vnet_buffer (p0)->sw_if_index[VLIB_RX]); - fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ? - fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX]; - - lb_index0 = ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), - &ip0->dst_address); - - lb0 = load_balance_get (lb_index0); - - ASSERT (lb0->lb_n_buckets > 0); - ASSERT (is_pow2 (lb0->lb_n_buckets)); - - vnet_buffer (p0)->ip.flow_hash = ip4_compute_flow_hash - (ip0, lb0->lb_hash_config); - - dpo0 = load_balance_get_bucket_i (lb0, - (vnet_buffer (p0)->ip.flow_hash & - (lb0->lb_n_buckets_minus_1))); - - next0 = dpo0->dpoi_next_node; - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; - - if (1) /* $$$$$$ HACK FIXME */ - vlib_increment_combined_counter - (cm, cpu_index, lb_index0, 1, - vlib_buffer_length_in_chain (vm, p0)); - - from += 1; - to_next += 1; - n_left_to_next -= 1; - n_left_from -= 1; - - if (PREDICT_FALSE (next0 != next)) - { - n_left_to_next += 1; - vlib_put_next_frame (vm, node, next, n_left_to_next); - next = next0; - vlib_get_next_frame (vm, node, next, to_next, n_left_to_next); - to_next[0] = pi0; - to_next += 1; - n_left_to_next -= 1; - } - } - - vlib_put_next_frame (vm, node, next, n_left_to_next); - } - - if (node->flags & VLIB_NODE_FLAG_TRACE) - ip4_forward_next_trace (vm, node, frame, VLIB_TX); - - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (ip4_lookup_multicast_node, static) = -{ -.function = ip4_lookup_multicast,.name = - "ip4-lookup-multicast",.vector_size = sizeof (u32),.sibling_of = - "ip4-lookup",.format_trace = format_ip4_lookup_trace,.n_next_nodes = 0,}; - -VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node, - ip4_lookup_multicast); - -VLIB_REGISTER_NODE (ip4_multicast_node, static) = -{ - .function = ip4_drop,.name = "ip4-multicast",.vector_size = - sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes = - 1,.next_nodes = - { - [0] = "error-drop",} -,}; - int ip4_lookup_validate (ip4_address_t * a, u32 fib_index0) { diff --git a/src/vnet/ip/ip4_input.c b/src/vnet/ip/ip4_input.c index 1cf5e0b8517..ba200a9fe13 100644 --- a/src/vnet/ip/ip4_input.c +++ b/src/vnet/ip/ip4_input.c @@ -426,7 +426,7 @@ VLIB_REGISTER_NODE (ip4_input_node) = { [IP4_INPUT_NEXT_DROP] = "error-drop", [IP4_INPUT_NEXT_PUNT] = "error-punt", [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup", - [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-lookup-multicast", + [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup", [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", }, @@ -448,7 +448,7 @@ VLIB_REGISTER_NODE (ip4_input_no_checksum_node,static) = { [IP4_INPUT_NEXT_DROP] = "error-drop", [IP4_INPUT_NEXT_PUNT] = "error-punt", [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup", - [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-lookup-multicast", + [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup", [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", }, diff --git a/src/vnet/ip/ip6.h b/src/vnet/ip/ip6.h index f493db017ec..6fecd42dc61 100644 --- a/src/vnet/ip/ip6.h +++ b/src/vnet/ip/ip6.h @@ -49,6 +49,7 @@ #include <stdbool.h> #include <vppinfra/bihash_24_8.h> #include <vppinfra/bihash_template.h> +#include <vnet/util/radix.h> /* * Default size of the ip6 fib hash table @@ -75,6 +76,21 @@ typedef struct flow_hash_config_t flow_hash_config; } ip6_fib_t; +typedef struct ip6_mfib_t +{ + /* Table ID (hash key) for this FIB. */ + u32 table_id; + + /* Index into FIB vector. */ + u32 index; + + /* + * Pointer to the top of a radix tree. + * This cannot be realloc'd, hence it cannot be inlined with this table + */ + struct radix_node_head *rhead; +} ip6_mfib_t; + struct ip6_main_t; typedef void (ip6_add_del_interface_address_function_t) @@ -137,12 +153,18 @@ typedef struct ip6_main_t /* Pool of FIBs. */ struct fib_table_t_ *fibs; + /** Vector of MFIBs. */ + struct mfib_table_t_ *mfibs; + /* Network byte orders subnet mask for each prefix length */ ip6_address_t fib_masks[129]; /* Table index indexed by software interface. */ u32 *fib_index_by_sw_if_index; + /** Table index indexed by software interface. */ + u32 *mfib_index_by_sw_if_index; + /* IP6 enabled count by software interface */ u8 *ip_enabled_by_sw_if_index; @@ -150,6 +172,10 @@ typedef struct ip6_main_t ID space is not necessarily dense; index space is dense. */ uword *fib_index_by_table_id; + /** Hash table mapping table id to multicast fib index. + ID space is not necessarily dense; index space is dense. */ + uword *mfib_index_by_table_id; + /* Hash table mapping interface rewrite adjacency index by sw if index. */ uword *interface_route_adj_index_by_sw_if_index; @@ -185,6 +211,7 @@ extern ip6_main_t ip6_main; /* Global ip6 input node. Errors get attached to ip6 input node. */ extern vlib_node_registration_t ip6_input_node; extern vlib_node_registration_t ip6_rewrite_node; +extern vlib_node_registration_t ip6_rewrite_mcast_node; extern vlib_node_registration_t ip6_rewrite_local_node; extern vlib_node_registration_t ip6_discover_neighbor_node; extern vlib_node_registration_t ip6_glean_node; diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index 232f72833fd..ac47b3ad1fb 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -42,8 +42,8 @@ #include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */ #include <vnet/srp/srp.h> /* for srp_hw_interface_class */ #include <vppinfra/cache.h> -#include <vnet/fib/fib_table.h> #include <vnet/fib/ip6_fib.h> +#include <vnet/mfib/ip6_mfib.h> #include <vnet/dpo/load_balance.h> #include <vnet/dpo/classify_dpo.h> @@ -411,11 +411,14 @@ ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable) return; } + if (sw_if_index != 0) + ip6_mfib_interface_enable_disable (sw_if_index, is_enable); + vnet_feature_enable_disable ("ip6-unicast", "ip6-lookup", sw_if_index, is_enable, 0, 0); - vnet_feature_enable_disable ("ip6-multicast", "ip6-lookup", sw_if_index, - is_enable, 0, 0); + vnet_feature_enable_disable ("ip6-multicast", "ip6-mfib-forward-lookup", + sw_if_index, is_enable, 0, 0); } @@ -457,6 +460,8 @@ ip6_add_del_interface_address (vlib_main_t * vm, ip6_address_fib_t ip6_af, *addr_fib = 0; vec_validate (im->fib_index_by_sw_if_index, sw_if_index); + vec_validate (im->mfib_index_by_sw_if_index, sw_if_index); + ip6_addr_fib_init (&ip6_af, address, vec_elt (im->fib_index_by_sw_if_index, sw_if_index)); vec_add1 (addr_fib, ip6_af); @@ -611,12 +616,12 @@ VNET_FEATURE_ARC_INIT (ip6_multicast, static) = VNET_FEATURE_INIT (ip6_vpath_mc, static) = { .arc_name = "ip6-multicast", .node_name = "vpath-input-ip6", - .runs_before = VNET_FEATURES ("ip6-lookup"), + .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"), }; VNET_FEATURE_INIT (ip6_mc_lookup, static) = { .arc_name = "ip6-multicast", - .node_name = "ip6-lookup", + .node_name = "ip6-mfib-forward-lookup", .runs_before = VNET_FEATURES ("ip6-drop"), }; @@ -1122,22 +1127,6 @@ VLIB_REGISTER_NODE (ip6_punt_node, static) = VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt); -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (ip6_multicast_node, static) = -{ - .function = ip6_drop, - .name = "ip6-multicast", - .vector_size = sizeof (u32), - .format_trace = format_ip6_forward_next_trace, - .n_next_nodes = 1, - .next_nodes = - { - [0] = "error-drop", - }, -}; - -/* *INDENT-ON* */ - /* Compute TCP/UDP/ICMP6 checksum in software. */ u16 ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0, @@ -1977,7 +1966,7 @@ typedef enum always_inline uword ip6_rewrite_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame, int is_midchain) + vlib_frame_t * frame, int is_midchain, int is_mcast) { ip_lookup_main_t *lm = &ip6_main.lookup_main; u32 *from = vlib_frame_vector_args (frame); @@ -2165,6 +2154,14 @@ ip6_rewrite_inline (vlib_main_t * vm, adj0->sub_type.midchain.fixup_func (vm, adj0, p0); adj1->sub_type.midchain.fixup_func (vm, adj1, p1); } + if (is_mcast) + { + /* + * copy bytes from the IP address into the MAC rewrite + */ + vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 0); + vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1, 0); + } vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, n_left_to_next, @@ -2265,6 +2262,10 @@ ip6_rewrite_inline (vlib_main_t * vm, { adj0->sub_type.midchain.fixup_func (vm, adj0, p0); } + if (is_mcast) + { + vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 0); + } p0->error = error_node->errors[error0]; @@ -2292,16 +2293,21 @@ static uword ip6_rewrite (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip6_rewrite_inline (vm, node, frame, - /* midchain */ 0); + return ip6_rewrite_inline (vm, node, frame, 0, 0); +} + +static uword +ip6_rewrite_mcast (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return ip6_rewrite_inline (vm, node, frame, 0, 1); } static uword ip6_midchain (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip6_rewrite_inline (vm, node, frame, - /* midchain */ 1); + return ip6_rewrite_inline (vm, node, frame, 1, 0); } /* *INDENT-OFF* */ @@ -2335,10 +2341,22 @@ VLIB_REGISTER_NODE (ip6_rewrite_node) = VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite); +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) = +{ + .function = ip6_rewrite_mcast, + .name = "ip6-rewrite-mcast", + .vector_size = sizeof (u32), + .format_trace = format_ip6_rewrite_trace, + .sibling_of = "ip6-rewrite", +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast); + /* * Hop-by-Hop handling */ - ip6_hop_by_hop_main_t ip6_hop_by_hop_main; #define foreach_ip6_hop_by_hop_error \ @@ -2346,13 +2364,15 @@ _(PROCESSED, "pkts with ip6 hop-by-hop options") \ _(FORMAT, "incorrectly formatted hop-by-hop options") \ _(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options") +/* *INDENT-OFF* */ typedef enum { #define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym, foreach_ip6_hop_by_hop_error #undef _ - IP6_HOP_BY_HOP_N_ERROR, + IP6_HOP_BY_HOP_N_ERROR, } ip6_hop_by_hop_error_t; +/* *INDENT-ON* */ /* * Primary h-b-h handler trace support @@ -2878,6 +2898,7 @@ ip6_lookup_init (vlib_main_t * vm) /* Create FIB with index 0 and table id of 0. */ fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0); + mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0); { pg_node_t *pn; @@ -2955,6 +2976,12 @@ add_del_ip6_interface_table (vlib_main_t * vm, vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index); ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index; + + fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, + table_id); + + vec_validate (ip6_main.mfib_index_by_sw_if_index, sw_if_index); + ip6_main.mfib_index_by_sw_if_index[sw_if_index] = fib_index; } diff --git a/src/vnet/ip/ip6_input.c b/src/vnet/ip/ip6_input.c index bbc2cebaa39..20306088611 100644 --- a/src/vnet/ip/ip6_input.c +++ b/src/vnet/ip/ip6_input.c @@ -64,6 +64,7 @@ typedef enum { IP6_INPUT_NEXT_DROP, IP6_INPUT_NEXT_LOOKUP, + IP6_INPUT_NEXT_LOOKUP_MULTICAST, IP6_INPUT_NEXT_ICMP_ERROR, IP6_INPUT_N_NEXT, } ip6_input_next_t; @@ -142,12 +143,27 @@ ip6_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX]; sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX]; - arc0 = - ip6_address_is_multicast (&ip0->dst_address) ? - lm->mcast_feature_arc_index : lm->ucast_feature_arc_index; - arc1 = - ip6_address_is_multicast (&ip1->dst_address) ? - lm->mcast_feature_arc_index : lm->ucast_feature_arc_index; + if (PREDICT_FALSE (ip6_address_is_multicast (&ip0->dst_address))) + { + arc0 = lm->mcast_feature_arc_index; + next0 = IP6_INPUT_NEXT_LOOKUP_MULTICAST; + } + else + { + arc0 = lm->ucast_feature_arc_index; + next0 = IP6_INPUT_NEXT_LOOKUP; + } + + if (PREDICT_FALSE (ip6_address_is_multicast (&ip1->dst_address))) + { + arc1 = lm->mcast_feature_arc_index; + next1 = IP6_INPUT_NEXT_LOOKUP_MULTICAST; + } + else + { + arc1 = lm->ucast_feature_arc_index; + next1 = IP6_INPUT_NEXT_LOOKUP; + } vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0; vnet_buffer (p1)->ip.adj_index[VLIB_RX] = ~0; @@ -240,9 +256,17 @@ ip6_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) ip0 = vlib_buffer_get_current (p0); sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX]; - arc0 = - ip6_address_is_multicast (&ip0->dst_address) ? - lm->mcast_feature_arc_index : lm->ucast_feature_arc_index; + if (PREDICT_FALSE (ip6_address_is_multicast (&ip0->dst_address))) + { + arc0 = lm->mcast_feature_arc_index; + next0 = IP6_INPUT_NEXT_LOOKUP_MULTICAST; + } + else + { + arc0 = lm->ucast_feature_arc_index; + next0 = IP6_INPUT_NEXT_LOOKUP; + } + vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0; vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0); @@ -313,6 +337,7 @@ VLIB_REGISTER_NODE (ip6_input_node) = { [IP6_INPUT_NEXT_DROP] = "error-drop", [IP6_INPUT_NEXT_LOOKUP] = "ip6-lookup", [IP6_INPUT_NEXT_ICMP_ERROR] = "ip6-icmp-error", + [IP6_INPUT_NEXT_LOOKUP_MULTICAST] = "ip6-mfib-forward-lookup", }, .format_buffer = format_ip6_header, diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c index 46c0e3168c0..46d04769a96 100644 --- a/src/vnet/ip/ip6_neighbor.c +++ b/src/vnet/ip/ip6_neighbor.c @@ -21,6 +21,7 @@ #include <vppinfra/mhash.h> #include <vppinfra/md5.h> #include <vnet/adj/adj.h> +#include <vnet/adj/adj_mcast.h> #include <vnet/fib/fib_table.h> #include <vnet/fib/ip6_fib.h> @@ -116,9 +117,7 @@ typedef struct u32 seed; u64 randomizer; int ref_count; - adj_index_t all_nodes_adj_index; - adj_index_t all_routers_adj_index; - adj_index_t all_mldv2_routers_adj_index; + adj_index_t mcast_adj_index; /* timing information */ #define DEF_MAX_RADV_INTERVAL 200 @@ -474,33 +473,72 @@ ip6_ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai) nbr = ip6_nd_find (sw_if_index, &adj->sub_type.nbr.next_hop.ip6); - if (NULL != nbr) - { - adj_nbr_walk_nh6 (sw_if_index, &nbr->key.ip6_address, - ip6_nd_mk_complete_walk, nbr); - } - else + switch (adj->lookup_next_index) { + case IP_LOOKUP_NEXT_ARP: + case IP_LOOKUP_NEXT_GLEAN: + if (NULL != nbr) + { + adj_nbr_walk_nh6 (sw_if_index, &nbr->key.ip6_address, + ip6_nd_mk_complete_walk, nbr); + } + else + { + /* + * no matching ND entry. + * construct the rewrite required to for an ND packet, and stick + * that in the adj's pipe to smoke. + */ + adj_nbr_update_rewrite (ai, + ADJ_NBR_REWRITE_FLAG_INCOMPLETE, + ethernet_build_rewrite (vnm, + sw_if_index, + VNET_LINK_IP6, + VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST)); + + /* + * since the FIB has added this adj for a route, it makes sense it may + * want to forward traffic sometime soon. Let's send a speculative ND. + * just one. If we were to do periodically that wouldn't be bad either, + * but that's more code than i'm prepared to write at this time for + * relatively little reward. + */ + ip6_nbr_probe (adj); + } + break; + case IP_LOOKUP_NEXT_MCAST: /* - * no matching ND entry. - * construct the rewrite required to for an ND packet, and stick - * that in the adj's pipe to smoke. + * Construct a partial rewrite from the known ethernet mcast dest MAC */ - adj_nbr_update_rewrite (ai, - ADJ_NBR_REWRITE_FLAG_INCOMPLETE, - ethernet_build_rewrite (vnm, - sw_if_index, - VNET_LINK_IP6, - VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST)); + adj_mcast_update_rewrite + (ai, + ethernet_build_rewrite (vnm, + sw_if_index, + adj->ia_link, + ethernet_ip6_mcast_dst_addr ())); /* - * since the FIB has added this adj for a route, it makes sense it may - * want to forward traffic sometime soon. Let's send a speculative ND. - * just one. If we were to do periodically that wouldn't be bad either, - * but that's more code than i'm prepared to write at this time for - * relatively little reward. + * Complete the remaining fields of the adj's rewrite to direct the + * complete of the rewrite at switch time by copying in the IP + * dst address's bytes. + * Ofset is 12 bytes from the end of the MAC header - which is 2 + * bytes into the desintation address. And we write 4 bytes. */ - ip6_nbr_probe (adj); + adj->rewrite_header.dst_mcast_offset = 12; + adj->rewrite_header.dst_mcast_n_bytes = 4; + + break; + + case IP_LOOKUP_NEXT_DROP: + case IP_LOOKUP_NEXT_PUNT: + case IP_LOOKUP_NEXT_LOCAL: + case IP_LOOKUP_NEXT_REWRITE: + case IP_LOOKUP_NEXT_LOAD_BALANCE: + case IP_LOOKUP_NEXT_MIDCHAIN: + case IP_LOOKUP_NEXT_ICMP_ERROR: + case IP_LOOKUP_N_NEXT: + ASSERT (0); + break; } } @@ -1517,7 +1555,7 @@ icmp6_router_solicitation (vlib_main_t * vm, } else { - adj_index0 = radv_info->all_nodes_adj_index; + adj_index0 = radv_info->mcast_adj_index; if (adj_index0 == 0) error0 = ICMP6_ERROR_DST_LOOKUP_MISS; else @@ -1918,10 +1956,8 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, ip6_radv_prefix_t *p; ip6_mldp_group_t *m; - /* remove adjacencies */ - adj_unlock (a->all_nodes_adj_index); - adj_unlock (a->all_routers_adj_index); - adj_unlock (a->all_mldv2_routers_adj_index); + /* release the lock on the interface's mcast adj */ + adj_unlock (a->mcast_adj_index); /* clean up prefix_pool */ /* *INDENT-OFF* */ @@ -2017,36 +2053,9 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, mhash_init (&a->address_to_mldp_index, sizeof (uword), sizeof (ip6_address_t)); - { - u8 link_layer_address[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, - IP6_MULTICAST_GROUP_ID_all_hosts - }; - - a->all_nodes_adj_index = - adj_rewrite_add_and_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6, - sw_if_index, link_layer_address); - } - - { - u8 link_layer_address[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, - IP6_MULTICAST_GROUP_ID_all_routers - }; - - a->all_routers_adj_index = - adj_rewrite_add_and_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6, - sw_if_index, link_layer_address); - } - - { - u8 link_layer_address[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, - IP6_MULTICAST_GROUP_ID_mldv2_routers - }; - - a->all_mldv2_routers_adj_index = - adj_rewrite_add_and_lock (FIB_PROTOCOL_IP6, - VNET_LINK_IP6, - sw_if_index, link_layer_address); - } + a->mcast_adj_index = adj_mcast_add_or_lock (FIB_PROTOCOL_IP6, + VNET_LINK_IP6, + sw_if_index); /* add multicast groups we will always be reporting */ ip6_address_t addr; @@ -2273,11 +2282,10 @@ ip6_neighbor_send_mldpv2_report (u32 sw_if_index) vnet_buffer (b0)->sw_if_index[VLIB_RX] = vnet_main.local_interface_sw_if_index; - vnet_buffer (b0)->ip.adj_index[VLIB_TX] = - radv_info->all_mldv2_routers_adj_index; + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = radv_info->mcast_adj_index; b0->flags |= VNET_BUFFER_LOCALLY_ORIGINATED; - vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite"); + vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite-mcast"); f = vlib_get_frame_to_node (vm, node->index); to_next = vlib_frame_vector_args (f); @@ -2301,7 +2309,7 @@ VLIB_REGISTER_NODE (ip6_icmp_router_solicitation_node,static) = .n_next_nodes = ICMP6_ROUTER_SOLICITATION_N_NEXT, .next_nodes = { [ICMP6_ROUTER_SOLICITATION_NEXT_DROP] = "error-drop", - [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite", + [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite-mcast", [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output", }, }; diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c index aafde464445..437d26749cd 100644 --- a/src/vnet/ip/ip_api.c +++ b/src/vnet/ip/ip_api.c @@ -33,6 +33,9 @@ #include <vnet/dpo/classify_dpo.h> #include <vnet/dpo/ip_null_dpo.h> #include <vnet/ethernet/arp_packet.h> +//#include <vnet/mfib/ip6_mfib.h> +#include <vnet/mfib/ip4_mfib.h> +#include <vnet/mfib/mfib_signal.h> #include <vnet/vnet_msg_enum.h> @@ -58,6 +61,8 @@ _(IP_FIB_DETAILS, ip_fib_details) \ _(IP6_FIB_DUMP, ip6_fib_dump) \ _(IP6_FIB_DETAILS, ip6_fib_details) \ _(IP_NEIGHBOR_DUMP, ip_neighbor_dump) \ +_(IP_MROUTE_ADD_DEL, ip_mroute_add_del) \ +_(MFIB_SIGNAL_DUMP, mfib_signal_dump) \ _(IP_NEIGHBOR_DETAILS, ip_neighbor_details) \ _(IP_ADDRESS_DUMP, ip_address_dump) \ _(IP_DUMP, ip_dump) \ @@ -845,6 +850,144 @@ vl_api_ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) REPLY_MACRO (VL_API_IP_ADD_DEL_ROUTE_REPLY); } +static int +add_del_mroute_check (fib_protocol_t table_proto, + u32 table_id, + u32 next_hop_sw_if_index, + u8 is_local, u8 create_missing_tables, u32 * fib_index) +{ + vnet_main_t *vnm = vnet_get_main (); + + *fib_index = mfib_table_find (table_proto, ntohl (table_id)); + if (~0 == *fib_index) + { + if (create_missing_tables) + { + *fib_index = mfib_table_find_or_create_and_lock (table_proto, + ntohl (table_id)); + } + else + { + /* No such VRF, and we weren't asked to create one */ + return VNET_API_ERROR_NO_SUCH_FIB; + } + } + + if (~0 != ntohl (next_hop_sw_if_index)) + { + if (pool_is_free_index (vnm->interface_main.sw_interfaces, + ntohl (next_hop_sw_if_index))) + { + return VNET_API_ERROR_NO_MATCHING_INTERFACE; + } + } + + return (0); +} + +static int +mroute_add_del_handler (u8 is_add, + u8 is_local, + u32 fib_index, + const mfib_prefix_t * prefix, + u32 entry_flags, + u32 next_hop_sw_if_index, u32 itf_flags) +{ + stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ ); + + fib_route_path_t path = { + .frp_sw_if_index = next_hop_sw_if_index, + .frp_proto = prefix->fp_proto, + }; + + if (is_local) + path.frp_flags |= FIB_ROUTE_PATH_LOCAL; + + + if (!is_local && ~0 == next_hop_sw_if_index) + { + mfib_table_entry_update (fib_index, prefix, + MFIB_SOURCE_API, entry_flags); + } + else + { + if (is_add) + { + mfib_table_entry_path_update (fib_index, prefix, + MFIB_SOURCE_API, &path, itf_flags); + } + else + { + mfib_table_entry_path_remove (fib_index, prefix, + MFIB_SOURCE_API, &path); + } + } + + stats_dsunlock (); + return (0); +} + +static int +api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp) +{ + fib_protocol_t fproto; + u32 fib_index; + int rv; + + fproto = (mp->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4); + rv = add_del_mroute_check (fproto, + mp->table_id, + mp->next_hop_sw_if_index, + mp->is_local, + mp->create_vrf_if_needed, &fib_index); + + if (0 != rv) + return (rv); + + mfib_prefix_t pfx = { + .fp_len = ntohs (mp->grp_address_length), + .fp_proto = fproto, + }; + + if (FIB_PROTOCOL_IP4 == fproto) + { + clib_memcpy (&pfx.fp_grp_addr.ip4, mp->grp_address, + sizeof (pfx.fp_grp_addr.ip4)); + clib_memcpy (&pfx.fp_src_addr.ip4, mp->src_address, + sizeof (pfx.fp_src_addr.ip4)); + } + else + { + clib_memcpy (&pfx.fp_grp_addr.ip6, mp->grp_address, + sizeof (pfx.fp_grp_addr.ip6)); + clib_memcpy (&pfx.fp_src_addr.ip6, mp->src_address, + sizeof (pfx.fp_src_addr.ip6)); + } + + return (mroute_add_del_handler (mp->is_add, + mp->is_local, + fib_index, &pfx, + ntohl (mp->entry_flags), + ntohl (mp->next_hop_sw_if_index), + ntohl (mp->itf_flags))); +} + +void +vl_api_ip_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp) +{ + vl_api_ip_mroute_add_del_reply_t *rmp; + int rv; + vnet_main_t *vnm = vnet_get_main (); + + vnm->api_errno = 0; + + rv = api_mroute_add_del_t_handler (mp); + + rv = (rv == 0) ? vnm->api_errno : rv; + + REPLY_MACRO (VL_API_IP_MROUTE_ADD_DEL_REPLY); +} + static void send_ip_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, u32 sw_if_index, u32 context) @@ -1148,6 +1291,73 @@ static void REPLY_MACRO (VL_API_SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY); } +void +vl_mfib_signal_send_one (unix_shared_memory_queue_t * q, + u32 context, const mfib_signal_t * mfs) +{ + vl_api_mfib_signal_details_t *mp; + mfib_prefix_t prefix; + mfib_table_t *mfib; + mfib_itf_t *mfi; + + mp = vl_msg_api_alloc (sizeof (*mp)); + + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_MFIB_SIGNAL_DETAILS); + mp->context = context; + + mfi = mfib_itf_get (mfs->mfs_itf); + mfib_entry_get_prefix (mfs->mfs_entry, &prefix); + mfib = mfib_table_get (mfib_entry_get_fib_index (mfs->mfs_entry), + prefix.fp_proto); + mp->table_id = ntohl (mfib->mft_table_id); + mp->sw_if_index = ntohl (mfi->mfi_sw_if_index); + + if (FIB_PROTOCOL_IP4 == prefix.fp_proto) + { + mp->grp_address_len = ntohs (prefix.fp_len); + + memcpy (mp->grp_address, &prefix.fp_grp_addr.ip4, 4); + if (prefix.fp_len > 32) + { + memcpy (mp->src_address, &prefix.fp_src_addr.ip4, 4); + } + } + else + { + mp->grp_address_len = ntohs (prefix.fp_len); + + ASSERT (0); + } + + if (0 != mfs->mfs_buffer_len) + { + mp->ip_packet_len = ntohs (mfs->mfs_buffer_len); + + memcpy (mp->ip_packet_data, mfs->mfs_buffer, mfs->mfs_buffer_len); + } + else + { + mp->ip_packet_len = 0; + } + + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + +static void +vl_api_mfib_signal_dump_t_handler (vl_api_mfib_signal_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + { + return; + } + + while (q->cursize < q->maxsize && mfib_signal_send_one (q, mp->context)) + ; +} #define vl_msg_name_crc_list #include <vnet/ip/ip.api.h> diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c index 734a4cd7cfb..6c5611d3955 100644 --- a/src/vnet/ip/lookup.c +++ b/src/vnet/ip/lookup.c @@ -43,6 +43,7 @@ #include <vnet/fib/ip4_fib.h> #include <vnet/fib/ip6_fib.h> #include <vnet/mpls/mpls.h> +#include <vnet/mfib/mfib_table.h> #include <vnet/dpo/drop_dpo.h> #include <vnet/dpo/classify_dpo.h> #include <vnet/dpo/punt_dpo.h> @@ -258,6 +259,9 @@ format_ip_lookup_next (u8 * s, va_list * args) case IP_LOOKUP_NEXT_GLEAN: t = "glean"; break; + case IP_LOOKUP_NEXT_MCAST: + t = "mcast"; + break; case IP_LOOKUP_NEXT_REWRITE: break; } @@ -767,6 +771,173 @@ VLIB_CLI_COMMAND (ip_route_command, static) = { }; /* *INDENT-ON* */ +clib_error_t * +vnet_ip_mroute_cmd (vlib_main_t * vm, + unformat_input_t * main_input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = NULL; + fib_route_path_t rpath; + u32 table_id, is_del; + vnet_main_t *vnm; + mfib_prefix_t pfx; + u32 fib_index; + mfib_itf_flags_t iflags = 0; + mfib_entry_flags_t eflags = 0; + + vnm = vnet_get_main (); + is_del = 0; + table_id = 0; + memset (&pfx, 0, sizeof (pfx)); + memset (&rpath, 0, sizeof (rpath)); + rpath.frp_sw_if_index = ~0; + + /* Get a line of input. */ + if (!unformat_user (main_input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "table %d", &table_id)) + ; + else if (unformat (line_input, "del")) + is_del = 1; + else if (unformat (line_input, "add")) + is_del = 0; + else if (unformat (line_input, "%U %U", + unformat_ip4_address, + &pfx.fp_src_addr.ip4, + unformat_ip4_address, &pfx.fp_grp_addr.ip4)) + { + pfx.fp_proto = FIB_PROTOCOL_IP4; + pfx.fp_len = 64; + } + else if (unformat (line_input, "%U %U", + unformat_ip6_address, + &pfx.fp_src_addr.ip6, + unformat_ip6_address, &pfx.fp_grp_addr.ip6)) + { + pfx.fp_proto = FIB_PROTOCOL_IP6; + pfx.fp_len = 256; + } + else if (unformat (line_input, "%U/%d", + unformat_ip4_address, + &pfx.fp_grp_addr.ip4, &pfx.fp_len)) + { + pfx.fp_proto = FIB_PROTOCOL_IP4; + } + else if (unformat (line_input, "%U/%d", + unformat_ip6_address, + &pfx.fp_grp_addr.ip6, &pfx.fp_len)) + { + pfx.fp_proto = FIB_PROTOCOL_IP6; + } + else if (unformat (line_input, "%U", + unformat_ip4_address, &pfx.fp_grp_addr.ip4)) + { + memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4)); + pfx.fp_proto = FIB_PROTOCOL_IP4; + pfx.fp_len = 32; + } + else if (unformat (line_input, "%U", + unformat_ip6_address, &pfx.fp_grp_addr.ip6)) + { + memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6)); + pfx.fp_proto = FIB_PROTOCOL_IP6; + pfx.fp_len = 128; + } + else if (unformat (line_input, "via %U", + unformat_vnet_sw_interface, vnm, + &rpath.frp_sw_if_index)) + { + rpath.frp_weight = 1; + rpath.frp_proto = FIB_PROTOCOL_IP4; + } + else if (unformat (line_input, "%U", unformat_mfib_itf_flags, &iflags)) + ; + else if (unformat (line_input, "%U", + unformat_mfib_entry_flags, &eflags)) + ; + else + { + error = unformat_parse_error (line_input); + goto done; + } + } + + unformat_free (line_input); + + if (~0 == table_id) + { + /* + * if no table_id is passed we will manipulate the default + */ + fib_index = 0; + } + else + { + fib_index = mfib_table_find (pfx.fp_proto, table_id); + + if (~0 == fib_index) + { + error = clib_error_return (0, "Nonexistent table id %d", table_id); + goto done; + } + } + + if (is_del && 0 == rpath.frp_weight) + { + mfib_table_entry_delete (fib_index, &pfx, MFIB_SOURCE_CLI); + } + else if (eflags) + { + mfib_table_entry_update (fib_index, &pfx, MFIB_SOURCE_CLI, eflags); + } + else + { + if (is_del) + mfib_table_entry_path_remove (fib_index, + &pfx, MFIB_SOURCE_CLI, &rpath); + else + mfib_table_entry_path_update (fib_index, + &pfx, MFIB_SOURCE_CLI, &rpath, iflags); + } + +done: + return error; +} + +/*? + * This command is used to add or delete IPv4 or IPv6 multicastroutes. All + * IP Addresses ('<em><dst-ip-addr>/<width></em>', + * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>') + * can be IPv4 or IPv6, but all must be of the same form in a single + * command. To display the current set of routes, use the commands + * '<em>show ip mfib</em>' and '<em>show ip6 mfib</em>'. + * The full set of support flags for interfaces and route is shown via; + * '<em>show mfib route flags</em>' and '<em>show mfib itf flags</em>' + * respectively. + * @cliexpar + * Example of how to add a forwarding interface to a route (and create the + * route if it does not exist) + * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/0 Forward} + * Example of how to add an accepting interface to a route (and create the + * route if it does not exist) + * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/1 Accept} + * Example of changing the route's flags to send signals via the API + * @cliexcmd{ip mroute add 232.1.1.1 Signal} + + ?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (ip_mroute_command, static) = +{ + .path = "ip mroute", + .short_help = "ip mroute [add|del] <dst-ip-addr>/<width> [table <table-id>] [via <next-hop-ip-addr> [<interface>],", + .function = vnet_ip_mroute_cmd, + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ + /* * The next two routines address a longstanding script hemorrhoid. * Probing a v4 or v6 neighbor needs to appear to be synchronous, diff --git a/src/vnet/ip/lookup.h b/src/vnet/ip/lookup.h index 3dbd7b3b8e8..27c70943991 100644 --- a/src/vnet/ip/lookup.h +++ b/src/vnet/ip/lookup.h @@ -91,6 +91,9 @@ typedef enum /** This packets needs to go to ICMP error */ IP_LOOKUP_NEXT_ICMP_ERROR, + /** Multicast Adjacency. */ + IP_LOOKUP_NEXT_MCAST, + IP_LOOKUP_N_NEXT, } ip_lookup_next_t; @@ -115,6 +118,7 @@ typedef enum [IP_LOOKUP_NEXT_ARP] = "ip4-arp", \ [IP_LOOKUP_NEXT_GLEAN] = "ip4-glean", \ [IP_LOOKUP_NEXT_REWRITE] = "ip4-rewrite", \ + [IP_LOOKUP_NEXT_MCAST] = "ip4-rewrite-mcast", \ [IP_LOOKUP_NEXT_MIDCHAIN] = "ip4-midchain", \ [IP_LOOKUP_NEXT_LOAD_BALANCE] = "ip4-load-balance", \ [IP_LOOKUP_NEXT_ICMP_ERROR] = "ip4-icmp-error", \ @@ -127,6 +131,7 @@ typedef enum [IP_LOOKUP_NEXT_ARP] = "ip6-discover-neighbor", \ [IP_LOOKUP_NEXT_GLEAN] = "ip6-glean", \ [IP_LOOKUP_NEXT_REWRITE] = "ip6-rewrite", \ + [IP_LOOKUP_NEXT_MCAST] = "ip6-rewrite-mcast", \ [IP_LOOKUP_NEXT_MIDCHAIN] = "ip6-midchain", \ [IP_LOOKUP_NEXT_LOAD_BALANCE] = "ip6-load-balance", \ [IP_LOOKUP_NEXT_ICMP_ERROR] = "ip6-icmp-error", \ @@ -203,12 +208,6 @@ typedef struct ip_adjacency_t_ /** Interface address index for this local/arp adjacency. */ u32 if_address_index; - /** Force re-lookup in a different FIB. ~0 => normal behavior */ - u16 mcast_group_index; - - /** Highest possible perf subgraph arc interposition, e.g. for ip6 ioam */ - u16 saved_lookup_next_index; - /* * link/ether-type */ @@ -236,28 +235,28 @@ typedef struct ip_adjacency_t_ */ struct { - /** - * The recursive next-hop - */ + /** + * The recursive next-hop + */ ip46_address_t next_hop; - /** - * The node index of the tunnel's post rewrite/TX function. - */ + /** + * The node index of the tunnel's post rewrite/TX function. + */ u32 tx_function_node; - /** - * The next DPO to use - */ + /** + * The next DPO to use + */ dpo_id_t next_dpo; - /** - * A function to perform the post-rewrite fixup - */ - adj_midchain_fixup_t fixup_func; - } midchain; /** - * IP_LOOKUP_NEXT_GLEAN - * - * Glean the address to ARP for from the packet's destination + * A function to perform the post-rewrite fixup */ + adj_midchain_fixup_t fixup_func; + } midchain; + /** + * IP_LOOKUP_NEXT_GLEAN + * + * Glean the address to ARP for from the packet's destination + */ struct { ip46_address_t receive_addr; @@ -291,43 +290,6 @@ STATIC_ASSERT ((STRUCT_OFFSET_OF (ip_adjacency_t, cacheline1) == /* An all zeros address */ extern const ip46_address_t zero_addr; -/* IP multicast adjacency. */ -typedef struct -{ - /* Handle for this adjacency in adjacency heap. */ - u32 heap_handle; - - /* Number of adjecencies in block. */ - u32 n_adj; - - /* Rewrite string. */ - vnet_declare_rewrite (64 - 2 * sizeof (u32)); -} -ip_multicast_rewrite_t; - -typedef struct -{ - /* ip4-multicast-rewrite next index. */ - u32 next_index; - - u8 n_rewrite_bytes; - - u8 rewrite_string[64 - 1 * sizeof (u32) - 1 * sizeof (u8)]; -} -ip_multicast_rewrite_string_t; - -typedef struct -{ - ip_multicast_rewrite_t *rewrite_heap; - - ip_multicast_rewrite_string_t *rewrite_strings; - - /* Negative rewrite string index; >= 0 sw_if_index. - Sorted. Used to hash. */ - i32 **adjacency_id_vector; - - uword *adjacency_by_id_vector; -} ip_multicast_lookup_main_t; typedef struct { |