summaryrefslogtreecommitdiffstats
path: root/src/vnet/ethernet
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/ethernet')
-rw-r--r--src/vnet/ethernet/arp.c127
1 files changed, 97 insertions, 30 deletions
diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c
index 619628b37ca..d5dc9cceb39 100644
--- a/src/vnet/ethernet/arp.c
+++ b/src/vnet/ethernet/arp.c
@@ -22,6 +22,7 @@
#include <vnet/l2/l2_input.h>
#include <vppinfra/mhash.h>
#include <vnet/fib/ip4_fib.h>
+#include <vnet/fib/fib_entry_src.h>
#include <vnet/adj/adj_nbr.h>
#include <vnet/adj/adj_mcast.h>
#include <vnet/mpls/mpls.h>
@@ -955,52 +956,118 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
32);
dst_flags = fib_entry_get_flags (dst_fei);
- src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
- &arp0->ip4_over_ethernet[0].ip4,
- 32);
- src_flags = fib_entry_get_flags (src_fei);
-
conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei);
- if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
- {
- error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
- goto drop1;
- }
-
/* Honor unnumbered interface, if any */
is_unnum0 = sw_if_index0 != conn_sw_if_index0;
- /* Source must also be local to subnet of matching interface address. */
- if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
- (FIB_ENTRY_FLAG_CONNECTED & src_flags)))
+ {
+ /*
+ * we're looking for FIB entries that indicate the source
+ * is attached. There may be more specific non-attached
+ * routes tht match the source, but these do not influence
+ * whether we respond to an ARP request, i.e. they do not
+ * influence whether we are the correct way for the sender
+ * to reach us, they only affect how we reach the sender.
+ */
+ fib_entry_t *src_fib_entry;
+ fib_entry_src_t *src;
+ fib_source_t source;
+ fib_prefix_t pfx;
+ int attached;
+ int mask;
+
+ mask = 32;
+ attached = 0;
+
+ do
+ {
+ src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
+ &arp0->
+ ip4_over_ethernet[0].ip4,
+ mask);
+ src_fib_entry = fib_entry_get (src_fei);
+
+ /*
+ * It's possible that the source that provides the
+ * flags we need, or the flags we must not have,
+ * is not the best source, so check then all.
+ */
+ /* *INDENT-OFF* */
+ FOR_EACH_SRC_ADDED(src_fib_entry, src, source,
+ ({
+ src_flags = fib_entry_get_flags_for_source (src_fei, source);
+
+ /* Reject requests/replies with our local interface
+ address. */
+ if (FIB_ENTRY_FLAG_LOCAL & src_flags)
+ {
+ error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
+ goto drop2;
+ }
+ /* A Source must also be local to subnet of matching
+ * interface address. */
+ if ((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
+ (FIB_ENTRY_FLAG_CONNECTED & src_flags))
+ {
+ attached = 1;
+ break;
+ }
+ /*
+ * else
+ * The packet was sent from an address that is not
+ * connected nor attached i.e. it is not from an
+ * address that is covered by a link's sub-net,
+ * nor is it a already learned host resp.
+ */
+ }));
+ /* *INDENT-ON* */
+
+ /*
+ * shorter mask lookup for the next iteration.
+ */
+ fib_entry_get_prefix (src_fei, &pfx);
+ mask = pfx.fp_len - 1;
+
+ /*
+ * continue until we hit the default route or we find
+ * the attached we are looking for. The most likely
+ * outcome is we find the attached with the first source
+ * on the first lookup.
+ */
+ }
+ while (!attached &&
+ !fib_entry_is_sourced (src_fei, FIB_SOURCE_DEFAULT_ROUTE));
+
+ if (!attached)
+ {
+ /*
+ * the matching route is a not attached, i.e. it was
+ * added as a result of routing, rather than interface/ARP
+ * configuration. If the matching route is not a host route
+ * (i.e. a /32)
+ */
+ error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
+ goto drop2;
+ }
+ }
+
+ if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
{
- /*
- * The packet was sent from an address that is not connected nor attached
- * i.e. it is not from an address that is covered by a link's sub-net,
- * nor is it a already learned host resp.
- */
- error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
- goto drop2;
+ error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
+ goto drop1;
}
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.
+ * on which the covering prefix is configured. Maybe this is a
+ * case for unnumbered.
*/
is_unnum0 = 1;
}
- /* Reject requests/replies with our local interface address. */
- if (FIB_ENTRY_FLAG_LOCAL & src_flags)
- {
- error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
- goto drop2;
- }
-
dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
fib_entry_get_prefix (dst_fei, &pfx0);
if_addr0 = &pfx0.fp_addr.ip4;