diff options
Diffstat (limited to 'vnet/vnet/gre/node.c')
-rw-r--r-- | vnet/vnet/gre/node.c | 211 |
1 files changed, 164 insertions, 47 deletions
diff --git a/vnet/vnet/gre/node.c b/vnet/vnet/gre/node.c index d5ea4b65ddb..b55f5511916 100644 --- a/vnet/vnet/gre/node.c +++ b/vnet/vnet/gre/node.c @@ -18,6 +18,7 @@ #include <vlib/vlib.h> #include <vnet/pg/pg.h> #include <vnet/gre/gre.h> +#include <vnet/mpls/mpls.h> #include <vppinfra/sparse_vec.h> #define foreach_gre_input_next \ @@ -25,7 +26,8 @@ _(PUNT, "error-punt") \ _(DROP, "error-drop") \ _(ETHERNET_INPUT, "ethernet-input") \ _(IP4_INPUT, "ip4-input") \ -_(IP6_INPUT, "ip6-input") +_(IP6_INPUT, "ip6-input") \ +_(MPLS_INPUT, "mpls-input") typedef enum { #define _(s,n) GRE_INPUT_NEXT_##s, @@ -66,13 +68,17 @@ gre_input (vlib_main_t * vm, vlib_frame_t * from_frame) { gre_main_t * gm = &gre_main; + mpls_main_t * mm = &mpls_main; + ip4_main_t * ip4m = &ip4_main; gre_input_runtime_t * rt = (void *) node->runtime_data; __attribute__((unused)) u32 n_left_from, next_index, * from, * to_next; u64 cached_tunnel_key = (u64) ~0; - u32 cached_tunnel_sw_if_index = 0, tunnel_sw_if_index; + u32 cached_tunnel_sw_if_index = 0, tunnel_sw_if_index = 0; u32 cached_tunnel_fib_index = 0, tunnel_fib_index; u32 cpu_index = os_get_cpu_number(); + u32 len; + vnet_interface_main_t *im = &gm->vnet_main->interface_main; from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; @@ -141,7 +147,7 @@ gre_input (vlib_main_t * vm, /* Index sparse array with network byte order. */ protocol0 = h0->protocol; protocol1 = h1->protocol; - sparse_vec_index2 (rt->next_by_protocol, protocol0, protocol1, + sparse_vec_index2 (rt->next_by_protocol, protocol0, protocol1, &i0, &i1); next0 = vec_elt(rt->next_by_protocol, i0); next1 = vec_elt(rt->next_by_protocol, i1); @@ -154,10 +160,10 @@ gre_input (vlib_main_t * vm, version1 = clib_net_to_host_u16 (h1->flags_and_version); verr1 = version1 & GRE_VERSION_MASK; - b0->error = verr0 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION] + b0->error = verr0 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION] : b0->error; next0 = verr0 ? GRE_INPUT_NEXT_DROP : next0; - b1->error = verr1 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION] + b1->error = verr1 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION] : b1->error; next1 = verr1 ? GRE_INPUT_NEXT_DROP : next1; @@ -176,7 +182,6 @@ gre_input (vlib_main_t * vm, gre_tunnel_t * t; uword * p; - ip4_main_t * ip4m = &ip4_main; p = hash_get (gm->tunnel_by_key, key); if (!p) { @@ -199,19 +204,56 @@ gre_input (vlib_main_t * vm, tunnel_sw_if_index = cached_tunnel_sw_if_index; tunnel_fib_index = cached_tunnel_fib_index; } + } + else if (PREDICT_TRUE(next0 == GRE_INPUT_NEXT_MPLS_INPUT)) + { + u64 key = ((u64)(vnet_buffer(b0)->gre.dst) << 32) | + (u64)(vnet_buffer(b0)->gre.src); + + if (cached_tunnel_key != key) + { + vnet_hw_interface_t * hi; + mpls_gre_tunnel_t * t; + uword * p; - u32 len = vlib_buffer_length_in_chain (vm, b0); - vnet_interface_main_t *im = &gm->vnet_main->interface_main; - vlib_increment_combined_counter (im->combined_sw_if_counters - + VNET_INTERFACE_COUNTER_RX, - cpu_index, - tunnel_sw_if_index, - 1 /* packets */, - len /* bytes */); - - vnet_buffer(b0)->sw_if_index[VLIB_TX] = tunnel_fib_index; - vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index; + p = hash_get (gm->tunnel_by_key, key); + if (!p) + { + next0 = GRE_INPUT_NEXT_DROP; + b0->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL]; + goto drop0; + } + t = pool_elt_at_index (mm->gre_tunnels, p[0]); + hi = vnet_get_hw_interface (gm->vnet_main, + t->hw_if_index); + tunnel_sw_if_index = hi->sw_if_index; + tunnel_fib_index = vec_elt (ip4m->fib_index_by_sw_if_index, + tunnel_sw_if_index); + + cached_tunnel_sw_if_index = tunnel_sw_if_index; + cached_tunnel_fib_index = tunnel_fib_index; + } + else + { + tunnel_sw_if_index = cached_tunnel_sw_if_index; + tunnel_fib_index = cached_tunnel_fib_index; + } } + else + { + next0 = GRE_INPUT_NEXT_DROP; + goto drop0; + } + len = vlib_buffer_length_in_chain (vm, b0); + vlib_increment_combined_counter (im->combined_sw_if_counters + + VNET_INTERFACE_COUNTER_RX, + cpu_index, + tunnel_sw_if_index, + 1 /* packets */, + len /* bytes */); + + vnet_buffer(b0)->sw_if_index[VLIB_TX] = tunnel_fib_index; + vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index; drop0: if (PREDICT_FALSE(next1 == GRE_INPUT_NEXT_IP4_INPUT @@ -227,7 +269,6 @@ drop0: gre_tunnel_t * t; uword * p; - ip4_main_t * ip4m = &ip4_main; p = hash_get (gm->tunnel_by_key, key); if (!p) { @@ -250,23 +291,62 @@ drop0: tunnel_sw_if_index = cached_tunnel_sw_if_index; tunnel_fib_index = cached_tunnel_fib_index; } + } + else if (PREDICT_TRUE(next1 == GRE_INPUT_NEXT_MPLS_INPUT)) + { + u64 key = ((u64)(vnet_buffer(b1)->gre.dst) << 32) | + (u64)(vnet_buffer(b1)->gre.src); - u32 len = vlib_buffer_length_in_chain (vm, b1); - vnet_interface_main_t *im = &gm->vnet_main->interface_main; - vlib_increment_combined_counter (im->combined_sw_if_counters - + VNET_INTERFACE_COUNTER_RX, - cpu_index, - tunnel_sw_if_index, - 1 /* packets */, - len /* bytes */); - - vnet_buffer(b1)->sw_if_index[VLIB_TX] = tunnel_fib_index; - vnet_buffer(b1)->sw_if_index[VLIB_RX] = tunnel_sw_if_index; + if (cached_tunnel_key != key) + { + vnet_hw_interface_t * hi; + mpls_gre_tunnel_t * t; + uword * p; + + ip4_main_t * ip4m = &ip4_main; + p = hash_get (gm->tunnel_by_key, key); + if (!p) + { + next1 = GRE_INPUT_NEXT_DROP; + b1->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL]; + goto drop1; + } + t = pool_elt_at_index (mm->gre_tunnels, p[0]); + hi = vnet_get_hw_interface (gm->vnet_main, + t->hw_if_index); + tunnel_sw_if_index = hi->sw_if_index; + tunnel_fib_index = vec_elt (ip4m->fib_index_by_sw_if_index, + tunnel_sw_if_index); + + cached_tunnel_sw_if_index = tunnel_sw_if_index; + cached_tunnel_fib_index = tunnel_fib_index; + } + else + { + tunnel_sw_if_index = cached_tunnel_sw_if_index; + tunnel_fib_index = cached_tunnel_fib_index; + } } + else + { + next1 = GRE_INPUT_NEXT_DROP; + goto drop1; + } + len = vlib_buffer_length_in_chain (vm, b1); + vlib_increment_combined_counter (im->combined_sw_if_counters + + VNET_INTERFACE_COUNTER_RX, + cpu_index, + tunnel_sw_if_index, + 1 /* packets */, + len /* bytes */); + + vnet_buffer(b1)->sw_if_index[VLIB_TX] = tunnel_fib_index; + vnet_buffer(b1)->sw_if_index[VLIB_RX] = tunnel_sw_if_index; + drop1: - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { - gre_rx_trace_t *tr = vlib_add_trace (vm, node, + gre_rx_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); tr->tunnel_id = ~0; tr->length = ip0->length; @@ -274,9 +354,9 @@ drop1: tr->dst.as_u32 = ip0->dst_address.as_u32; } - if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) + if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) { - gre_rx_trace_t *tr = vlib_add_trace (vm, node, + gre_rx_trace_t *tr = vlib_add_trace (vm, node, b1, sizeof (*tr)); tr->tunnel_id = ~0; tr->length = ip1->length; @@ -336,6 +416,7 @@ drop1: /* For IP payload we need to find source interface so we can increase counters and help forward node to pick right FIB */ + /* RPF check for ip4/ip6 input */ if (PREDICT_FALSE(next0 == GRE_INPUT_NEXT_IP4_INPUT || next0 == GRE_INPUT_NEXT_IP6_INPUT || next0 == GRE_INPUT_NEXT_ETHERNET_INPUT)) @@ -349,7 +430,6 @@ drop1: gre_tunnel_t * t; uword * p; - ip4_main_t * ip4m = &ip4_main; p = hash_get (gm->tunnel_by_key, key); if (!p) { @@ -372,26 +452,63 @@ drop1: tunnel_sw_if_index = cached_tunnel_sw_if_index; tunnel_fib_index = cached_tunnel_fib_index; } + } + else if (PREDICT_TRUE(next0 == GRE_INPUT_NEXT_MPLS_INPUT)) + { + u64 key = ((u64)(vnet_buffer(b0)->gre.dst) << 32) | + (u64)(vnet_buffer(b0)->gre.src); - u32 len = vlib_buffer_length_in_chain (vm, b0); - vnet_interface_main_t *im = &gm->vnet_main->interface_main; - vlib_increment_combined_counter (im->combined_sw_if_counters - + VNET_INTERFACE_COUNTER_RX, - cpu_index, - tunnel_sw_if_index, - 1 /* packets */, - len /* bytes */); - - vnet_buffer(b0)->sw_if_index[VLIB_TX] = tunnel_fib_index; - vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index; + if (cached_tunnel_key != key) + { + vnet_hw_interface_t * hi; + mpls_gre_tunnel_t * t; + uword * p; + + p = hash_get (gm->tunnel_by_key, key); + if (!p) + { + next0 = GRE_INPUT_NEXT_DROP; + b0->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL]; + goto drop; + } + t = pool_elt_at_index (mm->gre_tunnels, p[0]); + hi = vnet_get_hw_interface (gm->vnet_main, + t->hw_if_index); + tunnel_sw_if_index = hi->sw_if_index; + tunnel_fib_index = vec_elt (ip4m->fib_index_by_sw_if_index, + tunnel_sw_if_index); + + cached_tunnel_sw_if_index = tunnel_sw_if_index; + cached_tunnel_fib_index = tunnel_fib_index; + } + else + { + tunnel_sw_if_index = cached_tunnel_sw_if_index; + tunnel_fib_index = cached_tunnel_fib_index; + } + } + else + { + next0 = GRE_INPUT_NEXT_DROP; + goto drop; } + len = vlib_buffer_length_in_chain (vm, b0); + vlib_increment_combined_counter (im->combined_sw_if_counters + + VNET_INTERFACE_COUNTER_RX, + cpu_index, + tunnel_sw_if_index, + 1 /* packets */, + len /* bytes */); + + vnet_buffer(b0)->sw_if_index[VLIB_TX] = tunnel_fib_index; + vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index; drop: if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { gre_rx_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); - tr->tunnel_id = ~0; + tr->tunnel_id = tunnel_sw_if_index; tr->length = ip0->length; tr->src.as_u32 = ip0->src_address.as_u32; tr->dst.as_u32 = ip0->dst_address.as_u32; @@ -509,7 +626,7 @@ static clib_error_t * gre_input_init (vlib_main_t * vm) ASSERT(ip4_input); ip6_input = vlib_get_node_by_name (vm, (u8 *)"ip6-input"); ASSERT(ip6_input); - mpls_unicast_input = vlib_get_node_by_name (vm, (u8 *)"mpls-gre-input"); + mpls_unicast_input = vlib_get_node_by_name (vm, (u8 *)"mpls-input"); ASSERT(mpls_unicast_input); gre_register_input_protocol (vm, GRE_PROTOCOL_teb, |