aboutsummaryrefslogtreecommitdiffstats
path: root/vnet/vnet/ethernet/arp.c
diff options
context:
space:
mode:
authorDamjan Marion <damarion@cisco.com>2016-03-29 13:18:17 +0200
committerGerrit Code Review <gerrit@fd.io>2016-04-01 10:38:42 +0000
commit102ec52bc41c630f011884250e0f20ea49ac6d33 (patch)
tree089e710419690fb4714d765ba4dc8f3288a67d4d /vnet/vnet/ethernet/arp.c
parentb02e49c4be32c5092f6948d40f84a9e2aeae66e6 (diff)
Add support for installing ipv4 routes via unresolved next hop
Change-Id: I71f3ba0c8192fe0ac3b5b81fb1275b64ec02876a Signed-off-by: Damjan Marion <damarion@cisco.com>
Diffstat (limited to 'vnet/vnet/ethernet/arp.c')
-rw-r--r--vnet/vnet/ethernet/arp.c195
1 files changed, 181 insertions, 14 deletions
diff --git a/vnet/vnet/ethernet/arp.c b/vnet/vnet/ethernet/arp.c
index 3eb6a11391e..205023a6ffb 100644
--- a/vnet/vnet/ethernet/arp.c
+++ b/vnet/vnet/ethernet/arp.c
@@ -35,8 +35,11 @@ typedef struct {
u16 flags;
#define ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC (1 << 0)
+#define ETHERNET_ARP_IP4_ENTRY_FLAG_GLEAN (2 << 0)
u64 cpu_time_last_updated;
+
+ u32 * adjacencies;
} ethernet_arp_ip4_entry_t;
typedef struct {
@@ -210,22 +213,31 @@ static u8 * format_ethernet_arp_ip4_entry (u8 * s, va_list * va)
ethernet_arp_ip4_entry_t * e = va_arg (*va, ethernet_arp_ip4_entry_t *);
vnet_sw_interface_t * si;
ip4_fib_t * fib;
+ u8 * flags = 0;
if (! e)
- return format (s, "%=12s%=6s%=16s%=4s%=20s%=24s", "Time", "FIB", "IP4",
- "Static", "Ethernet", "Interface");
+ return format (s, "%=12s%=6s%=16s%=6s%=20s%=24s", "Time", "FIB", "IP4",
+ "Flags", "Ethernet", "Interface");
fib = find_ip4_fib_by_table_index_or_id (&ip4_main, e->key.fib_index,
IP4_ROUTE_FLAG_FIB_INDEX);
si = vnet_get_sw_interface (vnm, e->key.sw_if_index);
- s = format (s, "%=12U%=6u%=16U%=4s%=20U%=25U",
+
+ if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_GLEAN)
+ flags = format(flags, "G");
+
+ if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC)
+ flags = format(flags, "S");
+
+ s = format (s, "%=12U%=6u%=16U%=6s%=20U%=24U",
format_vlib_cpu_time, vnm->vlib_main, e->cpu_time_last_updated,
fib->table_id,
format_ip4_address, &e->key.ip4_address,
- (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC) ? "S" : "",
+ flags ? (char *) flags : "",
format_ethernet_address, e->ethernet_address,
format_vnet_sw_interface_name, vnm, si);
+ vec_free(flags);
return s;
}
@@ -357,13 +369,15 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
ethernet_arp_ip4_over_ethernet_address_t * a = a_arg;
vlib_main_t * vm = vlib_get_main();
ip4_main_t * im = &ip4_main;
+ ip_lookup_main_t * lm = &im->lookup_main;
int make_new_arp_cache_entry=1;
uword * p;
ip4_add_del_route_args_t args;
- ip_adjacency_t adj;
+ ip_adjacency_t adj, * existing_adj;
pending_resolution_t * pr, * mc;
u32 next_index;
+ u32 adj_index;
fib_index = (fib_index != (u32)~0)
? fib_index : im->fib_index_by_sw_if_index[sw_if_index];
@@ -396,15 +410,40 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
&adj.rewrite_header,
sizeof (adj.rewrite_data));
- args.table_index_or_table_id = fib_index;
- args.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_ADD | IP4_ROUTE_FLAG_NEIGHBOR;
- args.dst_address = a->ip4;
- args.dst_address_length = 32;
- args.adj_index = ~0;
- args.add_adj = &adj;
- args.n_add_adj = 1;
+ /* result of this lookup should be next-hop adjacency */
+ adj_index = ip4_fib_lookup_with_table (im, fib_index, &a->ip4, 0);
+ existing_adj = ip_get_adjacency(lm, adj_index);
+
+ if (existing_adj->lookup_next_index == IP_LOOKUP_NEXT_ARP &&
+ existing_adj->arp.next_hop.ip4.as_u32 == a->ip4.as_u32)
+ {
+ u32 * ai;
+ u32 * adjs = vec_dup(e->adjacencies);
+ /* Update all adj assigned to this arp entry */
+ vec_foreach(ai, adjs)
+ {
+ int i;
+ ip_adjacency_t * uadj = ip_get_adjacency(lm, *ai);
+ for (i = 0; i < uadj->n_adj; i++)
+ if (uadj[i].lookup_next_index == IP_LOOKUP_NEXT_ARP &&
+ uadj[i].arp.next_hop.ip4.as_u32 == a->ip4.as_u32)
+ ip_update_adjacency (lm, *ai + i, &adj);
+ }
+ vec_free(adjs);
+ }
+ else
+ {
+ /* create new adj */
+ args.table_index_or_table_id = fib_index;
+ args.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_ADD | IP4_ROUTE_FLAG_NEIGHBOR;
+ args.dst_address = a->ip4;
+ args.dst_address_length = 32;
+ args.adj_index = ~0;
+ args.add_adj = &adj;
+ args.n_add_adj = 1;
+ ip4_add_del_route (im, &args);
+ }
- ip4_add_del_route (im, &args);
if (make_new_arp_cache_entry)
{
pool_get (am->ip4_entry_pool, e);
@@ -1242,11 +1281,88 @@ clib_error_t *ip4_set_arp_limit (u32 arp_limit)
return 0;
}
+static void
+arp_ip4_entry_del_adj(ethernet_arp_ip4_entry_t *e, u32 adj_index)
+{
+ int done = 0;
+ int i;
+
+ while (!done)
+ {
+ vec_foreach_index(i, e->adjacencies)
+ if (vec_elt(e->adjacencies, i) == adj_index)
+ {
+ vec_del1(e->adjacencies, i);
+ continue;
+ }
+ done = 1;
+ }
+}
+
+static void
+arp_ip4_entry_add_adj(ethernet_arp_ip4_entry_t *e, u32 adj_index)
+{
+ int i;
+ vec_foreach_index(i, e->adjacencies)
+ if (vec_elt(e->adjacencies, i) == adj_index)
+ return;
+ vec_add1(e->adjacencies, adj_index);
+}
+
+static void
+arp_add_del_adj_cb (struct ip_lookup_main_t * lm,
+ u32 adj_index,
+ ip_adjacency_t * adj,
+ u32 is_del)
+{
+ ethernet_arp_main_t * am = &ethernet_arp_main;
+ ip4_main_t * im = &ip4_main;
+ ethernet_arp_ip4_key_t k;
+ ethernet_arp_ip4_entry_t * e = 0;
+ uword * p;
+ u32 ai;
+
+ for(ai = adj->heap_handle; ai < adj->heap_handle + adj->n_adj ; ai++)
+ {
+ adj = ip_get_adjacency (lm, ai);
+ if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP && adj->arp.next_hop.ip4.as_u32)
+ {
+ k.sw_if_index = adj->rewrite_header.sw_if_index;
+ k.ip4_address.as_u32 = adj->arp.next_hop.ip4.as_u32;
+ k.fib_index = im->fib_index_by_sw_if_index[adj->rewrite_header.sw_if_index];
+ p = mhash_get (&am->ip4_entry_by_key, &k);
+ if (p)
+ e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
+ }
+ else
+ continue;
+
+ if (is_del)
+ {
+ if (!e)
+ clib_warning("Adjacency contains unknown ARP next hop %U (del)",
+ format_ip4_address, &adj->arp.next_hop);
+ else
+ arp_ip4_entry_del_adj(e, adj->heap_handle);
+ }
+ else /* add */
+ {
+ if (!e)
+ clib_warning("Adjacency contains unknown ARP next hop %U (add)",
+ format_ip4_address, &adj->arp.next_hop);
+ else
+ arp_ip4_entry_add_adj(e, adj->heap_handle);
+ }
+ }
+}
+
static clib_error_t * ethernet_arp_init (vlib_main_t * vm)
{
ethernet_arp_main_t * am = &ethernet_arp_main;
pg_node_t * pn;
clib_error_t * error;
+ ip4_main_t * im = &ip4_main;
+ ip_lookup_main_t * lm = &im->lookup_main;
if ((error = vlib_call_init_function (vm, ethernet_init)))
return error;
@@ -1283,7 +1399,9 @@ static clib_error_t * ethernet_arp_init (vlib_main_t * vm)
foreach_ethernet_arp_error
#undef _
}
-
+
+ ip_register_add_del_adjacency_callback(lm, arp_add_del_adj_cb);
+
return 0;
}
@@ -1474,6 +1592,55 @@ int vnet_proxy_arp_fib_reset (u32 fib_id)
return 0;
}
+u32
+vnet_arp_glean_add(u32 fib_index, void * next_hop_arg)
+{
+ ethernet_arp_main_t * am = &ethernet_arp_main;
+ ip4_main_t * im = &ip4_main;
+ ip_lookup_main_t * lm = &im->lookup_main;
+ ip4_address_t * next_hop = next_hop_arg;
+ ip_adjacency_t add_adj, *adj;
+ ip4_add_del_route_args_t args;
+ ethernet_arp_ip4_entry_t * e;
+ ethernet_arp_ip4_key_t k;
+ u32 adj_index;
+
+ adj_index = ip4_fib_lookup_with_table(im, fib_index, next_hop, 0);
+ adj = ip_get_adjacency(lm, adj_index);
+
+ if (!adj || adj->lookup_next_index != IP_LOOKUP_NEXT_ARP)
+ return ~0;
+
+ if (adj->arp.next_hop.ip4.as_u32 != 0)
+ return adj_index;
+
+ k.sw_if_index = adj->rewrite_header.sw_if_index;
+ k.fib_index = fib_index;
+ k.ip4_address.as_u32 = next_hop->as_u32;
+
+ if (mhash_get (&am->ip4_entry_by_key, &k))
+ return adj_index;
+
+ pool_get (am->ip4_entry_pool, e);
+ mhash_set (&am->ip4_entry_by_key, &k, e - am->ip4_entry_pool, /* old value */ 0);
+ e->key = k;
+ e->cpu_time_last_updated = clib_cpu_time_now ();
+ e->flags = ETHERNET_ARP_IP4_ENTRY_FLAG_GLEAN;
+
+ memset(&args, 0, sizeof(args));
+ memcpy(&add_adj, adj, sizeof(add_adj));
+ add_adj.arp.next_hop.ip4.as_u32 = next_hop->as_u32; /* install neighbor /32 route */
+ args.table_index_or_table_id = fib_index;
+ args.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_ADD| IP4_ROUTE_FLAG_NEIGHBOR;
+ args.dst_address.as_u32 = next_hop->as_u32;
+ args.dst_address_length = 32;
+ args.adj_index = ~0;
+ args.add_adj = &add_adj;
+ args.n_add_adj = 1;
+ ip4_add_del_route (im, &args);
+ return ip4_fib_lookup_with_table (im, fib_index, next_hop, 0);
+}
+
static clib_error_t *
ip_arp_add_del_command_fn (vlib_main_t * vm,
unformat_input_t * input,