diff options
Diffstat (limited to 'src/vnet/mpls')
-rw-r--r-- | src/vnet/mpls/error.def | 1 | ||||
-rw-r--r-- | src/vnet/mpls/mpls_output.c | 70 |
2 files changed, 57 insertions, 14 deletions
diff --git a/src/vnet/mpls/error.def b/src/vnet/mpls/error.def index 34a46522894..9941b18baf4 100644 --- a/src/vnet/mpls/error.def +++ b/src/vnet/mpls/error.def @@ -20,6 +20,7 @@ mpls_error (UNKNOWN_PROTOCOL, "unknown protocol") mpls_error (UNSUPPORTED_VERSION, "unsupported version") mpls_error (PKTS_DECAP, "MPLS input packets decapsulated") mpls_error (PKTS_ENCAP, "MPLS output packets encapsulated") +mpls_error (PKTS_NEED_FRAG, "MPLS output packets needs fragmentation") mpls_error (NO_LABEL, "MPLS no label for fib/dst") mpls_error (TTL_EXPIRED, "MPLS ttl expired") mpls_error (S_NOT_SET, "MPLS s-bit not set") diff --git a/src/vnet/mpls/mpls_output.c b/src/vnet/mpls/mpls_output.c index 68577e711cc..5ede22aa410 100644 --- a/src/vnet/mpls/mpls_output.c +++ b/src/vnet/mpls/mpls_output.c @@ -19,6 +19,7 @@ #include <vnet/pg/pg.h> #include <vnet/ip/ip.h> #include <vnet/mpls/mpls.h> +#include <vnet/ip/ip_frag.h> typedef struct { /* Adjacency taken. */ @@ -26,8 +27,15 @@ typedef struct { u32 flow_hash; } mpls_output_trace_t; +typedef enum { + MPLS_OUTPUT_MODE, + MPLS_OUTPUT_MIDCHAIN_MODE +}mpls_output_mode_t; + #define foreach_mpls_output_next \ -_(DROP, "error-drop") +_(DROP, "error-drop") \ +_(IP4_FRAG, "ip4-frag") \ +_(IP6_FRAG, "ip6-frag") typedef enum { #define _(s,n) MPLS_OUTPUT_NEXT_##s, @@ -50,11 +58,36 @@ format_mpls_output_trace (u8 * s, va_list * args) return s; } +/* + * Save the mpls header length and adjust the current to ip header + */ +static inline u32 +set_mpls_fragmentation(vlib_buffer_t * p0, ip_adjacency_t * adj0) +{ + u32 next0; + + /* advance size of (all) mpls header to ip header before fragmenting */ + /* save the current pointing to first mpls header. */ + vnet_buffer (p0)->mpls.mpls_hdr_length = vnet_buffer(p0)->l3_hdr_offset - p0->current_data; + vlib_buffer_advance (p0, vnet_buffer (p0)->mpls.mpls_hdr_length); + + /* IP fragmentation */ + ip_frag_set_vnet_buffer (p0, adj0[0].rewrite_header.max_l3_packet_bytes, + IP4_FRAG_NEXT_MPLS_OUTPUT, + ((vnet_buffer (p0)->mpls.pyld_proto == DPO_PROTO_IP4) ? IP_FRAG_FLAG_IP4_HEADER:IP_FRAG_FLAG_IP6_HEADER)); + + /* Tell ip_frag to retain certain mpls parameters after fragmentation of mpls packet */ + vnet_buffer (p0)->ip_frag.flags = (vnet_buffer (p0)->ip_frag.flags | IP_FRAG_FLAG_MPLS_HEADER); + next0 = (vnet_buffer (p0)->mpls.pyld_proto == DPO_PROTO_IP4)? MPLS_OUTPUT_NEXT_IP4_FRAG:MPLS_OUTPUT_NEXT_IP6_FRAG; + + return next0; +} + static inline uword mpls_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, - int is_midchain) + mpls_output_mode_t mode) { u32 n_left_from, next_index, * from, * to_next, thread_index; vlib_node_runtime_t * error_node; @@ -162,8 +195,11 @@ mpls_output_inline (vlib_main_t * vm, } else { - error0 = IP4_ERROR_MTU_EXCEEDED; - next0 = MPLS_OUTPUT_NEXT_DROP; + error0 = IP4_ERROR_MTU_EXCEEDED; + next0 = set_mpls_fragmentation (p0, adj0); + vlib_node_increment_counter (vm, mpls_output_node.index, + MPLS_ERROR_PKTS_NEED_FRAG, + 1); } if (PREDICT_TRUE(vlib_buffer_length_in_chain (vm, p1) <= adj1[0].rewrite_header.max_l3_packet_bytes)) @@ -182,10 +218,13 @@ mpls_output_inline (vlib_main_t * vm, } else { - error1 = IP4_ERROR_MTU_EXCEEDED; - next1 = MPLS_OUTPUT_NEXT_DROP; + error1 = IP4_ERROR_MTU_EXCEEDED; + next1 = set_mpls_fragmentation (p1, adj1); + vlib_node_increment_counter (vm, mpls_output_node.index, + MPLS_ERROR_PKTS_NEED_FRAG, + 1); } - if (is_midchain) + if (mode == MPLS_OUTPUT_MIDCHAIN_MODE) { adj0->sub_type.midchain.fixup_func (vm, adj0, p0, @@ -221,7 +260,7 @@ mpls_output_inline (vlib_main_t * vm, while (n_left_from > 0 && n_left_to_next > 0) { ip_adjacency_t * adj0; - mpls_unicast_header_t *hdr0; + mpls_unicast_header_t *hdr0; vlib_buffer_t * p0; u32 pi0, adj_index0, next0, error0; word rw_len0; @@ -233,7 +272,7 @@ mpls_output_inline (vlib_main_t * vm, adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; adj0 = adj_get(adj_index0); - hdr0 = vlib_buffer_get_current (p0); + hdr0 = vlib_buffer_get_current (p0); /* Guess we are only writing on simple Ethernet header. */ vnet_rewrite_one_header (adj0[0], hdr0, @@ -268,10 +307,13 @@ mpls_output_inline (vlib_main_t * vm, } else { - error0 = IP4_ERROR_MTU_EXCEEDED; - next0 = MPLS_OUTPUT_NEXT_DROP; + error0 = IP4_ERROR_MTU_EXCEEDED; + next0 = set_mpls_fragmentation (p0, adj0); + vlib_node_increment_counter (vm, mpls_output_node.index, + MPLS_ERROR_PKTS_NEED_FRAG, + 1); } - if (is_midchain) + if (mode == MPLS_OUTPUT_MIDCHAIN_MODE) { adj0->sub_type.midchain.fixup_func (vm, adj0, p0, @@ -317,7 +359,7 @@ VLIB_NODE_FN (mpls_output_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) { - return (mpls_output_inline(vm, node, from_frame, /* is_midchain */ 0)); + return (mpls_output_inline(vm, node, from_frame, MPLS_OUTPUT_MODE)); } VLIB_REGISTER_NODE (mpls_output_node) = { @@ -341,7 +383,7 @@ VLIB_NODE_FN (mpls_midchain_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) { - return (mpls_output_inline(vm, node, from_frame, /* is_midchain */ 1)); + return (mpls_output_inline(vm, node, from_frame, MPLS_OUTPUT_MIDCHAIN_MODE)); } VLIB_REGISTER_NODE (mpls_midchain_node) = { |