diff options
Diffstat (limited to 'vnet/vnet/ip/ip4_forward.c')
-rw-r--r-- | vnet/vnet/ip/ip4_forward.c | 60 |
1 files changed, 52 insertions, 8 deletions
diff --git a/vnet/vnet/ip/ip4_forward.c b/vnet/vnet/ip/ip4_forward.c index 6bfe1cff2f2..e099cd9d047 100644 --- a/vnet/vnet/ip/ip4_forward.c +++ b/vnet/vnet/ip/ip4_forward.c @@ -242,7 +242,7 @@ void ip4_add_del_route (ip4_main_t * im, ip4_add_del_route_args_t * a) old_adj_index = fib->old_hash_values[0]; /* Avoid spurious reference count increments */ - if (old_adj_index == adj_index) + if (old_adj_index == adj_index && !(a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY)) { ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index); if (adj->share_count > 0) @@ -318,13 +318,29 @@ ip4_add_del_route_next_hop (ip4_main_t * im, /* Next hop must be known. */ if (! nh_result) { - vnm->api_errno = VNET_API_ERROR_NEXT_HOP_NOT_IN_FIB; - error = clib_error_return (0, "next-hop %U/32 not in FIB", - format_ip4_address, next_hop); - goto done; - } - nh_adj_index = *nh_result; - } + ip_adjacency_t * adj; + + nh_adj_index = ip4_fib_lookup_with_table (im, fib_index, + next_hop, 0); + adj = ip_get_adjacency (lm, nh_adj_index); + /* if ARP interface adjacencty is present, we need to + install ARP adjaceny for specific next hop */ + if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP && + adj->arp.next_hop.ip4.as_u32 == 0) + { + nh_adj_index = vnet_arp_glean_add(fib_index, next_hop); + } + else + { + vnm->api_errno = VNET_API_ERROR_NEXT_HOP_NOT_IN_FIB; + error = clib_error_return (0, "next-hop %U/32 not in FIB", + format_ip4_address, next_hop); + goto done; + } + } + else + nh_adj_index = *nh_result; + } } else { @@ -369,6 +385,29 @@ ip4_add_del_route_next_hop (ip4_main_t * im, goto done; } + /* Destination is not known and default weight is set so add route + to existing non-multipath adjacency */ + if (dst_adj_index == ~0 && next_hop_weight == 1 && next_hop_sw_if_index == ~0) + { + /* create new adjacency */ + ip4_add_del_route_args_t a; + a.table_index_or_table_id = fib_index; + a.flags = ((is_del ? IP4_ROUTE_FLAG_DEL : IP4_ROUTE_FLAG_ADD) + | IP4_ROUTE_FLAG_FIB_INDEX + | IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY + | (flags & (IP4_ROUTE_FLAG_NO_REDISTRIBUTE + | IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP))); + a.dst_address = dst_address[0]; + a.dst_address_length = dst_address_length; + a.adj_index = nh_adj_index; + a.add_adj = 0; + a.n_add_adj = 0; + + ip4_add_del_route (im, &a); + + goto done; + } + old_mp_adj_index = dst_adj ? dst_adj->heap_handle : ~0; if (! ip_multipath_adjacency_add_del_next_hop @@ -934,6 +973,7 @@ void ip4_adjacency_set_interface_route (vnet_main_t * vnm, n = IP_LOOKUP_NEXT_ARP; node_index = ip4_arp_node.index; adj->if_address_index = if_address_index; + adj->arp.next_hop.ip4.as_u32 = 0; packet_type = VNET_L3_PACKET_TYPE_ARP; } else @@ -2084,6 +2124,10 @@ ip4_arp (vlib_main_t * vm, adj0 = ip_get_adjacency (lm, adj_index0); ip0 = vlib_buffer_get_current (p0); + /* If packet destination is not local, send ARP to next hop */ + if (adj0->arp.next_hop.ip4.as_u32) + ip0->dst_address.data_u32 = adj0->arp.next_hop.ip4.as_u32; + /* * if ip4_rewrite_local applied the IP_LOOKUP_NEXT_ARP * rewrite to this packet, we need to skip it here. |