diff options
author | Neale Ranns <nranns@cisco.com> | 2018-02-23 05:29:09 -0800 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2018-03-09 11:59:58 +0000 |
commit | 31ed74407643595fdce206e9d7487108fb8b33ab (patch) | |
tree | c22c3703c30b7d457b858fe899f56e57613cbb52 /src/vnet/dpo | |
parent | 8f931a47b0fa58d5d33a792062650a42ff8bef70 (diff) |
MPLS Unifom mode
- support both pipe and uniform modes for all MPLS LSP
- all API programming for output-labels requires that the mode (and associated data) is specificed
- API changes in MPLS, BIER and IP are involved
- new DPO [sub] types for MPLS labels to handle the two modes.
Change-Id: I87b76401e996f10dfbdbe4552ff6b19af958783c
Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'src/vnet/dpo')
-rw-r--r-- | src/vnet/dpo/dpo.h | 8 | ||||
-rw-r--r-- | src/vnet/dpo/mpls_disposition.c | 316 | ||||
-rw-r--r-- | src/vnet/dpo/mpls_disposition.h | 15 | ||||
-rw-r--r-- | src/vnet/dpo/mpls_label_dpo.c | 1075 | ||||
-rw-r--r-- | src/vnet/dpo/mpls_label_dpo.h | 65 |
5 files changed, 1150 insertions, 329 deletions
diff --git a/src/vnet/dpo/dpo.h b/src/vnet/dpo/dpo.h index afee458c02f..4d484786fba 100644 --- a/src/vnet/dpo/dpo.h +++ b/src/vnet/dpo/dpo.h @@ -111,8 +111,8 @@ typedef enum dpo_type_t_ { DPO_LOOKUP, DPO_LISP_CP, DPO_CLASSIFY, - DPO_MPLS_LABEL, - DPO_MPLS_DISPOSITION, + DPO_MPLS_DISPOSITION_PIPE, + DPO_MPLS_DISPOSITION_UNIFORM, DPO_MFIB_ENTRY, DPO_INTERFACE_RX, DPO_INTERFACE_TX, @@ -146,8 +146,8 @@ typedef enum dpo_type_t_ { [DPO_REPLICATE] = "dpo-replicate", \ [DPO_LISP_CP] = "dpo-lisp-cp", \ [DPO_CLASSIFY] = "dpo-classify", \ - [DPO_MPLS_LABEL] = "dpo-mpls-label", \ - [DPO_MPLS_DISPOSITION] = "dpo-mpls-diposition", \ + [DPO_MPLS_DISPOSITION_PIPE] = "dpo-mpls-diposition-pipe", \ + [DPO_MPLS_DISPOSITION_UNIFORM] = "dpo-mpls-diposition-uniform", \ [DPO_MFIB_ENTRY] = "dpo-mfib-entry", \ [DPO_INTERFACE_RX] = "dpo-interface-rx", \ [DPO_INTERFACE_TX] = "dpo-interface-tx", \ diff --git a/src/vnet/dpo/mpls_disposition.c b/src/vnet/dpo/mpls_disposition.c index 77429de4116..2956e541d57 100644 --- a/src/vnet/dpo/mpls_disposition.c +++ b/src/vnet/dpo/mpls_disposition.c @@ -42,38 +42,55 @@ mpls_disp_dpo_get_index (mpls_disp_dpo_t *mdd) return (mdd - mpls_disp_dpo_pool); } -index_t +void mpls_disp_dpo_create (dpo_proto_t payload_proto, fib_rpf_id_t rpf_id, - const dpo_id_t *dpo) + fib_mpls_lsp_mode_t mode, + const dpo_id_t *parent, + dpo_id_t *dpo) { mpls_disp_dpo_t *mdd; + dpo_type_t dtype; mdd = mpls_disp_dpo_alloc(); mdd->mdd_payload_proto = payload_proto; mdd->mdd_rpf_id = rpf_id; - - dpo_stack(DPO_MPLS_DISPOSITION, + mdd->mdd_mode = mode; + dtype = (FIB_MPLS_LSP_MODE_PIPE == mode ? + DPO_MPLS_DISPOSITION_PIPE : + DPO_MPLS_DISPOSITION_UNIFORM); + + /* + * stack this disposition object on the parent given + */ + dpo_stack(dtype, mdd->mdd_payload_proto, &mdd->mdd_dpo, - dpo); - - return (mpls_disp_dpo_get_index(mdd)); + parent); + + /* + * set up the return DPO to refer to this object + */ + dpo_set(dpo, + dtype, + payload_proto, + mpls_disp_dpo_get_index(mdd)); } u8* format_mpls_disp_dpo (u8 *s, va_list *args) { - index_t index = va_arg (*args, index_t); - u32 indent = va_arg (*args, u32); + index_t index = va_arg(*args, index_t); + u32 indent = va_arg(*args, u32); mpls_disp_dpo_t *mdd; mdd = mpls_disp_dpo_get(index); - s = format(s, "mpls-disposition:[%d]:[%U]", + s = format(s, "mpls-disposition:[%d]:[%U, %U]", index, - format_dpo_proto, mdd->mdd_payload_proto); + format_dpo_proto, mdd->mdd_payload_proto, + format_fib_mpls_lsp_mode, mdd->mdd_mode); s = format(s, "\n%U", format_white_space, indent); s = format(s, "%U", format_dpo_id, &mdd->mdd_dpo, indent+2); @@ -116,25 +133,41 @@ typedef struct mpls_label_disposition_trace_t_ index_t mdd; } mpls_label_disposition_trace_t; -extern vlib_node_registration_t ip4_mpls_label_disposition_node; -extern vlib_node_registration_t ip6_mpls_label_disposition_node; +extern vlib_node_registration_t ip4_mpls_label_disposition_pipe_node; +extern vlib_node_registration_t ip6_mpls_label_disposition_pipe_node; +extern vlib_node_registration_t ip4_mpls_label_disposition_uniform_node; +extern vlib_node_registration_t ip6_mpls_label_disposition_uniform_node; always_inline uword mpls_label_disposition_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame, - u8 payload_is_ip4, - u8 payload_is_ip6) + vlib_node_runtime_t * node, + vlib_frame_t * from_frame, + u8 payload_is_ip4, + u8 payload_is_ip6, + fib_mpls_lsp_mode_t mode) { u32 n_left_from, next_index, * from, * to_next; vlib_node_runtime_t *error_node; if (payload_is_ip4) - error_node = vlib_node_get_runtime (vm, ip4_mpls_label_disposition_node.index); + { + if (FIB_MPLS_LSP_MODE_PIPE == mode) + error_node = + vlib_node_get_runtime(vm, ip4_mpls_label_disposition_pipe_node.index); + else + error_node = + vlib_node_get_runtime(vm, ip4_mpls_label_disposition_uniform_node.index); + } else - error_node = vlib_node_get_runtime (vm, ip6_mpls_label_disposition_node.index); - - from = vlib_frame_vector_args (from_frame); + { + if (FIB_MPLS_LSP_MODE_PIPE == mode) + error_node = + vlib_node_get_runtime(vm, ip6_mpls_label_disposition_uniform_node.index); + else + error_node = + vlib_node_get_runtime(vm, ip6_mpls_label_disposition_uniform_node.index); + } + from = vlib_frame_vector_args(from_frame); n_left_from = from_frame->n_vectors; next_index = node->cached_next_index; @@ -159,14 +192,14 @@ mpls_label_disposition_inline (vlib_main_t * vm, { vlib_buffer_t * p2, * p3; - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); + p2 = vlib_get_buffer(vm, from[2]); + p3 = vlib_get_buffer(vm, from[3]); - vlib_prefetch_buffer_header (p2, STORE); - vlib_prefetch_buffer_header (p3, STORE); + vlib_prefetch_buffer_header(p2, STORE); + vlib_prefetch_buffer_header(p3, STORE); - CLIB_PREFETCH (p2->data, sizeof (ip6_header_t), STORE); - CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), STORE); + CLIB_PREFETCH(p2->data, sizeof(ip6_header_t), STORE); + CLIB_PREFETCH(p3->data, sizeof(ip6_header_t), STORE); } from += 2; @@ -174,8 +207,8 @@ mpls_label_disposition_inline (vlib_main_t * vm, n_left_from -= 2; n_left_to_next -= 2; - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); + b0 = vlib_get_buffer(vm, bi0); + b1 = vlib_get_buffer(vm, bi1); /* dst lookup was done by ip4 lookup */ mddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX]; @@ -190,30 +223,62 @@ mpls_label_disposition_inline (vlib_main_t * vm, { ip4_header_t *ip0, *ip1; - ip0 = vlib_buffer_get_current (b0); - ip1 = vlib_buffer_get_current (b1); + ip0 = vlib_buffer_get_current(b0); + ip1 = vlib_buffer_get_current(b1); /* * IPv4 input checks on the exposed IP header * including checksum */ - ip4_input_check_x2 (vm, error_node, - b0, b1, ip0, ip1, - &next0, &next1, 1); + ip4_input_check_x2(vm, error_node, + b0, b1, ip0, ip1, + &next0, &next1, 1); + + if (FIB_MPLS_LSP_MODE_UNIFORM == mode) + { + /* + * Copy the TTL from the MPLS packet into the + * exposed IP. recalc the chksum + */ + ip0->ttl = vnet_buffer(b0)->mpls.ttl; + ip1->ttl = vnet_buffer(b1)->mpls.ttl; + ip0->tos = mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp); + ip1->tos = mpls_exp_to_ip_dscp(vnet_buffer(b1)->mpls.exp); + + ip0->checksum = ip4_header_checksum(ip0); + ip1->checksum = ip4_header_checksum(ip1); + } } else if (payload_is_ip6) { ip6_header_t *ip0, *ip1; - ip0 = vlib_buffer_get_current (b0); - ip1 = vlib_buffer_get_current (b1); + ip0 = vlib_buffer_get_current(b0); + ip1 = vlib_buffer_get_current(b1); /* * IPv6 input checks on the exposed IP header */ - ip6_input_check_x2 (vm, error_node, - b0, b1, ip0, ip1, - &next0, &next1); + ip6_input_check_x2(vm, error_node, + b0, b1, ip0, ip1, + &next0, &next1); + + if (FIB_MPLS_LSP_MODE_UNIFORM == mode) + { + /* + * Copy the TTL from the MPLS packet into the + * exposed IP + */ + ip0->hop_limit = vnet_buffer(b0)->mpls.ttl; + ip1->hop_limit = vnet_buffer(b1)->mpls.ttl; + + ip6_set_traffic_class_network_order( + ip0, + mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp)); + ip6_set_traffic_class_network_order( + ip1, + mpls_exp_to_ip_dscp(vnet_buffer(b1)->mpls.exp)); + } } vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mdd0->mdd_dpo.dpoi_index; @@ -224,14 +289,14 @@ mpls_label_disposition_inline (vlib_main_t * vm, if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { mpls_label_disposition_trace_t *tr = - vlib_add_trace (vm, node, b0, sizeof (*tr)); + vlib_add_trace(vm, node, b0, sizeof(*tr)); tr->mdd = mddi0; } if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) { mpls_label_disposition_trace_t *tr = - vlib_add_trace (vm, node, b1, sizeof (*tr)); + vlib_add_trace(vm, node, b1, sizeof(*tr)); tr->mdd = mddi1; } @@ -254,7 +319,7 @@ mpls_label_disposition_inline (vlib_main_t * vm, n_left_from -= 1; n_left_to_next -= 1; - b0 = vlib_get_buffer (vm, bi0); + b0 = vlib_get_buffer(vm, bi0); /* dst lookup was done by ip4 lookup */ mddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX]; @@ -265,24 +330,48 @@ mpls_label_disposition_inline (vlib_main_t * vm, { ip4_header_t *ip0; - ip0 = vlib_buffer_get_current (b0); + ip0 = vlib_buffer_get_current(b0); /* * IPv4 input checks on the exposed IP header * including checksum */ - ip4_input_check_x1 (vm, error_node, b0, ip0, &next0, 1); + ip4_input_check_x1(vm, error_node, b0, ip0, &next0, 1); + + if (FIB_MPLS_LSP_MODE_UNIFORM == mode) + { + /* + * Copy the TTL from the MPLS packet into the + * exposed IP. recalc the chksum + */ + ip0->ttl = vnet_buffer(b0)->mpls.ttl; + ip0->tos = mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp); + ip0->checksum = ip4_header_checksum(ip0); + } } else if (payload_is_ip6) { ip6_header_t *ip0; - ip0 = vlib_buffer_get_current (b0); + ip0 = vlib_buffer_get_current(b0); /* * IPv6 input checks on the exposed IP header */ - ip6_input_check_x1 (vm, error_node, b0, ip0, &next0); + ip6_input_check_x1(vm, error_node, b0, ip0, &next0); + + if (FIB_MPLS_LSP_MODE_UNIFORM == mode) + { + /* + * Copy the TTL from the MPLS packet into the + * exposed IP + */ + ip0->hop_limit = vnet_buffer(b0)->mpls.ttl; + + ip6_set_traffic_class_network_order( + ip0, + mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp)); + } } vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mdd0->mdd_dpo.dpoi_index; @@ -291,14 +380,14 @@ mpls_label_disposition_inline (vlib_main_t * vm, if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { mpls_label_disposition_trace_t *tr = - vlib_add_trace (vm, node, b0, sizeof (*tr)); + vlib_add_trace(vm, node, b0, sizeof(*tr)); tr->mdd = mddi0; } vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0); } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); + vlib_put_next_frame(vm, node, next_index, n_left_to_next); } return from_frame->n_vectors; } @@ -306,57 +395,103 @@ mpls_label_disposition_inline (vlib_main_t * vm, static u8 * format_mpls_label_disposition_trace (u8 * s, va_list * args) { - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - CLIB_UNUSED (mpls_label_disposition_trace_t * t); + CLIB_UNUSED(vlib_main_t * vm) = va_arg(*args, vlib_main_t *); + CLIB_UNUSED(vlib_node_t * node) = va_arg(*args, vlib_node_t *); + CLIB_UNUSED(mpls_label_disposition_trace_t * t); - t = va_arg (*args, mpls_label_disposition_trace_t *); + t = va_arg(*args, mpls_label_disposition_trace_t *); s = format(s, "disp:%d", t->mdd); return (s); } static uword -ip4_mpls_label_disposition (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +ip4_mpls_label_disposition_pipe (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) { - return (mpls_label_disposition_inline(vm, node, frame, 1, 0)); + return (mpls_label_disposition_inline(vm, node, frame, 1, 0, + FIB_MPLS_LSP_MODE_PIPE)); } -VLIB_REGISTER_NODE (ip4_mpls_label_disposition_node) = { - .function = ip4_mpls_label_disposition, - .name = "ip4-mpls-label-disposition", - .vector_size = sizeof (u32), +VLIB_REGISTER_NODE(ip4_mpls_label_disposition_pipe_node) = { + .function = ip4_mpls_label_disposition_pipe, + .name = "ip4-mpls-label-disposition-pipe", + .vector_size = sizeof(u32), .format_trace = format_mpls_label_disposition_trace, .sibling_of = "ip4-input", .n_errors = IP4_N_ERROR, .error_strings = ip4_error_strings, }; -VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_disposition_node, - ip4_mpls_label_disposition) +VLIB_NODE_FUNCTION_MULTIARCH(ip4_mpls_label_disposition_pipe_node, + ip4_mpls_label_disposition_pipe) static uword -ip6_mpls_label_disposition (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +ip6_mpls_label_disposition_pipe (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) { - return (mpls_label_disposition_inline(vm, node, frame, 0, 1)); + return (mpls_label_disposition_inline(vm, node, frame, 0, 1, + FIB_MPLS_LSP_MODE_PIPE)); } -VLIB_REGISTER_NODE (ip6_mpls_label_disposition_node) = { - .function = ip6_mpls_label_disposition, - .name = "ip6-mpls-label-disposition", - .vector_size = sizeof (u32), +VLIB_REGISTER_NODE(ip6_mpls_label_disposition_pipe_node) = { + .function = ip6_mpls_label_disposition_pipe, + .name = "ip6-mpls-label-disposition-pipe", + .vector_size = sizeof(u32), .format_trace = format_mpls_label_disposition_trace, .sibling_of = "ip6-input", .n_errors = IP6_N_ERROR, .error_strings = ip6_error_strings, }; -VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_disposition_node, - ip6_mpls_label_disposition) +VLIB_NODE_FUNCTION_MULTIARCH(ip6_mpls_label_disposition_pipe_node, + ip6_mpls_label_disposition_pipe) + +static uword +ip4_mpls_label_disposition_uniform (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return (mpls_label_disposition_inline(vm, node, frame, 1, 0, + FIB_MPLS_LSP_MODE_UNIFORM)); +} + +VLIB_REGISTER_NODE(ip4_mpls_label_disposition_uniform_node) = { + .function = ip4_mpls_label_disposition_uniform, + .name = "ip4-mpls-label-disposition-uniform", + .vector_size = sizeof(u32), + + .format_trace = format_mpls_label_disposition_trace, + .sibling_of = "ip4-input", + .n_errors = IP4_N_ERROR, + .error_strings = ip4_error_strings, +}; +VLIB_NODE_FUNCTION_MULTIARCH(ip4_mpls_label_disposition_uniform_node, + ip4_mpls_label_disposition_uniform) + +static uword +ip6_mpls_label_disposition_uniform (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return (mpls_label_disposition_inline(vm, node, frame, 0, 1, + FIB_MPLS_LSP_MODE_UNIFORM)); +} + +VLIB_REGISTER_NODE(ip6_mpls_label_disposition_uniform_node) = { + .function = ip6_mpls_label_disposition_uniform, + .name = "ip6-mpls-label-disposition-uniform", + .vector_size = sizeof(u32), + + .format_trace = format_mpls_label_disposition_trace, + .sibling_of = "ip6-input", + .n_errors = IP6_N_ERROR, + .error_strings = ip6_error_strings, +}; +VLIB_NODE_FUNCTION_MULTIARCH(ip6_mpls_label_disposition_uniform_node, + ip6_mpls_label_disposition_uniform) static void mpls_disp_dpo_mem_show (void) @@ -374,25 +509,44 @@ const static dpo_vft_t mdd_vft = { .dv_mem_show = mpls_disp_dpo_mem_show, }; -const static char* const mpls_label_disp_ip4_nodes[] = +const static char* const mpls_label_disp_pipe_ip4_nodes[] = +{ + "ip4-mpls-label-disposition-pipe", + NULL, +}; +const static char* const mpls_label_disp_pipe_ip6_nodes[] = +{ + "ip6-mpls-label-disposition-pipe", + NULL, +}; +const static char* const * const mpls_label_disp_pipe_nodes[DPO_PROTO_NUM] = +{ + [DPO_PROTO_IP4] = mpls_label_disp_pipe_ip4_nodes, + [DPO_PROTO_IP6] = mpls_label_disp_pipe_ip6_nodes, +}; + +const static char* const mpls_label_disp_uniform_ip4_nodes[] = { - "ip4-mpls-label-disposition", + "ip4-mpls-label-disposition-uniform", NULL, }; -const static char* const mpls_label_disp_ip6_nodes[] = +const static char* const mpls_label_disp_uniform_ip6_nodes[] = { - "ip6-mpls-label-disposition", + "ip6-mpls-label-disposition-uniform", NULL, }; -const static char* const * const mpls_label_disp_nodes[DPO_PROTO_NUM] = +const static char* const * const mpls_label_disp_uniform_nodes[DPO_PROTO_NUM] = { - [DPO_PROTO_IP4] = mpls_label_disp_ip4_nodes, - [DPO_PROTO_IP6] = mpls_label_disp_ip6_nodes, + [DPO_PROTO_IP4] = mpls_label_disp_uniform_ip4_nodes, + [DPO_PROTO_IP6] = mpls_label_disp_uniform_ip6_nodes, }; void -mpls_disp_dpo_module_init (void) +mpls_disp_dpo_module_init(void) { - dpo_register(DPO_MPLS_DISPOSITION, &mdd_vft, mpls_label_disp_nodes); + dpo_register(DPO_MPLS_DISPOSITION_PIPE, &mdd_vft, + mpls_label_disp_pipe_nodes); + dpo_register(DPO_MPLS_DISPOSITION_UNIFORM, &mdd_vft, + mpls_label_disp_uniform_nodes); } diff --git a/src/vnet/dpo/mpls_disposition.h b/src/vnet/dpo/mpls_disposition.h index 9c0150830d2..9c3cc46ff30 100644 --- a/src/vnet/dpo/mpls_disposition.h +++ b/src/vnet/dpo/mpls_disposition.h @@ -45,6 +45,11 @@ typedef struct mpls_disp_dpo_t * Number of locks/users of the label */ u16 mdd_locks; + + /** + * LSP mode + */ + fib_mpls_lsp_mode_t mdd_mode; } mpls_disp_dpo_t; /** @@ -60,11 +65,15 @@ _Static_assert((sizeof(mpls_disp_dpo_t) <= CLIB_CACHE_LINE_BYTES), * * @param payload_proto The ptocool of the payload packets that will * be imposed with this label header. + * @param rpf_id The RPF ID the packet will aquire - only for mcast + * @param mode The LSP mode; pipe or uniform * @param dpo The parent of the created MPLS label object */ -extern index_t mpls_disp_dpo_create(dpo_proto_t payload_proto, - fib_rpf_id_t rpf_id, - const dpo_id_t *dpo); +extern void mpls_disp_dpo_create(dpo_proto_t payload_proto, + fib_rpf_id_t rpf_id, + fib_mpls_lsp_mode_t mode, + const dpo_id_t *parent, + dpo_id_t *dpo); extern u8* format_mpls_disp_dpo(u8 *s, va_list *args); diff --git a/src/vnet/dpo/mpls_label_dpo.c b/src/vnet/dpo/mpls_label_dpo.c index fa5177ab9ea..954d637937b 100644 --- a/src/vnet/dpo/mpls_label_dpo.c +++ b/src/vnet/dpo/mpls_label_dpo.c @@ -23,6 +23,17 @@ */ mpls_label_dpo_t *mpls_label_dpo_pool; +/** + * Strings for the flags + */ +const char* mpls_label_dpo_attr_names[] = MPLS_LABEL_DPO_ATTR_NAMES; + +/** + * registered DPO types for each of the label sub-types. And there's a + * subtype for each of the flag combinations. + */ +static dpo_type_t mpls_label_dpo_types[1 << MPLS_LABEL_DPO_ATTR_MAX]; + static mpls_label_dpo_t * mpls_label_dpo_alloc (void) { @@ -42,70 +53,138 @@ mpls_label_dpo_get_index (mpls_label_dpo_t *mld) return (mld - mpls_label_dpo_pool); } -index_t -mpls_label_dpo_create (mpls_label_t *label_stack, +void +mpls_label_dpo_create (fib_mpls_label_t *label_stack, mpls_eos_bit_t eos, - u8 ttl, - u8 exp, dpo_proto_t payload_proto, - const dpo_id_t *dpo) + mpls_label_dpo_flags_t flags, + const dpo_id_t *parent, + dpo_id_t *dpo) { mpls_label_dpo_t *mld; + dpo_type_t dtype; u32 ii; + if ((DPO_PROTO_IP4 != payload_proto) && + (DPO_PROTO_IP6 != payload_proto)) + { + /* + * remove unsupported configuration + */ + flags &= ~MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR; + } + mld = mpls_label_dpo_alloc(); + mld->mld_flags = flags; + dtype = mpls_label_dpo_types[flags]; if (MPLS_LABEL_DPO_MAX_N_LABELS < vec_len(label_stack)) { clib_warning("Label stack size exceeded"); - dpo_stack(DPO_MPLS_LABEL, + dpo_stack(dtype, mld->mld_payload_proto, &mld->mld_dpo, drop_dpo_get(DPO_PROTO_MPLS)); - return (mpls_label_dpo_get_index(mld)); } + else + { + mld->mld_n_labels = vec_len(label_stack); + mld->mld_n_hdr_bytes = mld->mld_n_labels * sizeof(mld->mld_hdr[0]); + mld->mld_payload_proto = payload_proto; + + /* + * construct label rewrite headers for each value passed. + * get the header in network byte order since we will paint it + * on a packet in the data-plane + */ + for (ii = 0; ii < mld->mld_n_labels-1; ii++) + { + vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl, + label_stack[ii].fml_value); + vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl, + label_stack[ii].fml_exp); + vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl, + MPLS_NON_EOS); + if (0 != label_stack[ii].fml_ttl) + { + vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl, + label_stack[ii].fml_ttl); + } + else + { + vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl, + MPLS_LABEL_DEFAULT_TTL); + } + mld->mld_hdr[ii].label_exp_s_ttl = + clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl); + } - mld->mld_n_labels = vec_len(label_stack); - mld->mld_n_hdr_bytes = mld->mld_n_labels * sizeof(mld->mld_hdr[0]); - mld->mld_payload_proto = payload_proto; + /* + * the inner most label + */ + ii = mld->mld_n_labels-1; + + vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl, + label_stack[ii].fml_value); + vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl, + label_stack[ii].fml_exp); + vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl, eos); + if (0 != label_stack[ii].fml_ttl) + { + vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl, + label_stack[ii].fml_ttl); + } + else + { + vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl, + MPLS_LABEL_DEFAULT_TTL); + } + mld->mld_hdr[ii].label_exp_s_ttl = + clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl); - /* - * construct label rewrite headers for each value value passed. - * get the header in network byte order since we will paint it - * on a packet in the data-plane - */ + /* + * pipe/uniform mode is only supported for the bottom of stack label + */ + if (FIB_MPLS_LSP_MODE_UNIFORM == label_stack[ii].fml_mode) + { + mld->mld_flags |= MPLS_LABEL_DPO_FLAG_UNIFORM_MODE; + } + else + { + mld->mld_flags &= ~MPLS_LABEL_DPO_FLAG_UNIFORM_MODE; + } + dtype = mpls_label_dpo_types[mld->mld_flags]; - for (ii = 0; ii < mld->mld_n_labels-1; ii++) - { - vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl, label_stack[ii]); - vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl, 255); - vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl, 0); - vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl, MPLS_NON_EOS); - mld->mld_hdr[ii].label_exp_s_ttl = - clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl); + /* + * stack this label object on its parent. + */ + dpo_stack(dtype, + mld->mld_payload_proto, + &mld->mld_dpo, + parent); } - /* - * the inner most label - */ - ii = mld->mld_n_labels-1; + dpo_set(dpo, + dtype, + mld->mld_payload_proto, + mpls_label_dpo_get_index(mld)); +} - vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl, label_stack[ii]); - vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl, ttl); - vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl, exp); - vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl, eos); - mld->mld_hdr[ii].label_exp_s_ttl = - clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl); +u8* +format_mpls_label_dpo_flags (u8 *s, va_list *args) +{ + mpls_label_dpo_flags_t flags = va_arg (*args, int); + mpls_label_dpo_attr_t attr; - /* - * stack this label objct on its parent. - */ - dpo_stack(DPO_MPLS_LABEL, - mld->mld_payload_proto, - &mld->mld_dpo, - dpo); + FOR_EACH_MPLS_LABEL_DPO_ATTR(attr) + { + if ((1 << attr) & flags) + { + s = format(s, "%s,", mpls_label_dpo_attr_names[attr]); + } + } - return (mpls_label_dpo_get_index(mld)); + return (s); } u8* @@ -117,17 +196,18 @@ format_mpls_label_dpo (u8 *s, va_list *args) mpls_label_dpo_t *mld; u32 ii; - s = format(s, "mpls-label:[%d]:", index); - if (pool_is_free_index(mpls_label_dpo_pool, index)) { /* * the packet trace can be printed after the DPO has been deleted */ - return (s); + return (format(s, "mpls-label[???,%d]:", index)); } mld = mpls_label_dpo_get(index); + s = format(s, "mpls-label[%U%d]:", + format_mpls_label_dpo_flags, + (int) mld->mld_flags, index); for (ii = 0; ii < mld->mld_n_labels; ii++) { @@ -178,12 +258,21 @@ typedef struct mpls_label_imposition_trace_t_ * The MPLS header imposed */ mpls_unicast_header_t hdr; + + /** + * TTL imposed - only valid for uniform LSPs + */ + u8 ttl; + + /** + * TTL imposed - only valid for uniform LSPs + */ + u8 exp; } mpls_label_imposition_trace_t; always_inline mpls_unicast_header_t * mpls_label_paint (vlib_buffer_t * b0, - mpls_label_dpo_t *mld0, - u8 ttl0) + mpls_label_dpo_t *mld0) { mpls_unicast_header_t *hdr0; @@ -201,19 +290,74 @@ mpls_label_paint (vlib_buffer_t * b0, clib_memcpy(hdr0, mld0->mld_hdr, mld0->mld_n_hdr_bytes); hdr0 = hdr0 + (mld0->mld_n_labels - 1); } + + return (hdr0); +} + +/** + * Paint on an MPLS label and fixup the TTL + */ +always_inline mpls_unicast_header_t * +mpls_label_paint_w_ttl (vlib_buffer_t * b0, + mpls_label_dpo_t *mld0, + u8 ttl0) +{ + mpls_unicast_header_t *hdr0; + + hdr0 = mpls_label_paint(b0, mld0); + /* fixup the TTL for the inner most label */ ((char*)hdr0)[3] = ttl0; return (hdr0); } +/** + * Paint on an MPLS label and fixup the TTL and EXP bits. + */ +always_inline mpls_unicast_header_t * +mpls_label_paint_w_ttl_exp (vlib_buffer_t * b0, + mpls_label_dpo_t *mld0, + u8 ttl0, + u8 exp0) +{ + mpls_unicast_header_t *hdr0; + + hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0); + + /* fixup the EXP for the inner most label */ + ((char*)hdr0)[2] |= (exp0 << 1); + + return (hdr0); +} + +/** + * Paint on an MPLS label and fixup the TTL and EXP bits + * When the EXP bits are *already* bit shift to the correct place in + * in the 2nd byte (i.e. they were read from another label) + */ +always_inline mpls_unicast_header_t * +mpls_label_paint_w_ttl_mpls_exp (vlib_buffer_t * b0, + mpls_label_dpo_t *mld0, + u8 ttl0, + u8 exp0) +{ + mpls_unicast_header_t *hdr0; + + hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0); + + /* fixup the EXP for the inner most label */ + ((char*)hdr0)[2] |= exp0; + + return (hdr0); +} + always_inline uword mpls_label_imposition_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, - u8 payload_is_ip4, - u8 payload_is_ip6, - u8 payload_is_ethernet) + const dpo_proto_t dproto, + const mpls_label_dpo_flags_t flags) { u32 n_left_from, next_index, * from, * to_next; @@ -235,7 +379,8 @@ mpls_label_imposition_inline (vlib_main_t * vm, mpls_label_dpo_t *mld0, *mld1, *mld2, *mld3; vlib_buffer_t * b0, *b1, * b2, *b3; u32 next0, next1, next2, next3; - u8 ttl0, ttl1,ttl2, ttl3 ; + u8 ttl0, ttl1, ttl2, ttl3; + u8 exp0, exp1, exp2, exp3; bi0 = to_next[0] = from[0]; bi1 = to_next[1] = from[1]; @@ -282,141 +427,247 @@ mpls_label_imposition_inline (vlib_main_t * vm, mld2 = mpls_label_dpo_get(mldi2); mld3 = mpls_label_dpo_get(mldi3); - if (payload_is_ip4) + if (DPO_PROTO_MPLS != dproto) { /* - * decrement the TTL on ingress to the LSP + * These are the non-MPLS payload imposition cases */ - ip4_header_t * ip0 = vlib_buffer_get_current(b0); - ip4_header_t * ip1 = vlib_buffer_get_current(b1); - ip4_header_t * ip2 = vlib_buffer_get_current(b2); - ip4_header_t * ip3 = vlib_buffer_get_current(b3); - u32 checksum0; - u32 checksum1; - u32 checksum2; - u32 checksum3; - - checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100); - checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100); - checksum2 = ip2->checksum + clib_host_to_net_u16 (0x0100); - checksum3 = ip3->checksum + clib_host_to_net_u16 (0x0100); - - checksum0 += checksum0 >= 0xffff; - checksum1 += checksum1 >= 0xffff; - checksum2 += checksum2 >= 0xffff; - checksum3 += checksum3 >= 0xffff; - - ip0->checksum = checksum0; - ip1->checksum = checksum1; - ip2->checksum = checksum2; - ip3->checksum = checksum3; - - ip0->ttl -= 1; - ip1->ttl -= 1; - ip2->ttl -= 1; - ip3->ttl -= 1; - - ttl1 = ip1->ttl; - ttl0 = ip0->ttl; - ttl3 = ip3->ttl; - ttl2 = ip2->ttl; - } - else if (payload_is_ip6) - { - /* - * decrement the TTL on ingress to the LSP - */ - ip6_header_t * ip0 = vlib_buffer_get_current(b0); - ip6_header_t * ip1 = vlib_buffer_get_current(b1); - ip6_header_t * ip2 = vlib_buffer_get_current(b2); - ip6_header_t * ip3 = vlib_buffer_get_current(b3); - - ip0->hop_limit -= 1; - ip1->hop_limit -= 1; - ip2->hop_limit -= 1; - ip3->hop_limit -= 1; - - ttl0 = ip0->hop_limit; - ttl1 = ip1->hop_limit; - ttl2 = ip2->hop_limit; - ttl3 = ip3->hop_limit; - } - else if (payload_is_ethernet) - { + if (DPO_PROTO_IP4 == dproto) + { + ip4_header_t * ip0 = vlib_buffer_get_current(b0); + ip4_header_t * ip1 = vlib_buffer_get_current(b1); + ip4_header_t * ip2 = vlib_buffer_get_current(b2); + ip4_header_t * ip3 = vlib_buffer_get_current(b3); + + if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags)) + { + /* + * decrement the TTL on ingress to the LSP + */ + u32 checksum0; + u32 checksum1; + u32 checksum2; + u32 checksum3; + + checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100); + checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100); + checksum2 = ip2->checksum + clib_host_to_net_u16 (0x0100); + checksum3 = ip3->checksum + clib_host_to_net_u16 (0x0100); + + checksum0 += checksum0 >= 0xffff; + checksum1 += checksum1 >= 0xffff; + checksum2 += checksum2 >= 0xffff; + checksum3 += checksum3 >= 0xffff; + + ip0->checksum = checksum0; + ip1->checksum = checksum1; + ip2->checksum = checksum2; + ip3->checksum = checksum3; + + ip0->ttl -= 1; + ip1->ttl -= 1; + ip2->ttl -= 1; + ip3->ttl -= 1; + } + + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + ttl1 = ip1->ttl; + ttl0 = ip0->ttl; + ttl3 = ip3->ttl; + ttl2 = ip2->ttl; + /* by default copy the 3 most significant bits */ + exp0 = ip_dscp_to_mpls_exp(ip0->tos); + exp1 = ip_dscp_to_mpls_exp(ip1->tos); + exp2 = ip_dscp_to_mpls_exp(ip2->tos); + exp3 = ip_dscp_to_mpls_exp(ip3->tos); + } + } + else if (DPO_PROTO_IP6 == dproto) + { + /* + * decrement the TTL on ingress to the LSP + */ + ip6_header_t * ip0 = vlib_buffer_get_current(b0); + ip6_header_t * ip1 = vlib_buffer_get_current(b1); + ip6_header_t * ip2 = vlib_buffer_get_current(b2); + ip6_header_t * ip3 = vlib_buffer_get_current(b3); + + if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags)) + { + ip0->hop_limit -= 1; + ip1->hop_limit -= 1; + ip2->hop_limit -= 1; + ip3->hop_limit -= 1; + } + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + ttl0 = ip0->hop_limit; + ttl1 = ip1->hop_limit; + ttl2 = ip2->hop_limit; + ttl3 = ip3->hop_limit; + /* by default copy the 3 most significant bits */ + exp0 = ip_dscp_to_mpls_exp( + ip6_traffic_class_network_order(ip0)); + exp1 = ip_dscp_to_mpls_exp( + ip6_traffic_class_network_order(ip1)); + exp2 = ip_dscp_to_mpls_exp( + ip6_traffic_class_network_order(ip2)); + exp3 = ip_dscp_to_mpls_exp( + ip6_traffic_class_network_order(ip3)); + } + } + else + { + /* + * nothing to change in the ethernet header + */ + ttl0 = ttl1 = ttl2 = ttl3 = MPLS_LABEL_DEFAULT_TTL; + exp0 = exp1 = exp2 = exp3 = MPLS_LABEL_DEFAULT_EXP; + } /* - * nothing to chang ein the ethernet header + * These are the non-MPLS payload imposition cases. + * Based on the LSP mode either, for uniform, copy down the TTL + * and EXP from the payload or, for pipe mode, slap on the value + * requested from config */ - ttl0 = ttl1 = ttl2 = ttl3 = 255; + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0); + hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1); + hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2); + hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3); + } + else + { + hdr0 = mpls_label_paint(b0, mld0); + hdr1 = mpls_label_paint(b1, mld1); + hdr2 = mpls_label_paint(b2, mld2); + hdr3 = mpls_label_paint(b3, mld3); + } } else { /* * else, the packet to be encapped is an MPLS packet + * there are two cases to consider: + * 1 - this is an MPLS label swap at an LSP midpoint. + * recognisable because mpls.first = 1. In this case the + * TTL must be set to the current value -1. + * 2 - The MPLS packet is recursing (or being injected into) + * this LSP, in which case the pipe/uniform rules apply + * */ if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first)) { /* - * The first label to be imposed on the packet. this is a label swap. - * in which case we stashed the TTL and EXP bits in the - * packet in the lookup node + * The first label to be imposed on the packet. this is a + * label swap.in which case we stashed the TTL and EXP bits + * in the packet in the lookup node */ ASSERT(0 != vnet_buffer (b0)->mpls.ttl); ttl0 = vnet_buffer(b0)->mpls.ttl - 1; + exp0 = vnet_buffer(b0)->mpls.exp; + hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0); } else { /* - * not the first label. implying we are recusring down a chain of - * output labels. - * Each layer is considered a new LSP - hence the TTL is reset. + * not the first label. implying we are recusring down a + * chain of output labels. Each layer is considered a new + * LSP - hence the TTL/EXP are pipe/uniform handled */ - ttl0 = 255; + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + hdr0 = vlib_buffer_get_current(b0); + ttl0 = ((u8*)hdr0)[3]; + exp0 = ((u8*)hdr0)[2] & 0xe; + hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0); + } + else + { + hdr0 = mpls_label_paint(b0, mld0); + } } if (PREDICT_TRUE(vnet_buffer(b1)->mpls.first)) { - ASSERT(1 != vnet_buffer (b1)->mpls.ttl); + ASSERT(0 != vnet_buffer (b1)->mpls.ttl); + ttl1 = vnet_buffer(b1)->mpls.ttl - 1; + exp1 = vnet_buffer(b1)->mpls.exp; + hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1); } else { - ttl1 = 255; + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + hdr1 = vlib_buffer_get_current(b1); + ttl1 = ((u8*)hdr1)[3]; + exp1 = ((u8*)hdr1)[2] & 0xe; + hdr1 = mpls_label_paint_w_ttl_mpls_exp(b1, mld1, ttl1, exp1); + } + else + { + hdr1 = mpls_label_paint(b1, mld1); + } } if (PREDICT_TRUE(vnet_buffer(b2)->mpls.first)) { - ASSERT(1 != vnet_buffer (b2)->mpls.ttl); + ASSERT(0 != vnet_buffer (b2)->mpls.ttl); ttl2 = vnet_buffer(b2)->mpls.ttl - 1; + exp2 = vnet_buffer(b2)->mpls.exp; + hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2); } else { - ttl2 = 255; + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + hdr2 = vlib_buffer_get_current(b2); + ttl2 = ((u8*)hdr2)[3]; + exp2 = ((u8*)hdr2)[2] & 0xe; + hdr2 = mpls_label_paint_w_ttl_mpls_exp(b2, mld2, ttl2, exp2); + } + else + { + hdr2 = mpls_label_paint(b2, mld2); + } } if (PREDICT_TRUE(vnet_buffer(b3)->mpls.first)) { - ASSERT(1 != vnet_buffer (b3)->mpls.ttl); + ASSERT(0 != vnet_buffer (b3)->mpls.ttl); + ttl3 = vnet_buffer(b3)->mpls.ttl - 1; + exp3 = vnet_buffer(b0)->mpls.exp; + hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3); } else { - ttl3 = 255; + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + hdr3 = vlib_buffer_get_current(b3); + ttl3 = ((u8*)hdr3)[3]; + exp3 = ((u8*)hdr3)[2] & 0xe; + hdr3 = mpls_label_paint_w_ttl_mpls_exp(b3, mld3, ttl3, exp3); + } + else + { + hdr3 = mpls_label_paint(b3, mld3); + } } - } - vnet_buffer(b0)->mpls.first = 0; - vnet_buffer(b1)->mpls.first = 0; - vnet_buffer(b2)->mpls.first = 0; - vnet_buffer(b3)->mpls.first = 0; - /* Paint the MPLS header */ - hdr0 = mpls_label_paint(b0, mld0, ttl0); - hdr1 = mpls_label_paint(b1, mld1, ttl1); - hdr2 = mpls_label_paint(b2, mld2, ttl2); - hdr3 = mpls_label_paint(b3, mld3, ttl3); + vnet_buffer(b0)->mpls.first = 0; + vnet_buffer(b1)->mpls.first = 0; + vnet_buffer(b2)->mpls.first = 0; + vnet_buffer(b3)->mpls.first = 0; + } next0 = mld0->mld_dpo.dpoi_next_node; next1 = mld1->mld_dpo.dpoi_next_node; next2 = mld2->mld_dpo.dpoi_next_node; next3 = mld3->mld_dpo.dpoi_next_node; + vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index; vnet_buffer(b1)->ip.adj_index[VLIB_TX] = mld1->mld_dpo.dpoi_index; vnet_buffer(b2)->ip.adj_index[VLIB_TX] = mld2->mld_dpo.dpoi_index; @@ -427,24 +678,60 @@ mpls_label_imposition_inline (vlib_main_t * vm, mpls_label_imposition_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); tr->hdr = *hdr0; + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + tr->ttl = ttl0; + tr->exp = exp0; + } + else + { + tr->ttl = tr->exp = 0; + } } if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) { mpls_label_imposition_trace_t *tr = vlib_add_trace (vm, node, b1, sizeof (*tr)); tr->hdr = *hdr1; + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + tr->ttl = ttl1; + tr->exp = exp1; + } + else + { + tr->ttl = tr->exp = 0; + } } if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED)) { mpls_label_imposition_trace_t *tr = vlib_add_trace (vm, node, b2, sizeof (*tr)); tr->hdr = *hdr2; + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + tr->ttl = ttl2; + tr->exp = exp2; + } + else + { + tr->ttl = tr->exp = 0; + } } if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED)) { mpls_label_imposition_trace_t *tr = vlib_add_trace (vm, node, b3, sizeof (*tr)); tr->hdr = *hdr3; + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + tr->ttl = ttl3; + tr->exp = exp3; + } + else + { + tr->ttl = tr->exp = 0; + } } vlib_validate_buffer_enqueue_x4(vm, node, next_index, to_next, @@ -459,8 +746,8 @@ mpls_label_imposition_inline (vlib_main_t * vm, mpls_label_dpo_t *mld0; vlib_buffer_t * b0; u32 bi0, mldi0; + u8 ttl0, exp0; u32 next0; - u8 ttl; bi0 = from[0]; to_next[0] = bi0; @@ -475,67 +762,99 @@ mpls_label_imposition_inline (vlib_main_t * vm, mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX]; mld0 = mpls_label_dpo_get(mldi0); - if (payload_is_ip4) + if (DPO_PROTO_MPLS != dproto) { - /* - * decrement the TTL on ingress to the LSP - */ - ip4_header_t * ip0 = vlib_buffer_get_current(b0); - u32 checksum0; - - checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100); - checksum0 += checksum0 >= 0xffff; + if (DPO_PROTO_IP4 == dproto) + { + /* + * decrement the TTL on ingress to the LSP + */ + ip4_header_t * ip0 = vlib_buffer_get_current(b0); + if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags)) + { + u32 checksum0; + + checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100); + checksum0 += checksum0 >= 0xffff; + + ip0->checksum = checksum0; + ip0->ttl -= 1; + } + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + ttl0 = ip0->ttl; + exp0 = ip_dscp_to_mpls_exp(ip0->tos); + } + } + else if (DPO_PROTO_IP6 == dproto) + { + /* + * decrement the TTL on ingress to the LSP + */ + ip6_header_t * ip0 = vlib_buffer_get_current(b0); + + if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags)) + { + ip0->hop_limit -= 1; + } + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + ttl0 = ip0->hop_limit; + exp0 = ip_dscp_to_mpls_exp( + ip6_traffic_class_network_order(ip0)); + } + } + else + { + /* + * nothing to change in the ethernet header + */ + ttl0 = MPLS_LABEL_DEFAULT_TTL; + exp0 = MPLS_LABEL_DEFAULT_EXP; + } - ip0->checksum = checksum0; - ip0->ttl -= 1; - ttl = ip0->ttl; - } - else if (payload_is_ip6) - { /* - * decrement the TTL on ingress to the LSP + * These are the non-MPLS payload imposition cases. + * Based on the LSP mode either, for uniform, copy down the TTL + * from the payload or, for pipe mode, slap on the value + * requested from config */ - ip6_header_t * ip0 = vlib_buffer_get_current(b0); - - ip0->hop_limit -= 1; - ttl = ip0->hop_limit; + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0); + } + else + { + hdr0 = mpls_label_paint(b0, mld0); + } } else { - /* - * else, the packet to be encapped is an MPLS packet - */ - if (vnet_buffer(b0)->mpls.first) + if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first)) { - /* - * The first label to be imposed on the packet. this is a label swap. - * in which case we stashed the TTL and EXP bits in the - * packet in the lookup node - */ ASSERT(0 != vnet_buffer (b0)->mpls.ttl); - ttl = vnet_buffer(b0)->mpls.ttl - 1; + ttl0 = vnet_buffer(b0)->mpls.ttl - 1; + exp0 = vnet_buffer(b0)->mpls.exp; + hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0); } else { - /* - * not the first label. implying we are recusring down a chain of - * output labels. - * Each layer is considered a new LSP - hence the TTL is reset. - */ - ttl = 255; + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + hdr0 = vlib_buffer_get_current(b0); + ttl0 = ((u8*)hdr0)[3]; + exp0 = ((u8*)hdr0)[2] & 0xe; + hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0); + } + else + { + hdr0 = mpls_label_paint(b0, mld0); + } } - } - vnet_buffer(b0)->mpls.first = 0; - - /* Paint the MPLS header */ - vlib_buffer_advance(b0, -(mld0->mld_n_hdr_bytes)); - hdr0 = vlib_buffer_get_current(b0); - clib_memcpy(hdr0, mld0->mld_hdr, mld0->mld_n_hdr_bytes); - /* fixup the TTL for the inner most label */ - hdr0 = hdr0 + (mld0->mld_n_labels - 1); - ((char*)hdr0)[3] = ttl; + vnet_buffer(b0)->mpls.first = 0; + } next0 = mld0->mld_dpo.dpoi_next_node; vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index; @@ -545,7 +864,16 @@ mpls_label_imposition_inline (vlib_main_t * vm, mpls_label_imposition_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); tr->hdr = *hdr0; - } + if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE) + { + tr->ttl = ttl0; + tr->exp = exp0; + } + else + { + tr->ttl = tr->exp = 0; + } + } vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0); @@ -575,16 +903,18 @@ format_mpls_label_imposition_trace (u8 * s, va_list * args) } static uword -mpls_label_imposition (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +mpls_mpls_label_imposition_pipe (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) { - return (mpls_label_imposition_inline(vm, node, frame, 0, 0, 0)); + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_MPLS, + MPLS_LABEL_DPO_FLAG_NONE)); } -VLIB_REGISTER_NODE (mpls_label_imposition_node) = { - .function = mpls_label_imposition, - .name = "mpls-label-imposition", +VLIB_REGISTER_NODE (mpls_mpls_label_imposition_pipe_node) = { + .function = mpls_mpls_label_imposition_pipe, + .name = "mpls-label-imposition-pipe", .vector_size = sizeof (u32), .format_trace = format_mpls_label_imposition_trace, @@ -593,20 +923,22 @@ VLIB_REGISTER_NODE (mpls_label_imposition_node) = { [0] = "mpls-drop", } }; -VLIB_NODE_FUNCTION_MULTIARCH (mpls_label_imposition_node, - mpls_label_imposition) +VLIB_NODE_FUNCTION_MULTIARCH (mpls_mpls_label_imposition_pipe_node, + mpls_mpls_label_imposition_pipe) static uword -ip4_mpls_label_imposition (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +ip4_mpls_label_imposition_pipe (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) { - return (mpls_label_imposition_inline(vm, node, frame, 1, 0, 0)); + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_IP4, + MPLS_LABEL_DPO_FLAG_NONE)); } -VLIB_REGISTER_NODE (ip4_mpls_label_imposition_node) = { - .function = ip4_mpls_label_imposition, - .name = "ip4-mpls-label-imposition", +VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_node) = { + .function = ip4_mpls_label_imposition_pipe, + .name = "ip4-mpls-label-imposition-pipe", .vector_size = sizeof (u32), .format_trace = format_mpls_label_imposition_trace, @@ -615,20 +947,22 @@ VLIB_REGISTER_NODE (ip4_mpls_label_imposition_node) = { [0] = "ip4-drop", } }; -VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_imposition_node, - ip4_mpls_label_imposition) +VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_imposition_pipe_node, + ip4_mpls_label_imposition_pipe) static uword -ip6_mpls_label_imposition (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +ip6_mpls_label_imposition_pipe (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) { - return (mpls_label_imposition_inline(vm, node, frame, 0, 1, 0)); + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_IP6, + MPLS_LABEL_DPO_FLAG_NONE)); } -VLIB_REGISTER_NODE (ip6_mpls_label_imposition_node) = { - .function = ip6_mpls_label_imposition, - .name = "ip6-mpls-label-imposition", +VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_node) = { + .function = ip6_mpls_label_imposition_pipe, + .name = "ip6-mpls-label-imposition-pipe", .vector_size = sizeof (u32), .format_trace = format_mpls_label_imposition_trace, @@ -637,20 +971,22 @@ VLIB_REGISTER_NODE (ip6_mpls_label_imposition_node) = { [0] = "ip6-drop", } }; -VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_imposition_node, - ip6_mpls_label_imposition) +VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_imposition_pipe_node, + ip6_mpls_label_imposition_pipe) static uword -ethernet_mpls_label_imposition (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +ethernet_mpls_label_imposition_pipe (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) { - return (mpls_label_imposition_inline(vm, node, frame, 0, 0, 1)); + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_ETHERNET, + MPLS_LABEL_DPO_FLAG_NONE)); } -VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_node) = { - .function = ethernet_mpls_label_imposition, - .name = "ethernet-mpls-label-imposition", +VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_pipe_node) = { + .function = ethernet_mpls_label_imposition_pipe, + .name = "ethernet-mpls-label-imposition-pipe", .vector_size = sizeof (u32), .format_trace = format_mpls_label_imposition_trace, @@ -659,8 +995,205 @@ VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_node) = { [0] = "error-drop", } }; -VLIB_NODE_FUNCTION_MULTIARCH (ethernet_mpls_label_imposition_node, - ethernet_mpls_label_imposition) + +VLIB_NODE_FUNCTION_MULTIARCH (ethernet_mpls_label_imposition_pipe_node, + ethernet_mpls_label_imposition_pipe) + +static uword +mpls_mpls_label_imposition_uniform (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_MPLS, + MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)); +} + +VLIB_REGISTER_NODE (mpls_mpls_label_imposition_uniform_node) = { + .function = mpls_mpls_label_imposition_uniform, + .name = "mpls-label-imposition-uniform", + .vector_size = sizeof (u32), + + .format_trace = format_mpls_label_imposition_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "mpls-drop", + } +}; +VLIB_NODE_FUNCTION_MULTIARCH (mpls_mpls_label_imposition_uniform_node, + mpls_mpls_label_imposition_uniform) + +static uword +ip4_mpls_label_imposition_uniform (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_IP4, + MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)); +} + +VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_node) = { + .function = ip4_mpls_label_imposition_uniform, + .name = "ip4-mpls-label-imposition-uniform", + .vector_size = sizeof (u32), + + .format_trace = format_mpls_label_imposition_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "ip4-drop", + } +}; +VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_imposition_uniform_node, + ip4_mpls_label_imposition_uniform) + +static uword +ip6_mpls_label_imposition_uniform (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_IP6, + MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)); +} + +VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_node) = { + .function = ip6_mpls_label_imposition_uniform, + .name = "ip6-mpls-label-imposition-uniform", + .vector_size = sizeof (u32), + + .format_trace = format_mpls_label_imposition_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "ip6-drop", + } +}; +VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_imposition_uniform_node, + ip6_mpls_label_imposition_uniform) + +static uword +ethernet_mpls_label_imposition_uniform (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_ETHERNET, + MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)); +} + +VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_uniform_node) = { + .function = ethernet_mpls_label_imposition_uniform, + .name = "ethernet-mpls-label-imposition-uniform", + .vector_size = sizeof (u32), + + .format_trace = format_mpls_label_imposition_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "error-drop", + } +}; + +VLIB_NODE_FUNCTION_MULTIARCH (ethernet_mpls_label_imposition_uniform_node, + ethernet_mpls_label_imposition_uniform) + +static uword +ip4_mpls_label_imposition_pipe_no_ip_ttl_decr (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_IP4, + MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)); +} + +VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = { + .function = ip4_mpls_label_imposition_pipe_no_ip_ttl_decr, + .name = "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr", + .vector_size = sizeof (u32), + + .format_trace = format_mpls_label_imposition_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "ip4-drop", + } +}; +VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node, + ip4_mpls_label_imposition_pipe_no_ip_ttl_decr) + +static uword +ip6_mpls_label_imposition_pipe_no_ip_ttl_decr (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_IP6, + MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)); +} + +VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = { + .function = ip6_mpls_label_imposition_pipe_no_ip_ttl_decr, + .name = "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr", + .vector_size = sizeof (u32), + + .format_trace = format_mpls_label_imposition_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "ip6-drop", + } +}; +VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node, + ip6_mpls_label_imposition_pipe_no_ip_ttl_decr) + +static uword +ip4_mpls_label_imposition_uniform_no_ip_ttl_decr (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_IP4, + (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE | + MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR))); +} + +VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = { + .function = ip4_mpls_label_imposition_uniform_no_ip_ttl_decr, + .name = "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr", + .vector_size = sizeof (u32), + + .format_trace = format_mpls_label_imposition_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "ip4-drop", + } +}; +VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node, + ip4_mpls_label_imposition_uniform_no_ip_ttl_decr) + +static uword +ip6_mpls_label_imposition_uniform_no_ip_ttl_decr (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return (mpls_label_imposition_inline(vm, node, frame, + DPO_PROTO_IP6, + (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE | + MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR))); +} + +VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = { + .function = ip6_mpls_label_imposition_uniform_no_ip_ttl_decr, + .name = "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr", + .vector_size = sizeof (u32), + + .format_trace = format_mpls_label_imposition_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "ip6-drop", + } +}; +VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node, + ip6_mpls_label_imposition_uniform_no_ip_ttl_decr) + static void mpls_label_dpo_mem_show (void) @@ -678,38 +1211,118 @@ const static dpo_vft_t mld_vft = { .dv_mem_show = mpls_label_dpo_mem_show, }; -const static char* const mpls_label_imp_ip4_nodes[] = +const static char* const mpls_label_imp_pipe_ip4_nodes[] = { - "ip4-mpls-label-imposition", + "ip4-mpls-label-imposition-pipe", NULL, }; -const static char* const mpls_label_imp_ip6_nodes[] = +const static char* const mpls_label_imp_pipe_ip6_nodes[] = { - "ip6-mpls-label-imposition", + "ip6-mpls-label-imposition-pipe", NULL, }; -const static char* const mpls_label_imp_mpls_nodes[] = +const static char* const mpls_label_imp_pipe_mpls_nodes[] = { - "mpls-label-imposition", + "mpls-label-imposition-pipe", NULL, }; -const static char* const mpls_label_imp_ethernet_nodes[] = +const static char* const mpls_label_imp_pipe_ethernet_nodes[] = { - "ethernet-mpls-label-imposition", + "ethernet-mpls-label-imposition-pipe", NULL, }; -const static char* const * const mpls_label_imp_nodes[DPO_PROTO_NUM] = +const static char* const * const mpls_label_imp_pipe_nodes[DPO_PROTO_NUM] = { - [DPO_PROTO_IP4] = mpls_label_imp_ip4_nodes, - [DPO_PROTO_IP6] = mpls_label_imp_ip6_nodes, - [DPO_PROTO_MPLS] = mpls_label_imp_mpls_nodes, - [DPO_PROTO_ETHERNET] = mpls_label_imp_ethernet_nodes, + [DPO_PROTO_IP4] = mpls_label_imp_pipe_ip4_nodes, + [DPO_PROTO_IP6] = mpls_label_imp_pipe_ip6_nodes, + [DPO_PROTO_MPLS] = mpls_label_imp_pipe_mpls_nodes, + [DPO_PROTO_ETHERNET] = mpls_label_imp_pipe_ethernet_nodes, }; +const static char* const mpls_label_imp_uniform_ip4_nodes[] = +{ + "ip4-mpls-label-imposition-uniform", + NULL, +}; +const static char* const mpls_label_imp_uniform_ip6_nodes[] = +{ + "ip6-mpls-label-imposition-uniform", + NULL, +}; +const static char* const mpls_label_imp_uniform_mpls_nodes[] = +{ + "mpls-label-imposition-uniform", + NULL, +}; +const static char* const mpls_label_imp_uniform_ethernet_nodes[] = +{ + "ethernet-mpls-label-imposition-uniform", + NULL, +}; + +const static char* const * const mpls_label_imp_uniform_nodes[DPO_PROTO_NUM] = +{ + [DPO_PROTO_IP4] = mpls_label_imp_uniform_ip4_nodes, + [DPO_PROTO_IP6] = mpls_label_imp_uniform_ip6_nodes, + [DPO_PROTO_MPLS] = mpls_label_imp_uniform_mpls_nodes, + [DPO_PROTO_ETHERNET] = mpls_label_imp_uniform_ethernet_nodes, +}; + +const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip4_nodes[] = +{ + "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr", + NULL, +}; +const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip6_nodes[] = +{ + "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr", + NULL, +}; + +const static char* const * const mpls_label_imp_pipe_no_ip_tll_decr_nodes[DPO_PROTO_NUM] = +{ + [DPO_PROTO_IP4] = mpls_label_imp_pipe_no_ip_tll_decr_ip4_nodes, + [DPO_PROTO_IP6] = mpls_label_imp_pipe_no_ip_tll_decr_ip6_nodes, +}; + +const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip4_nodes[] = +{ + "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr", + NULL, +}; +const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip6_nodes[] = +{ + "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr", + NULL, +}; + +const static char* const * const mpls_label_imp_uniform_no_ip_tll_decr_nodes[DPO_PROTO_NUM] = +{ + [DPO_PROTO_IP4] = mpls_label_imp_uniform_no_ip_tll_decr_ip4_nodes, + [DPO_PROTO_IP6] = mpls_label_imp_uniform_no_ip_tll_decr_ip6_nodes, +}; void mpls_label_dpo_module_init (void) { - dpo_register(DPO_MPLS_LABEL, &mld_vft, mpls_label_imp_nodes); + mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE] = + dpo_register_new_type(&mld_vft, + mpls_label_imp_pipe_nodes); + mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] = + dpo_register_new_type(&mld_vft, + mpls_label_imp_pipe_no_ip_tll_decr_nodes); + mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE] = + dpo_register_new_type(&mld_vft, + mpls_label_imp_uniform_nodes); + mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE | + MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] = + dpo_register_new_type(&mld_vft, + mpls_label_imp_uniform_no_ip_tll_decr_nodes); +} + +dpo_type_t +mpls_label_dpo_get_type (mpls_label_dpo_flags_t flags) +{ + return (mpls_label_dpo_types[flags]); } diff --git a/src/vnet/dpo/mpls_label_dpo.h b/src/vnet/dpo/mpls_label_dpo.h index 8494d26b495..98c88f7d812 100644 --- a/src/vnet/dpo/mpls_label_dpo.h +++ b/src/vnet/dpo/mpls_label_dpo.h @@ -20,11 +20,47 @@ #include <vnet/mpls/packet.h> #include <vnet/dpo/dpo.h> +/** + * Flags present on an MPLS label sourced path-extension + */ +typedef enum mpls_label_dpo_attr_t_ +{ + /** + * Do not decrement the TTL of IP packet during imposition + */ + MPLS_LABEL_DPO_ATTR_NO_IP_TTL_DECR, + MPLS_LABEL_DPO_ATTR_UNIFORM_MODE, +} mpls_label_dpo_attr_t; + +#define MPLS_LABEL_DPO_ATTR_MAX (MPLS_LABEL_DPO_ATTR_UNIFORM_MODE+1) + +typedef enum mpls_label_dpo_flags_t_ +{ + MPLS_LABEL_DPO_FLAG_NONE = 0, + MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR = (1 << MPLS_LABEL_DPO_ATTR_NO_IP_TTL_DECR), + MPLS_LABEL_DPO_FLAG_UNIFORM_MODE = (1 << MPLS_LABEL_DPO_ATTR_UNIFORM_MODE), +} __attribute__ ((packed)) mpls_label_dpo_flags_t; + +#define MPLS_LABEL_DPO_ATTR_NAMES { \ + [MPLS_LABEL_DPO_ATTR_NO_IP_TTL_DECR] = "no-ip-tll-decr", \ + [MPLS_LABEL_DPO_ATTR_UNIFORM_MODE] = "uniform-mode", \ +} + +#define FOR_EACH_MPLS_LABEL_DPO_ATTR(_item) \ + for (_item = MPLS_LABEL_DPO_ATTR_NO_IP_TTL_DECR; \ + _item <= MPLS_LABEL_DPO_ATTR_UNIFORM_MODE; \ + _item++) + +/** + * Format the flags variable + */ +extern u8* format_mpls_label_dpo_flags(u8 *s, va_list *args); /** * Maximum number of labels in one DPO */ #define MPLS_LABEL_DPO_MAX_N_LABELS 12 + /** * A representation of an MPLS label for imposition in the data-path */ @@ -47,9 +83,14 @@ typedef struct mpls_label_dpo_t dpo_proto_t mld_payload_proto; /** + * Flags + */ + mpls_label_dpo_flags_t mld_flags; + + /** * Size of the label stack */ - u16 mld_n_labels; + u8 mld_n_labels; /** * Cached amount of header bytes to paint @@ -75,18 +116,17 @@ STATIC_ASSERT((sizeof(mpls_label_dpo_t) <= CLIB_CACHE_LINE_BYTES), * * @param label_stack The stack if labels to impose, outer most label first * @param eos The inner most label's EOS bit - * @param ttl The inner most label's TTL bit - * @param exp The inner most label's EXP bit * @param payload_proto The ptocool of the payload packets that will * be imposed with this label header. - * @param dpo The parent of the created MPLS label object + * @param parent The parent of the created MPLS label object + * @param dpo The MPLS label DPO created */ -extern index_t mpls_label_dpo_create(mpls_label_t *label_stack, - mpls_eos_bit_t eos, - u8 ttl, - u8 exp, - dpo_proto_t payload_proto, - const dpo_id_t *dpo); +extern void mpls_label_dpo_create(fib_mpls_label_t *label_stack, + mpls_eos_bit_t eos, + dpo_proto_t payload_proto, + mpls_label_dpo_flags_t flags, + const dpo_id_t *paremt, + dpo_id_t *dpo); extern u8* format_mpls_label_dpo(u8 *s, va_list *args); @@ -104,4 +144,9 @@ mpls_label_dpo_get (index_t index) extern void mpls_label_dpo_module_init(void); +/* + * test function to get the registered DPO type for the flags + */ +extern dpo_type_t mpls_label_dpo_get_type(mpls_label_dpo_flags_t flags); + #endif |