X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fethernet%2Farp.c;h=f7d8ff867f80d221062ffadb928d29b4bc2cba91;hb=1855b8e4;hp=249e3b6e8cf96d8a994c1f78428412ae4ef77a17;hpb=4fed5b1b34b346f25feef34c590b4dd428343756;p=vpp.git diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c index 249e3b6e8cf..f7d8ff867f8 100644 --- a/src/vnet/ethernet/arp.c +++ b/src/vnet/ethernet/arp.c @@ -352,6 +352,8 @@ arp_nbr_probe (ip_adjacency_t * adj) h = vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, &bi); + if (!h) + return; hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index); @@ -490,6 +492,15 @@ arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai) arp_nbr_probe (adj); } break; + case IP_LOOKUP_NEXT_BCAST: + adj_nbr_update_rewrite (ai, + ADJ_NBR_REWRITE_FLAG_COMPLETE, + ethernet_build_rewrite + (vnm, + sw_if_index, + VNET_LINK_IP4, + VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST)); + break; case IP_LOOKUP_NEXT_MCAST: { /* @@ -631,7 +642,13 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm, /* Refuse to over-write static arp. */ if (!is_static && (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC)) - return -2; + { + /* if MAC address match, still check to send event */ + if (0 == memcmp (e->ethernet_address, + a->ethernet, sizeof (e->ethernet_address))) + goto check_customers; + return -2; + } make_new_arp_cache_entry = 0; } } @@ -683,11 +700,12 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm, goto check_customers; } - /* Update time stamp and ethernet address. */ + /* Update ethernet address. */ clib_memcpy (e->ethernet_address, a->ethernet, sizeof (e->ethernet_address)); } + /* Update time stamp and flags. */ e->time_last_updated = vlib_time_now (vm); if (is_static) { @@ -864,6 +882,7 @@ typedef enum _ (l3_type_not_ip4, "L3 type not IP4") \ _ (l3_src_address_not_local, "IP4 source address not local to subnet") \ _ (l3_dst_address_not_local, "IP4 destination address not local to subnet") \ + _ (l3_dst_address_unset, "IP4 destination address is unset") \ _ (l3_src_address_is_local, "IP4 source address matches local interface") \ _ (l3_src_address_learned, "ARP request IP4 source address learned") \ _ (replies_received, "ARP replies received") \ @@ -980,6 +999,9 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) (arp0->l3_type != clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ? ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0); + error0 = + (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ? + ETHERNET_ARP_ERROR_l3_dst_address_unset : error0); sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX]; @@ -1110,7 +1132,23 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) } } - if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags)) + if (fib_entry_is_sourced (dst_fei, FIB_SOURCE_ADJ)) + { + /* + * We matched an adj-fib on ths source subnet (a /32 previously + * added as a result of ARP). If this request is a gratuitous + * ARP, then learn from it. + * The check for matching an adj-fib, is to prevent hosts + * from spamming us with gratuitous ARPS that might otherwise + * blow our ARP cache + */ + if (arp0->ip4_over_ethernet[0].ip4.as_u32 == + arp0->ip4_over_ethernet[1].ip4.as_u32) + error0 = arp_learn (vnm, am, sw_if_index0, + &arp0->ip4_over_ethernet[0]); + goto drop2; + } + else if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags)) { error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local; goto drop1; @@ -1152,11 +1190,17 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) /* 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) + clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply)) { - error0 = arp_learn (vnm, am, sw_if_index0, - &arp0->ip4_over_ethernet[0]); + if (dst_is_local0) + error0 = arp_learn (vnm, am, sw_if_index0, + &arp0->ip4_over_ethernet[0]); + else + /* a reply for a non-local destination could be a GARP. + * GARPs for hosts we know were handled above, so this one + * we drop */ + error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local; + goto drop1; } else if (arp0->opcode == @@ -1227,9 +1271,8 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) continue; drop1: - if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 || - (arp0->ip4_over_ethernet[0].ip4.as_u32 == - arp0->ip4_over_ethernet[1].ip4.as_u32)) + if (arp0->ip4_over_ethernet[0].ip4.as_u32 == + arp0->ip4_over_ethernet[1].ip4.as_u32) { error0 = ETHERNET_ARP_ERROR_gratuitous_arp; goto drop2; @@ -2297,7 +2340,6 @@ 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; @@ -2316,13 +2358,16 @@ arp_term_l2bd (vlib_main_t * vm, ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2)); arp0 = (ethernet_arp_header_t *) l3h0; - if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) || - (arp0->opcode != - clib_host_to_net_u16 - (ETHERNET_ARP_OPCODE_request)))) + if (ethertype0 != ETHERNET_TYPE_ARP) + goto check_ip6_nd; + + if ((arp0->opcode != + clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request)) && + (arp0->opcode != + clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))) goto check_ip6_nd; - /* Must be ARP request packet here */ + /* Must be ARP request/reply packet here */ if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (p0->flags & VLIB_BUFFER_IS_TRACED))) { @@ -2331,7 +2376,7 @@ arp_term_l2bd (vlib_main_t * vm, clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t)); } - error0 = ETHERNET_ARP_ERROR_replies_sent; + error0 = 0; error0 = (arp0->l2_type != clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) @@ -2346,22 +2391,25 @@ 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, unless it's - a reply from a VRRP virtual router */ + match, or if requester address is mcast */ if (PREDICT_FALSE (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet, - sizeof (eth0->src_address)) && !is_vrrp_reply0)) + sizeof (eth0->src_address)) || + ethernet_address_cast (arp0->ip4_over_ethernet[0].ethernet))) { - error0 = ETHERNET_ARP_ERROR_l2_address_mismatch; + /* VRRP virtual MAC may be different to SMAC in ARP reply */ + if (memcmp (arp0->ip4_over_ethernet[0].ethernet, vrrp_prefix, + sizeof (vrrp_prefix))) + { + error0 = ETHERNET_ARP_ERROR_l2_address_mismatch; + goto drop; + } + } + if (PREDICT_FALSE + (ip4_address_is_multicast (&arp0->ip4_over_ethernet[0].ip4))) + { + error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local; goto drop; } @@ -2526,22 +2574,22 @@ ethernet_arp_change_mac (u32 sw_if_index) } void -send_ip4_garp (vlib_main_t * vm, const vnet_hw_interface_t * hi) +send_ip4_garp (vlib_main_t * vm, u32 sw_if_index) { ip4_main_t *i4m = &ip4_main; - ip4_address_t *ip4_addr = - ip4_interface_first_address (i4m, hi->sw_if_index, 0); + ip4_address_t *ip4_addr = ip4_interface_first_address (i4m, sw_if_index, 0); - send_ip4_garp_w_addr (vm, ip4_addr, hi); + send_ip4_garp_w_addr (vm, ip4_addr, sw_if_index); } void send_ip4_garp_w_addr (vlib_main_t * vm, - const ip4_address_t * ip4_addr, - const vnet_hw_interface_t * hi) + const ip4_address_t * ip4_addr, u32 sw_if_index) { ip4_main_t *i4m = &ip4_main; - u32 sw_if_index = hi->sw_if_index; + vnet_main_t *vnm = vnet_get_main (); + u8 *rewrite, rewrite_len; + vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index); if (ip4_addr) { @@ -2554,6 +2602,10 @@ send_ip4_garp_w_addr (vlib_main_t * vm, u32 bi = 0; ethernet_arp_header_t *h = vlib_packet_template_get_packet (vm, &i4m->ip4_arp_request_packet_template, &bi); + + if (!h) + return; + clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address, sizeof (h->ip4_over_ethernet[0].ethernet)); clib_memcpy (h->ip4_over_ethernet[1].ethernet, hi->hw_address, @@ -2563,11 +2615,14 @@ send_ip4_garp_w_addr (vlib_main_t * vm, /* Setup MAC header with ARP Etype and broadcast DMAC */ vlib_buffer_t *b = vlib_get_buffer (vm, bi); - vlib_buffer_advance (b, -sizeof (ethernet_header_t)); + rewrite = + ethernet_build_rewrite (vnm, sw_if_index, VNET_LINK_ARP, + VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST); + rewrite_len = vec_len (rewrite); + vlib_buffer_advance (b, -rewrite_len); ethernet_header_t *e = vlib_buffer_get_current (b); - e->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP); - clib_memcpy (e->src_address, hi->hw_address, sizeof (e->src_address)); - memset (e->dst_address, 0xff, sizeof (e->dst_address)); + clib_memcpy (e->dst_address, rewrite, rewrite_len); + vec_free (rewrite); /* Send GARP packet out the specified interface */ vnet_buffer (b)->sw_if_index[VLIB_RX] =