Create macro for next_nodes used in lookup family of nodes
[vpp.git] / vnet / vnet / ip / ip4_forward.c
index 6bfe1cf..ef3624a 100644 (file)
@@ -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
@@ -1261,27 +1301,14 @@ ip4_sw_interface_add_del (vnet_main_t * vnm,
 
 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
 
+
 VLIB_REGISTER_NODE (ip4_lookup_node) = {
   .function = ip4_lookup,
   .name = "ip4-lookup",
   .vector_size = sizeof (u32),
 
   .n_next_nodes = IP_LOOKUP_N_NEXT,
-  .next_nodes = {
-    [IP_LOOKUP_NEXT_MISS] = "ip4-miss",
-    [IP_LOOKUP_NEXT_DROP] = "ip4-drop",
-    [IP_LOOKUP_NEXT_PUNT] = "ip4-punt",
-    [IP_LOOKUP_NEXT_LOCAL] = "ip4-local",
-    [IP_LOOKUP_NEXT_ARP] = "ip4-arp",
-    [IP_LOOKUP_NEXT_REWRITE] = "ip4-rewrite-transit",
-    [IP_LOOKUP_NEXT_CLASSIFY] = "ip4-classify",
-    [IP_LOOKUP_NEXT_MAP] = "ip4-map",
-    [IP_LOOKUP_NEXT_MAP_T] = "ip4-map-t",
-    [IP_LOOKUP_NEXT_SIXRD] = "ip4-sixrd",
-    [IP_LOOKUP_NEXT_HOP_BY_HOP] = "ip4-hop-by-hop",
-    [IP_LOOKUP_NEXT_ADD_HOP_BY_HOP] = "ip4-add-hop-by-hop", 
-    [IP_LOOKUP_NEXT_POP_HOP_BY_HOP] = "ip4-pop-hop-by-hop", 
-  },
+  .next_nodes = IP4_LOOKUP_NEXT_NODES,
 };
 
 /* Global IP4 main. */
@@ -2084,6 +2111,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.
@@ -2935,21 +2966,7 @@ VLIB_REGISTER_NODE (ip4_lookup_multicast_node,static) = {
   .vector_size = sizeof (u32),
 
   .n_next_nodes = IP_LOOKUP_N_NEXT,
-  .next_nodes = {
-    [IP_LOOKUP_NEXT_MISS] = "ip4-miss",
-    [IP_LOOKUP_NEXT_DROP] = "ip4-drop",
-    [IP_LOOKUP_NEXT_PUNT] = "ip4-punt",
-    [IP_LOOKUP_NEXT_LOCAL] = "ip4-local",
-    [IP_LOOKUP_NEXT_ARP] = "ip4-arp",
-    [IP_LOOKUP_NEXT_REWRITE] = "ip4-rewrite-transit",
-    [IP_LOOKUP_NEXT_CLASSIFY] = "ip4-classify",
-    [IP_LOOKUP_NEXT_MAP] = "ip4-map",
-    [IP_LOOKUP_NEXT_MAP_T] = "ip4-map-t",
-    [IP_LOOKUP_NEXT_SIXRD] = "ip4-sixrd",
-    [IP_LOOKUP_NEXT_HOP_BY_HOP] = "ip4-hop-by-hop",
-    [IP_LOOKUP_NEXT_ADD_HOP_BY_HOP] = "ip4-add-hop-by-hop", 
-    [IP_LOOKUP_NEXT_POP_HOP_BY_HOP] = "ip4-pop-hop-by-hop", 
-  },
+  .next_nodes = IP4_LOOKUP_NEXT_NODES,
 };
 
 VLIB_REGISTER_NODE (ip4_multicast_node,static) = {