From 8a8b83f5fe740d4972f12455a54a0fc906320338 Mon Sep 17 00:00:00 2001 From: Benoît Ganne Date: Tue, 25 Jun 2019 10:32:28 +0200 Subject: ip: check all fib src for a connected dst entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When looking for a connected fib entry matching the ARP destination, there can be other DPO interposed prior to the connected one. Type: fix Change-Id: I9b4ab387fb08acf9879d5fda3791e6572a099492 Signed-off-by: Benoît Ganne --- src/vnet/ethernet/arp.c | 78 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 25 deletions(-) (limited to 'src/vnet/ethernet/arp.c') diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c index 201bec499d1..b62dc4e0e90 100644 --- a/src/vnet/ethernet/arp.c +++ b/src/vnet/ethernet/arp.c @@ -1143,6 +1143,38 @@ arp_mk_reply (vnet_main_t * vnm, return (next0); } +enum arp_dst_fib_type +{ + ARP_DST_FIB_NONE, + ARP_DST_FIB_ADJ, + ARP_DST_FIB_CONN +}; + +/* + * we're looking for FIB sources that indicate the destination + * is attached. There may be interposed DPO prior to the one + * we are looking for + */ +static enum arp_dst_fib_type +arp_dst_fib_check (const fib_node_index_t fei, fib_entry_flag_t * flags) +{ + const fib_entry_t *entry = fib_entry_get (fei); + const fib_entry_src_t *entry_src; + fib_source_t src; + /* *INDENT-OFF* */ + FOR_EACH_SRC_ADDED(entry, entry_src, src, + ({ + *flags = fib_entry_get_flags_for_source (fei, src); + if (fib_entry_is_sourced (fei, FIB_SOURCE_ADJ)) + return ARP_DST_FIB_ADJ; + else if (FIB_ENTRY_FLAG_CONNECTED & *flags) + return ARP_DST_FIB_CONN; + })) + /* *INDENT-ON* */ + + return ARP_DST_FIB_NONE; +} + static uword arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { @@ -1173,7 +1205,7 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) ethernet_header_t *eth_rx; const ip4_address_t *if_addr0; u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0; - u8 dst_is_local0, is_unnum0, is_vrrp_reply0; + u8 dst_is_local0, is_vrrp_reply0; fib_node_index_t dst_fei, src_fei; const fib_prefix_t *pfx0; fib_entry_flag_t src_flags, dst_flags; @@ -1202,15 +1234,6 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) goto drop; } - dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0), - &arp0->ip4_over_ethernet[1].ip4, - 32); - dst_flags = fib_entry_get_flags (dst_fei); - - conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei); - - /* Honor unnumbered interface, if any */ - is_unnum0 = sw_if_index0 != conn_sw_if_index0; { /* @@ -1313,8 +1336,12 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) } } - if (fib_entry_is_sourced (dst_fei, FIB_SOURCE_ADJ)) + dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0), + &arp0->ip4_over_ethernet[1].ip4, + 32); + switch (arp_dst_fib_check (dst_fei, &dst_flags)) { + case ARP_DST_FIB_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 @@ -1328,23 +1355,15 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) error0 = arp_learn (vnm, am, sw_if_index0, &arp0->ip4_over_ethernet[0]); goto drop; - } - else if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags)) - { + case ARP_DST_FIB_CONN: + /* destination is connected, continue to process */ + break; + case ARP_DST_FIB_NONE: + /* destination is not connected, stop here */ error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local; goto next_feature; } - if (sw_if_index0 != fib_entry_get_resolving_interface (src_fei)) - { - /* - * The interface the ARP was received on is not the interface - * on which the covering prefix is configured. Maybe this is a - * case for unnumbered. - */ - is_unnum0 = 1; - } - dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags); pfx0 = fib_entry_get_prefix (dst_fei); if_addr0 = &pfx0->fp_addr.ip4; @@ -1390,8 +1409,17 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { goto next_feature; } - if (is_unnum0) + + /* Honor unnumbered interface, if any */ + conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei); + if (sw_if_index0 != conn_sw_if_index0 || + sw_if_index0 != fib_entry_get_resolving_interface (src_fei)) { + /* + * The interface the ARP is sent to or was received on is not the + * interface on which the covering prefix is configured. + * Maybe this is a case for unnumbered. + */ if (!arp_unnumbered (p0, sw_if_index0, conn_sw_if_index0)) { error0 = ETHERNET_ARP_ERROR_unnumbered_mismatch; -- cgit 1.2.3-korg