aboutsummaryrefslogtreecommitdiffstats
path: root/vnet/vnet/gre/gre.c
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2016-10-08 13:03:40 +0100
committerDave Barach <openvpp@barachs.net>2016-10-14 13:50:39 +0000
commitb80c536e34b610ca77cd84448754e4bd9c46cf68 (patch)
treed7a868cdd657a3a54ff9eef76bfe3e7e4678e6d3 /vnet/vnet/gre/gre.c
parent3ae1a91430a341cd9ca96023e4fb619efe7cac7e (diff)
FIB2.0: Adjacency complete pull model (VPP-487)
Change the adjacency completion model to pull not push. A complete adjacency has a rewirte string, an incomplete one does not. the re-write string for a peer comes either from a discovery protocol (i.e. ARP/ND) or can be directly derived from the link type (i.e. GRE tunnels). Which method it is, is interface type specific. For each packet type sent on a link to a peer there is a corresponding adjacency. For example, if there is a peer 10.0.0.1 on Eth0 and we need to send to it IPv4 and MPLS packets, there will be two adjacencies; one for the IPv4 and one for the MPLS packets. The adjacencies are thus distinguished by the packets the carry, this is known as the adjacency's 'link-type'. It is not an L3 packet type, since the adjacency can have a link type of Ethernet (for L2 over GRE). The discovery protocols are not aware of all the link types required - only the FIB is. the FIB will create adjacencies as and when they are required, and it is thus then desirable to 'pull' from the discovery protocol the re-write required. The alternative (that we have now) is that the discovery protocol pushes (i.e. creates) adjacencies for each link type - this creates more adjacencies than we need. To pull, FIB now requests from the interface-type to 'complete' the adjacency. The interface can then delegate to the discovery protocol (on ethernet links) or directly build the re-write (i.e on GRE). Change-Id: I61451789ae03f26b1012d8d6524007b769b6c6ee Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'vnet/vnet/gre/gre.c')
-rw-r--r--vnet/vnet/gre/gre.c243
1 files changed, 75 insertions, 168 deletions
diff --git a/vnet/vnet/gre/gre.c b/vnet/vnet/gre/gre.c
index aa6fca0f27d..a4b3f9fc228 100644
--- a/vnet/vnet/gre/gre.c
+++ b/vnet/vnet/gre/gre.c
@@ -17,7 +17,7 @@
#include <vnet/vnet.h>
#include <vnet/gre/gre.h>
-#include <vnet/adj/adj.h>
+#include <vnet/adj/adj_midchain.h>
gre_main_t gre_main;
@@ -162,133 +162,95 @@ unformat_gre_header (unformat_input_t * input, va_list * args)
return 1;
}
-static uword gre_set_rewrite (vnet_main_t * vnm,
- u32 sw_if_index,
- u32 l3_type,
- void * dst_address,
- void * rewrite,
- uword max_rewrite_bytes)
+static int
+gre_proto_from_vnet_link (vnet_link_t link)
{
- /*
- * Conundrum: packets from tun/tap destined for the tunnel
- * actually have this rewrite applied. Transit packets do not.
- * To make the two cases equivalent, don't generate a
- * rewrite here, build the entire header in the fast path.
- */
- return 0;
-
-#ifdef THINGS_WORKED_AS_ONE_MIGHT_LIKE
- ip4_and_gre_header_t * h = rewrite;
- gre_protocol_t protocol;
-
- if (max_rewrite_bytes < sizeof (h[0]))
- return 0;
-
- switch (l3_type) {
-#define _(a,b) case VNET_L3_PACKET_TYPE_##a: protocol = GRE_PROTOCOL_##b; break
- _ (IP4, ip4);
- _ (IP6, ip6);
-#undef _
- default:
- return 0;
- }
-
- memset (h, 0, sizeof (*h));
- h->ip4.ip_version_and_header_length = 0x45;
- h->ip4.ttl = 64;
- h->ip4.protocol = IP_PROTOCOL_GRE;
- h->gre.protocol = clib_host_to_net_u16 (protocol);
-
- return sizeof (h[0]);
-#endif
+ switch (link)
+ {
+ case VNET_LINK_IP4:
+ return (GRE_PROTOCOL_ip4);
+ case VNET_LINK_IP6:
+ return (GRE_PROTOCOL_ip6);
+ case VNET_LINK_MPLS:
+ return (GRE_PROTOCOL_mpls_unicast);
+ case VNET_LINK_ETHERNET:
+ return (GRE_PROTOCOL_teb);
+ case VNET_LINK_ARP:
+ return (GRE_PROTOCOL_arp);
+ }
+ ASSERT(0);
+ return (GRE_PROTOCOL_ip4);
}
-static uword
-gre_interface_tx (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame)
+static u8*
+gre_build_rewrite (vnet_main_t * vnm,
+ u32 sw_if_index,
+ vnet_link_t link_type,
+ const void *dst_address)
{
gre_main_t * gm = &gre_main;
- u32 next_index;
- u32 * from, * to_next, n_left_from, n_left_to_next;
- vnet_interface_output_runtime_t * rd = (void *) node->runtime_data;
- gre_tunnel_t *t = pool_elt_at_index (gm->tunnels, rd->dev_instance);
-
- /* Vector of buffer / pkt indices we're supposed to process */
- from = vlib_frame_vector_args (frame);
-
- /* Number of buffers / pkts */
- n_left_from = frame->n_vectors;
-
- /* Speculatively send the first buffer to the last disposition we used */
- next_index = node->cached_next_index;
-
- while (n_left_from > 0)
- {
- /* set up to enqueue to our disposition with index = next_index */
- vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+ ip4_and_gre_header_t * h;
+ u8* rewrite = NULL;
+ gre_tunnel_t *t;
+ u32 ti;
- /*
- * FIXME DUAL LOOP
- */
+ ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
- while (n_left_from > 0 && n_left_to_next > 0)
- {
- u32 bi0, adj_index0, next0;
- const ip_adjacency_t * adj0;
- const dpo_id_t *dpo0;
- ip4_header_t * ip0;
- vlib_buffer_t * b0;
+ if (~0 == ti)
+ /* not one of ours */
+ return (0);
- bi0 = from[0];
- to_next[0] = bi0;
- from += 1;
- to_next += 1;
- n_left_from -= 1;
- n_left_to_next -= 1;
+ t = pool_elt_at_index(gm->tunnels, ti);
- b0 = vlib_get_buffer(vm, bi0);
- ip0 = vlib_buffer_get_current (b0);
+ vec_validate(rewrite, sizeof(*h)-1);
+ h = (ip4_and_gre_header_t*)rewrite;
+ h->gre.protocol = clib_host_to_net_u16(gre_proto_from_vnet_link(link_type));
- /* Fixup the checksum and len fields in the GRE tunnel encap
- * that was applied at the midchain node */
- ip0->length =
- clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
- ip0->checksum = ip4_header_checksum (ip0);
+ h->ip4.ip_version_and_header_length = 0x45;
+ h->ip4.ttl = 254;
+ h->ip4.protocol = IP_PROTOCOL_GRE;
+ /* fixup ip4 header length and checksum after-the-fact */
+ h->ip4.src_address.as_u32 = t->tunnel_src.as_u32;
+ h->ip4.dst_address.as_u32 = t->tunnel_dst.as_u32;
+ h->ip4.checksum = ip4_header_checksum (&h->ip4);
- /* Follow the DPO on which the midchain is stacked */
- adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
- adj0 = adj_get(adj_index0);
- dpo0 = &adj0->sub_type.midchain.next_dpo;
- next0 = dpo0->dpoi_next_node;
- vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+ return (rewrite);
+}
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- gre_tx_trace_t *tr = vlib_add_trace (vm, node,
- b0, sizeof (*tr));
- tr->tunnel_id = t - gm->tunnels;
- tr->length = ip0->length;
- tr->src.as_u32 = ip0->src_address.as_u32;
- tr->dst.as_u32 = ip0->dst_address.as_u32;
- }
+void
+gre_fixup (vlib_main_t *vm,
+ ip_adjacency_t *adj,
+ vlib_buffer_t *b0)
+{
+ ip4_header_t * ip0;
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
- to_next, n_left_to_next,
- bi0, next0);
- }
+ ip0 = vlib_buffer_get_current (b0);
- vlib_put_next_frame (vm, node, next_index, n_left_to_next);
- }
+ /* Fixup the checksum and len fields in the GRE tunnel encap
+ * that was applied at the midchain node */
+ ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+ ip0->checksum = ip4_header_checksum (ip0);
+}
- vlib_node_increment_counter (vm, gre_input_node.index,
- GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
+void
+gre_update_adj (vnet_main_t * vnm,
+ u32 sw_if_index,
+ adj_index_t ai)
+{
+ adj_nbr_midchain_update_rewrite (ai, gre_fixup,
+ ADJ_MIDCHAIN_FLAG_NONE,
+ gre_build_rewrite(vnm, sw_if_index,
+ adj_get_link_type(ai),
+ NULL));
- return frame->n_vectors;
+ gre_tunnel_stack(ai);
}
+/**
+ * @brief TX function. Only called L2. L3 traffic uses the adj-midchains
+ */
static uword
-gre_l2_interface_tx (vlib_main_t * vm,
+gre_interface_tx (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
@@ -330,7 +292,7 @@ gre_l2_interface_tx (vlib_main_t * vm,
b0 = vlib_get_buffer(vm, bi0);
- vnet_buffer(b0)->ip.adj_index[VLIB_TX] = gt->adj_index[FIB_LINK_ETHERNET];
+ vnet_buffer(b0)->ip.adj_index[VLIB_TX] = gt->l2_adj_index;
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
@@ -356,38 +318,6 @@ gre_l2_interface_tx (vlib_main_t * vm,
return frame->n_vectors;
}
-static clib_error_t *
-gre_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
-{
- gre_main_t * gm = &gre_main;
- vnet_hw_interface_t * hi;
- gre_tunnel_t *t;
- u32 ti;
-
- hi = vnet_get_hw_interface (vnm, hw_if_index);
-
- if (NULL == gm->tunnel_index_by_sw_if_index ||
- hi->sw_if_index >= vec_len(gm->tunnel_index_by_sw_if_index))
- return (NULL);
-
- ti = gm->tunnel_index_by_sw_if_index[hi->sw_if_index];
-
- if (~0 == ti)
- /* not one of ours */
- return (NULL);
-
- t = pool_elt_at_index(gm->tunnels, ti);
-
- if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
- vnet_hw_interface_set_flags (vnm, hw_if_index, VNET_HW_INTERFACE_FLAG_LINK_UP);
- else
- vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */);
-
- gre_tunnel_stack(t);
-
- return /* no error */ 0;
-}
-
static u8 * format_gre_tunnel_name (u8 * s, va_list * args)
{
u32 dev_instance = va_arg (*args, u32);
@@ -403,15 +333,6 @@ static u8 * format_gre_device (u8 * s, va_list * args)
return s;
}
-static u8 * format_gre_l2_device (u8 * s, va_list * args)
-{
- u32 dev_instance = va_arg (*args, u32);
- CLIB_UNUSED (int verbose) = va_arg (*args, int);
-
- s = format (s, "GRE L2-tunnel: id %d\n", dev_instance);
- return s;
-}
-
VNET_DEVICE_CLASS (gre_device_class) = {
.name = "GRE tunnel device",
.format_device_name = format_gre_tunnel_name,
@@ -427,27 +348,13 @@ VNET_DEVICE_CLASS (gre_device_class) = {
VLIB_DEVICE_TX_FUNCTION_MULTIARCH (gre_device_class,
gre_interface_tx)
-VNET_DEVICE_CLASS (gre_l2_device_class) = {
- .name = "GRE L2 tunnel device",
- .format_device_name = format_gre_tunnel_name,
- .format_device = format_gre_l2_device,
- .format_tx_trace = format_gre_tx_trace,
- .tx_function = gre_l2_interface_tx,
- .admin_up_down_function = gre_interface_admin_up_down,
-#ifdef SOON
- .clear counter = 0;
-#endif
-};
-
-VLIB_DEVICE_TX_FUNCTION_MULTIARCH (gre_l2_device_class,
- gre_l2_interface_tx)
-
-
VNET_HW_INTERFACE_CLASS (gre_hw_interface_class) = {
.name = "GRE",
.format_header = format_gre_header_with_length,
.unformat_header = unformat_gre_header,
- .set_rewrite = gre_set_rewrite,
+ .build_rewrite = gre_build_rewrite,
+ .update_adjacency = gre_update_adj,
+ .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
};
static void add_protocol (gre_main_t * gm,