VPP/Introduction To IP Adjacency
Introduction
Each adjacency contains two "next index" fields. You can manipulate those fields to achieve different effects. Every adjacency represents an opportunity to divert traffic into an arbitrary subgraph.
Each successful ipv4 / ipv6 lookup yields an ip adjacency. Ipv4 and ipv6 adjacencies are identical, of type "ip_adjacency_t."
Ip4/6-lookup pushes matching traffic forward in the node graph via the graph arc given by adj->lookup_next_index. Typical ip4/6 rewrite adjacencies have adj->lookup_next_index = IP_LOOKUP_NEXT_REWRITE.
ip4/6-rewrite uses data from the ip_adjacency_t's vnet_rewrite_header to actually rewrite the packet. The rewrite header itself has a next_index, which tells ip4/6-rewrite where to send packets next. In the case of a typical rewrite adjacency, the rewrite header next index directs packets to the appropriate physical interface output node.
Use Case: Tunnel Encapsulation
It's easy to add a tunnel encapsulation by constructing an appropriate adjacency. We typically let adj->lookup_next_index = IP_LOOKUP_NEXT_REWRITE
, set up the rewrite string to encapsulate the tunneled packet with the appropriate ip4/6 header, and use the rewrite header next_index
to send packets to a "fixup" node - for example, to set the outer-ip packet length or fix the outer ipv4 header checksum. As of this writing, mpls-o-gre encapsulation works this way.
The fixup node sets outer-IP packet lengths, and fixes ip(v4) header checksums.
Here's a quick sketch of how to drive the internal APIs used to construct an ipv4 tunnel adjacency.
ip_adjacency_t adj; u8 * rewrite_data; ip4_address_t target_address; ip4_address_t zero; u32 adj_index; u32 inner_fib_index, outer_fib_index; zero.as_u32 = 0; /* Construct an adjacency template */ memset(&adj, 0, sizeof (adj)); adj.explicit_fib_index = ~0; adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE; /* * Construct the rewrite string in a u8 * vector * * The rewrite string begins with 0x45000000 - an unrouted ip4 * datagram with no options and a length of zero. Compute the * ip4 checksum with length = 0, and use the standard incremental * checksum fandango to adjust it in my_post_rewrite... * * my_post_rewrite is expected to send traffic to ip4-lookup. */ rewrite_data = my_tunnel_rewrite (mm, tp); /* Add rewrite header data to the template */ vnet_rewrite_for_tunnel (vnm, outer_fib_index /* rewrite sets tx_sw_if_index => outer fib index */, ip4_rewrite_node.index, /* vanilla rewrite */ my_post_rewrite_node.index, /* tunnel-specific post-rewrite node */ &adj.rewrite_header, rewrite_data, vec_len(rewrite_data)); /* Create an adjacency from the adjacency template */ ip_add_adjacency (lm, &adj, 1 /* one adj */, &adj_index); /* Add the adjacency to the indicated FIB */ ip4_add_del_route_next_hop (im, IP4_ROUTE_FLAG_ADD, &target_address, mask_width, &zero /* no next hop */, (u32)~0 /* next_hop_sw_if_index */, 1 /* weight */, adj_index /* our new adjacency */, inner_fib_index /* lookup FIB index, 0 is the default FIB */);
Note that if you follow the "typical" tunnel encapsulation process, you won't deal with these mechanics directly. The example shown above will help create completely arbitrary Forwarding Information Base (FIB) lookup / ip adjacency-based behaviors.
Other Use Cases
The tunnel encap use-case more or less follows the standard "lookup, rewrite, ship-it" pattern. We can achieve many other effects by using the degrees of freedom built into the underlying scheme.
Let's say that we want to build a plug-in to inspect traffic sent to a particular subnet. At plugin init time - using VLIB_INIT_FUNCTION
- we add a graph arc from ip4_lookup_node to my_plugin_node:
node_index = vlib_node_add_next (vm, ip4_lookup_node.index, my_plugin_node.index);
An adjacency with adj->lookup_next_index = node_index
will divert traffic to my_plugin_node as desired.
My_plugin_node can return traffic to its regularly-scheduled graph trajectory by enqueueing to ip4/6-rewrite, or not.
Note that the plug-in can track down and patch existing adjacencies by performing an FIB lookup, and then assigning the following setting:
adj->lookup_next_index = my_plugin_node.index
Depending on how "my_plugin_node" works - and where it sends packets in the graph - one can use the remainder of the ip_adjacency_t
object in arbitrary ways. Burying object indicies in unused rewrite space could work, as well as other uses.