Difference between revisions of "VPP/IP adjacency introduction"

From fd.io
< VPP
Jump to: navigation, search
(Created page with "=== IP adjacency introduction === Each adjacency contains two "next index" fields which one can manipulate to achieve different effects. Every adjacency represents an opportu...")
 
(remove content - more up-to-date content on another page)
 
Line 1: Line 1:
=== IP adjacency introduction ===
 
  
Each adjacency contains two "next index" fields which one can manipulate 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.
 
 
==== Tunnel Encapsulation Use Case ====
 
 
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, e.g. to set the outer-ip packet length / 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 "Tunnel Encapsulation HowTo" play-book, you won't deal with these mechanics directly. The example shown above will help create completely arbitrary FIB lookup / ip adjacency-based behaviors.
 
 
==== Arbitrary use-cases ====
 
 
The tunnel encap use-case more or less follows the stock "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 - via a VLIB_INIT_FUNCTION -  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 a FIB lookup, then 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 in arbitrary ways. Burying object indicies in unused rewrite space could work. And so on, and so forth.
 

Latest revision as of 03:53, 9 January 2016