|
|
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.
| |