X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fethernet%2Farp.c;h=ad0c2c8ceabb7563571b09ca193ebfe116477ef7;hb=8142499cd1cb3b8d0168d0e6cf5309c5b4813cc4;hp=ee7575051922f3991b5a6ae09960876388e9e961;hpb=fa5d19829759cef45cc34efe844d9471f5a1fc61;p=vpp.git diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c index ee757505192..ad0c2c8ceab 100644 --- a/src/vnet/ethernet/arp.c +++ b/src/vnet/ethernet/arp.c @@ -107,6 +107,8 @@ typedef struct #define ETHERNET_ARP_ARGS_POPULATE (1<<2) } vnet_arp_set_ip4_over_ethernet_rpc_args_t; +static const u8 vrrp_prefix[] = { 0x00, 0x00, 0x5E, 0x00, 0x01 }; + static void set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t * a); @@ -507,6 +509,7 @@ arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai) case IP_LOOKUP_NEXT_PUNT: case IP_LOOKUP_NEXT_LOCAL: case IP_LOOKUP_NEXT_REWRITE: + case IP_LOOKUP_NEXT_MCAST_MIDCHAIN: case IP_LOOKUP_NEXT_MIDCHAIN: case IP_LOOKUP_NEXT_ICMP_ERROR: case IP_LOOKUP_N_NEXT: @@ -563,6 +566,7 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm, e->sw_if_index = sw_if_index; e->ip4_address = a->ip4; + e->fib_entry_index = FIB_NODE_INDEX_INVALID; clib_memcpy (e->ethernet_address, a->ethernet, sizeof (e->ethernet_address)); @@ -578,11 +582,14 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm, fib_index = ip4_fib_table_get_index_for_sw_if_index (e->sw_if_index); e->fib_entry_index = - fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_ADJ, - FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, &pfx.fp_addr, - e->sw_if_index, ~0, 1, NULL, - FIB_ROUTE_PATH_FLAG_NONE); + fib_table_entry_path_add (fib_index, &pfx, FIB_SOURCE_ADJ, + FIB_ENTRY_FLAG_ATTACHED, + FIB_PROTOCOL_IP4, &pfx.fp_addr, + e->sw_if_index, ~0, 1, NULL, + FIB_ROUTE_PATH_FLAG_NONE); + } + else + { e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_NO_FIB_ENTRY; } } @@ -823,66 +830,39 @@ unset_random_arp_entry (void) static int arp_unnumbered (vlib_buffer_t * p0, - u32 pi0, ethernet_header_t * eth0, u32 sw_if_index) + u32 pi0, + ethernet_header_t * eth0, + u32 input_sw_if_index, u32 conn_sw_if_index) { vlib_main_t *vm = vlib_get_main (); vnet_main_t *vnm = vnet_get_main (); vnet_interface_main_t *vim = &vnm->interface_main; vnet_sw_interface_t *si; vnet_hw_interface_t *hi; - u32 unnum_src_sw_if_index; - u32 *broadcast_swifs = 0; u32 *buffers = 0; - u32 n_alloc = 0; vlib_buffer_t *b0; int i; u8 dst_mac_address[6]; i16 header_size; ethernet_arp_header_t *arp0; - /* Save the dst mac address */ - clib_memcpy (dst_mac_address, eth0->dst_address, sizeof (dst_mac_address)); - - /* Figure out which sw_if_index supplied the address */ - unnum_src_sw_if_index = sw_if_index; - - /* Track down all users of the unnumbered source */ - /* *INDENT-OFF* */ - pool_foreach (si, vim->sw_interfaces, - ({ - if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED && - (si->unnumbered_sw_if_index == unnum_src_sw_if_index)) - { - vec_add1 (broadcast_swifs, si->sw_if_index); - } - })); - /* *INDENT-ON* */ - - /* If there are no interfaces un-unmbered to this interface, - we are done here. */ - if (0 == vec_len (broadcast_swifs)) - return 0; + /* verify that the input interface is unnumbered to the connected. + * the connected interface is the interface on which the subnet is + * configured */ + si = &vim->sw_interfaces[input_sw_if_index]; - /* Allocate buffering if we need it */ - if (vec_len (broadcast_swifs) > 1) + if (!(si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED && + (si->unnumbered_sw_if_index == conn_sw_if_index))) { - vec_validate (buffers, vec_len (broadcast_swifs) - 2); - n_alloc = vlib_buffer_alloc (vm, buffers, vec_len (buffers)); - _vec_len (buffers) = n_alloc; - for (i = 0; i < n_alloc; i++) - { - b0 = vlib_get_buffer (vm, buffers[i]); - - /* xerox (partially built) ARP pkt */ - clib_memcpy (b0->data, p0->data, - p0->current_length + p0->current_data); - b0->current_data = p0->current_data; - b0->current_length = p0->current_length; - vnet_buffer (b0)->sw_if_index[VLIB_RX] = - vnet_buffer (p0)->sw_if_index[VLIB_RX]; - } + /* the input interface is not unnumbered to the interface on which + * the sub-net is configured that covers the ARP request. + * So this is not the case for unnumbered.. */ + return 0; } + /* Save the dst mac address */ + clib_memcpy (dst_mac_address, eth0->dst_address, sizeof (dst_mac_address)); + vec_insert (buffers, 1, 0); buffers[0] = pi0; @@ -891,8 +871,8 @@ arp_unnumbered (vlib_buffer_t * p0, b0 = vlib_get_buffer (vm, buffers[i]); arp0 = vlib_buffer_get_current (b0); - hi = vnet_get_sup_hw_interface (vnm, broadcast_swifs[i]); - si = vnet_get_sw_interface (vnm, broadcast_swifs[i]); + hi = vnet_get_sup_hw_interface (vnm, input_sw_if_index); + si = vnet_get_sw_interface (vnm, input_sw_if_index); /* For decoration, most likely */ vnet_buffer (b0)->sw_if_index[VLIB_TX] = hi->sw_if_index; @@ -962,14 +942,25 @@ arp_unnumbered (vlib_buffer_t * p0, } /* The regular path outputs the original pkt.. */ - vnet_buffer (p0)->sw_if_index[VLIB_TX] = broadcast_swifs[0]; + vnet_buffer (p0)->sw_if_index[VLIB_TX] = input_sw_if_index; - vec_free (broadcast_swifs); vec_free (buffers); return !0; } +static u32 +arp_learn (vnet_main_t * vnm, + ethernet_arp_main_t * am, u32 sw_if_index, void *addr) +{ + if (am->limit_arp_cache_size && + pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size) + unset_random_arp_entry (); + + vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index, addr, 0, 0); + return (ETHERNET_ARP_ERROR_l3_src_address_learned); +} + static uword arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { @@ -1002,7 +993,7 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) ethernet_header_t *eth0; ip4_address_t *if_addr0, proxy_src; u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0; - u8 is_request0, dst_is_local0, is_unnum0; + u8 is_request0, dst_is_local0, is_unnum0, is_vrrp_reply0; ethernet_proxy_arp_t *pa; fib_node_index_t dst_fei, src_fei; fib_prefix_t pfx0; @@ -1108,37 +1099,32 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) /* Fill in ethernet header. */ eth0 = ethernet_buffer_get_header (p0); + is_vrrp_reply0 = + ((arp0->opcode == + clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply)) + && + (!memcmp + (arp0->ip4_over_ethernet[0].ethernet, vrrp_prefix, + sizeof (vrrp_prefix)))); + /* Trash ARP packets whose ARP-level source addresses do not - match their L2-frame-level source addresses */ + match their L2-frame-level source addresses, unless it's + a reply from a VRRP virtual router */ if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet, - sizeof (eth0->src_address))) + sizeof (eth0->src_address)) && !is_vrrp_reply0) { error0 = ETHERNET_ARP_ERROR_l2_address_mismatch; goto drop2; } - /* Learn or update sender's mapping only for requests or unicasts - that don't match local interface address. */ - if (ethernet_address_cast (eth0->dst_address) == - ETHERNET_ADDRESS_UNICAST || is_request0) + /* Learn or update sender's mapping only for replies to addresses + * that are local to the subnet */ + if (arp0->opcode == + clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) && + dst_is_local0) { - if (am->limit_arp_cache_size && - pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size) - unset_random_arp_entry (); - - vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0, - &arp0->ip4_over_ethernet[0], - 0 /* is_static */ , 0); - error0 = ETHERNET_ARP_ERROR_l3_src_address_learned; - } - - /* Only send a reply for requests sent which match a local interface. */ - if (!(is_request0 && dst_is_local0)) - { - error0 = - (arp0->opcode == - clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ? - ETHERNET_ARP_ERROR_replies_received : error0); + error0 = arp_learn (vnm, am, sw_if_index0, + &arp0->ip4_over_ethernet[0]); goto drop1; } @@ -1172,7 +1158,8 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { if (is_unnum0) { - if (!arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0)) + if (!arp_unnumbered (p0, pi0, eth0, + sw_if_index0, conn_sw_if_index0)) goto drop2; } else @@ -1226,6 +1213,10 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) } } + /* We are going to reply to this request, so learn the sender */ + error0 = arp_learn (vnm, am, sw_if_index0, + &arp0->ip4_over_ethernet[1]); + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, pi0, next0); @@ -1681,9 +1672,8 @@ arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e) { ethernet_arp_main_t *am = ðernet_arp_main; - /* it's safe to delete the ADJ source on the FIB entry, even if it - * was added */ - fib_table_entry_delete_index (e->fib_entry_index, FIB_SOURCE_ADJ); + if (FIB_NODE_INDEX_INVALID != e->fib_entry_index) + fib_table_entry_delete_index (e->fib_entry_index, FIB_SOURCE_ADJ); hash_unset (eai->arp_entries, e->ip4_address.as_u32); pool_put (am->ip4_entry_pool, e); } @@ -1771,7 +1761,7 @@ set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t * a) { vnet_main_t *vm = vnet_get_main (); - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); if (a->flags & ETHERNET_ARP_ARGS_REMOVE) vnet_arp_unset_ip4_over_ethernet_internal (vm, a); @@ -1914,18 +1904,15 @@ vnet_proxy_arp_add_del (ip4_address_t * lo_addr, int vnet_proxy_arp_fib_reset (u32 fib_id) { - ip4_main_t *im = &ip4_main; ethernet_arp_main_t *am = ðernet_arp_main; ethernet_proxy_arp_t *pa; u32 *entries_to_delete = 0; u32 fib_index; - uword *p; int i; - p = hash_get (im->fib_index_by_table_id, fib_id); - if (!p) + fib_index = fib_table_find (FIB_PROTOCOL_IP4, fib_id); + if (~0 == fib_index) return VNET_API_ERROR_NO_SUCH_ENTRY; - fib_index = p[0]; vec_foreach (pa, am->proxy_arps) { @@ -1984,11 +1971,10 @@ ip_arp_add_del_command_fn (vlib_main_t * vm, else if (unformat (input, "fib-id %d", &fib_id)) { - ip4_main_t *im = &ip4_main; - uword *p = hash_get (im->fib_index_by_table_id, fib_id); - if (!p) + fib_index = fib_table_find (FIB_PROTOCOL_IP4, fib_id); + + if (~0 == fib_index) return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id); - fib_index = p[0]; } else if (unformat (input, "proxy %U - %U", @@ -2195,6 +2181,7 @@ arp_term_l2bd (vlib_main_t * vm, u16 bd_index0; u32 ip0; u8 *macp0; + u8 is_vrrp_reply0; pi0 = from[0]; to_next[0] = pi0; @@ -2243,12 +2230,20 @@ arp_term_l2bd (vlib_main_t * vm, if (error0) goto drop; + is_vrrp_reply0 = + ((arp0->opcode == + clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply)) + && + (!memcmp + (arp0->ip4_over_ethernet[0].ethernet, vrrp_prefix, + sizeof (vrrp_prefix)))); + /* Trash ARP packets whose ARP-level source addresses do not - match their L2-frame-level source addresses */ + match their L2-frame-level source addresses, unless it's + a reply from a VRRP virtual router */ if (PREDICT_FALSE - (memcmp - (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet, - sizeof (eth0->src_address)))) + (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet, + sizeof (eth0->src_address)) && !is_vrrp_reply0)) { error0 = ETHERNET_ARP_ERROR_l2_address_mismatch; goto drop;