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 | |
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')
40 files changed, 1754 insertions, 599 deletions
diff --git a/src/vat/api_format.c b/src/vat/api_format.c index dc7111d4ea7..776f3500675 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -8872,7 +8872,7 @@ api_bier_route_add_del (vat_main_t * vam) } /* Construct the API message */ - M2 (BIER_ROUTE_ADD_DEL, mp, sizeof (vl_api_fib_path3_t)); + M2 (BIER_ROUTE_ADD_DEL, mp, sizeof (vl_api_fib_path_t)); mp->br_is_add = is_add; mp->br_tbl_id.bt_set = set; @@ -8881,7 +8881,7 @@ api_bier_route_add_del (vat_main_t * vam) mp->br_bp = ntohs (bp); mp->br_n_paths = 1; mp->br_paths[0].n_labels = 1; - mp->br_paths[0].label_stack[0] = ntohl (next_hop_out_label); + mp->br_paths[0].label_stack[0].label = ntohl (next_hop_out_label); mp->br_paths[0].afi = (next_hop_proto_is_ip4 ? 0 : 1); if (next_hop_proto_is_ip4) @@ -19634,7 +19634,7 @@ api_netmap_delete (vat_main_t * vam) } static void -vl_api_mpls_fib_path_print (vat_main_t * vam, vl_api_fib_path2_t * fp) +vl_api_mpls_fib_path_print (vat_main_t * vam, vl_api_fib_path_t * fp) { if (fp->afi == IP46_TYPE_IP6) print (vam->ofp, @@ -19654,7 +19654,7 @@ vl_api_mpls_fib_path_print (vat_main_t * vam, vl_api_fib_path2_t * fp) static void vl_api_mpls_fib_path_json_print (vat_json_node_t * node, - vl_api_fib_path2_t * fp) + vl_api_fib_path_t * fp) { struct in_addr ip4; struct in6_addr ip6; @@ -19683,7 +19683,7 @@ vl_api_mpls_tunnel_details_t_handler (vl_api_mpls_tunnel_details_t * mp) { vat_main_t *vam = &vat_main; int count = ntohl (mp->mt_count); - vl_api_fib_path2_t *fp; + vl_api_fib_path_t *fp; i32 i; print (vam->ofp, "[%d]: sw_if_index %d via:", @@ -19707,7 +19707,7 @@ vl_api_mpls_tunnel_details_t_handler_json (vl_api_mpls_tunnel_details_t * mp) vat_main_t *vam = &vat_main; vat_json_node_t *node = NULL; int count = ntohl (mp->mt_count); - vl_api_fib_path2_t *fp; + vl_api_fib_path_t *fp; i32 i; if (VAT_JSON_ARRAY != vam->json_tree.type) @@ -19773,7 +19773,7 @@ vl_api_mpls_fib_details_t_handler (vl_api_mpls_fib_details_t * mp) { vat_main_t *vam = &vat_main; int count = ntohl (mp->count); - vl_api_fib_path2_t *fp; + vl_api_fib_path_t *fp; int i; print (vam->ofp, @@ -19793,7 +19793,7 @@ static void vl_api_mpls_fib_details_t_handler_json vat_main_t *vam = &vat_main; int count = ntohl (mp->count); vat_json_node_t *node = NULL; - vl_api_fib_path2_t *fp; + vl_api_fib_path_t *fp; int i; if (VAT_JSON_ARRAY != vam->json_tree.type) diff --git a/src/vnet/adj/adj_l2.c b/src/vnet/adj/adj_l2.c index 132ceb28168..09bf468ac40 100644 --- a/src/vnet/adj/adj_l2.c +++ b/src/vnet/adj/adj_l2.c @@ -91,6 +91,11 @@ adj_l2_rewrite_inline (vlib_main_t * vm, rw_len0 = adj0[0].rewrite_header.data_bytes; vnet_buffer(p0)->ip.save_rewrite_length = rw_len0; vnet_buffer(p0)->sw_if_index[VLIB_TX] = adj0->rewrite_header.sw_if_index; + /* since we are coming out of the L2 world, where the vlib_buffer + * union is used for other things, make sure it is clean for + * MPLS from now on. + */ + vnet_buffer(p0)->mpls.first = 0; vlib_increment_combined_counter(&adjacency_counters, thread_index, diff --git a/src/vnet/bier/bier.api b/src/vnet/bier/bier.api index 446863c8ee8..d07379e92f0 100644 --- a/src/vnet/bier/bier.api +++ b/src/vnet/bier/bier.api @@ -18,7 +18,7 @@ This file defines vpp BIER control-plane API messages which are generally called through a shared memory interface. */ -option version = "1.0.0"; +option version = "1.1.0"; import "vnet/fib/fib_types.api"; /** \brief BIER Table Indentifier @@ -84,7 +84,7 @@ autoreply define bier_route_add_del u8 br_is_replace; vl_api_bier_table_id_t br_tbl_id; u8 br_n_paths; - vl_api_fib_path3_t br_paths[br_n_paths]; + vl_api_fib_path_t br_paths[br_n_paths]; }; define bier_route_dump @@ -101,7 +101,7 @@ define bier_route_details u16 br_bp; vl_api_bier_table_id_t br_tbl_id; u32 br_n_paths; - vl_api_fib_path3_t br_paths[br_n_paths]; + vl_api_fib_path_t br_paths[br_n_paths]; }; /** \brief BIER Imposition Add @@ -211,7 +211,7 @@ autoreply define bier_disp_entry_add_del u8 bde_is_add; u8 bde_payload_proto; u8 bde_n_paths; - vl_api_fib_path3_t bde_paths[bde_n_paths]; + vl_api_fib_path_t bde_paths[bde_n_paths]; }; define bier_disp_entry_dump @@ -229,7 +229,7 @@ define bier_disp_entry_details u8 bde_is_add; u8 bde_payload_proto; u8 bde_n_paths; - vl_api_fib_path3_t bde_paths[bde_n_paths]; + vl_api_fib_path_t bde_paths[bde_n_paths]; }; /* diff --git a/src/vnet/bier/bier_api.c b/src/vnet/bier/bier_api.c index 4b1d1c28781..77b2cabaa44 100644 --- a/src/vnet/bier/bier_api.c +++ b/src/vnet/bier/bier_api.c @@ -202,8 +202,16 @@ vl_api_bier_route_add_del_t_handler (vl_api_bier_route_add_del_t * mp) mp->br_paths[ii].n_labels - 1); for (jj = 0; jj < mp->br_paths[ii].n_labels; jj++) { - brpath->frp_label_stack[jj] = - ntohl(mp->br_paths[ii].label_stack[jj]); + brpath->frp_label_stack[jj].fml_value = + ntohl(mp->br_paths[ii].label_stack[jj].label); + brpath->frp_label_stack[jj].fml_ttl = + mp->br_paths[ii].label_stack[jj].ttl; + brpath->frp_label_stack[jj].fml_exp = + mp->br_paths[ii].label_stack[jj].exp; + brpath->frp_label_stack[jj].fml_mode = + (mp->br_paths[ii].label_stack[jj].is_uniform ? + FIB_MPLS_LSP_MODE_UNIFORM : + FIB_MPLS_LSP_MODE_PIPE); } if (mp->br_paths[ii].is_udp_encap) @@ -275,11 +283,11 @@ send_bier_route_details (const bier_table_t *bt, fib_route_path_encode_t *api_rpaths = NULL, *api_rpath; bier_route_details_walk_t *ctx = args; vl_api_bier_route_details_t *mp; - vl_api_fib_path3_t *fp; + vl_api_fib_path_t *fp; u32 n_paths, m_size; n_paths = fib_path_list_get_n_paths(be->be_path_list); - m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path3_t)); + m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t)); mp = vl_msg_api_alloc(m_size); if (!mp) return; @@ -636,7 +644,7 @@ send_bier_disp_entry_details (const bier_disp_table_t *bdt, bier_disp_entry_details_walk_t *ctx = args; vl_api_bier_disp_entry_details_t *mp; bier_hdr_proto_id_t pproto; - vl_api_fib_path3_t *fp; + vl_api_fib_path_t *fp; u32 n_paths, m_size; FOR_EACH_BIER_HDR_PROTO(pproto) @@ -645,7 +653,7 @@ send_bier_disp_entry_details (const bier_disp_table_t *bdt, if (INDEX_INVALID != pl) { n_paths = fib_path_list_get_n_paths(pl); - m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path3_t)); + m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t)); mp = vl_msg_api_alloc(m_size); if (!mp) return; diff --git a/src/vnet/bier/bier_fmask.c b/src/vnet/bier/bier_fmask.c index 2fc24dca819..31d884af060 100644 --- a/src/vnet/bier/bier_fmask.c +++ b/src/vnet/bier/bier_fmask.c @@ -177,16 +177,13 @@ bier_fmask_init (bier_fmask_t *bfm, if (!(bfm->bfm_flags & BIER_FMASK_FLAG_DISP)) { - /* - * leave this label in host byte order so we can OR in the TTL - */ if (NULL != rpaths->frp_label_stack) { - olabel = rpaths->frp_label_stack[0]; + olabel = rpaths->frp_label_stack[0].fml_value; vnet_mpls_uc_set_label(&bfm->bfm_label, olabel); vnet_mpls_uc_set_exp(&bfm->bfm_label, 0); vnet_mpls_uc_set_s(&bfm->bfm_label, 1); - vnet_mpls_uc_set_ttl(&bfm->bfm_label, 0); + vnet_mpls_uc_set_ttl(&bfm->bfm_label, 64); bfm->bfm_flags |= BIER_FMASK_FLAG_MPLS; } else @@ -207,7 +204,9 @@ bier_fmask_init (bier_fmask_t *bfm, vnet_mpls_uc_set_label(&bfm->bfm_label, id); vnet_mpls_uc_set_s(&bfm->bfm_label, 1); vnet_mpls_uc_set_exp(&bfm->bfm_label, 0); + vnet_mpls_uc_set_ttl(&bfm->bfm_label, 64); } + bfm->bfm_label = clib_host_to_net_u32(bfm->bfm_label); } bfm->bfm_pl = fib_path_list_create((FIB_PATH_LIST_FLAG_SHARED | diff --git a/src/vnet/bier/bier_output.c b/src/vnet/bier/bier_output.c index db115d3ad5e..01eeffe475c 100644 --- a/src/vnet/bier/bier_output.c +++ b/src/vnet/bier/bier_output.c @@ -140,8 +140,8 @@ bier_output (vlib_main_t * vm, h0 = vlib_buffer_get_current(b0); h0[0] = bfm0->bfm_label; - vnet_mpls_uc_set_ttl(h0, vnet_buffer(b0)->mpls.ttl - 1); - h0[0] = clib_host_to_net_u32(h0[0]); + + ((char*)h0)[3]= vnet_buffer(b0)->mpls.ttl - 1; } /* diff --git a/src/vnet/bier/bier_test.c b/src/vnet/bier/bier_test.c index 08a8c55954d..6c7af829811 100644 --- a/src/vnet/bier/bier_test.c +++ b/src/vnet/bier/bier_test.c @@ -316,7 +316,10 @@ bier_test_mpls_spf (void) .frp_bier_fib_index = bti, .frp_sw_if_index = ~0, }; - vec_add1(path_1_1_1_1.frp_label_stack, 500); + fib_mpls_label_t fml_500 = { + .fml_value = 500, + }; + vec_add1(path_1_1_1_1.frp_label_stack, fml_500); vec_add1(paths_1_1_1_1, path_1_1_1_1); const fib_prefix_t pfx_1_1_1_1_s_32 = { .fp_addr = nh_1_1_1_1, @@ -389,8 +392,10 @@ bier_test_mpls_spf (void) .ttl = 255, }, }; - mpls_label_t *out_lbl_99 = NULL; - vec_add1(out_lbl_99, 99); + fib_mpls_label_t *out_lbl_99 = NULL, fml_99 = { + .fml_value = 99, + }; + vec_add1(out_lbl_99, fml_99); fei = fib_table_entry_update_one_path(0, &pfx_1_1_1_1_s_32, @@ -443,8 +448,10 @@ bier_test_mpls_spf (void) .ttl = 255, }, }; - mpls_label_t *out_lbl_100 = NULL; - vec_add1(out_lbl_100, 100); + fib_mpls_label_t *out_lbl_100 = NULL, fml_100 = { + .fml_value = 100, + }; + vec_add1(out_lbl_100, fml_100); fei = fib_table_entry_path_add(0, &pfx_1_1_1_1_s_32, @@ -505,13 +512,18 @@ bier_test_mpls_spf (void) .frp_bier_fib_index = bti, .frp_sw_if_index = ~0, }; - vec_add1(path_1_1_1_2.frp_label_stack, 501); + fib_mpls_label_t fml_501 = { + .fml_value = 501, + }; + vec_add1(path_1_1_1_2.frp_label_stack, fml_501); vec_add1(paths_1_1_1_2, path_1_1_1_2); input_paths_1_1_1_2 = vec_dup(paths_1_1_1_2); index_t bei_3; - mpls_label_t *out_lbl_101 = NULL; - vec_add1(out_lbl_101, 101); + fib_mpls_label_t *out_lbl_101 = NULL, fml_101 = { + .fml_value = 101, + }; + vec_add1(out_lbl_101, fml_101); fei = fib_table_entry_path_add(0, &pfx_1_1_1_2_s_32, FIB_SOURCE_API, @@ -605,7 +617,7 @@ bier_test_mpls_spf (void) * add the via back */ out_lbl_101 = NULL; - vec_add1(out_lbl_101, 101); + vec_add1(out_lbl_101, fml_101); fei = fib_table_entry_path_add(0, &pfx_1_1_1_2_s_32, FIB_SOURCE_API, diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index 5aedb431654..7a4bc245a30 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -181,6 +181,8 @@ typedef struct */ struct { + /* do not overlay w/ ip.adj_index[0,1] nor flow hash */ + u32 pad[VLIB_N_RX_TX + 1]; u8 ttl; u8 exp; u8 first; 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 diff --git a/src/vnet/fib/fib_api.h b/src/vnet/fib/fib_api.h index bbe4eaac74b..d10ba00913b 100644 --- a/src/vnet/fib/fib_api.h +++ b/src/vnet/fib/fib_api.h @@ -53,7 +53,7 @@ add_del_route_t_handler (u8 is_multipath, u16 next_hop_weight, u16 next_hop_preference, mpls_label_t next_hop_via_label, - mpls_label_t * next_hop_out_label_stack); + fib_mpls_label_t * next_hop_out_label_stack); void copy_fib_next_hop (fib_route_path_encode_t * api_rpath, diff --git a/src/vnet/fib/fib_entry_src.c b/src/vnet/fib/fib_entry_src.c index 6dc0c73a305..ec8c7393030 100644 --- a/src/vnet/fib/fib_entry_src.c +++ b/src/vnet/fib/fib_entry_src.c @@ -212,6 +212,7 @@ static int fib_entry_src_valid_out_label (mpls_label_t label) { return ((MPLS_LABEL_IS_REAL(label) || + MPLS_LABEL_POP == label || MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL == label || MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL == label || MPLS_IETF_IMPLICIT_NULL_LABEL == label)); @@ -330,6 +331,7 @@ fib_entry_src_get_path_forwarding (fib_node_index_t path_index, &nh->path_dpo); fib_path_stack_mpls_disp(path_index, fib_prefix_get_payload_proto(&ctx->fib_entry->fe_prefix), + FIB_MPLS_LSP_MODE_PIPE, &nh->path_dpo); break; @@ -391,7 +393,7 @@ fib_entry_src_collect_forwarding (fib_node_index_t pl_index, switch (path_ext->fpe_type) { case FIB_PATH_EXT_MPLS: - if (fib_entry_src_valid_out_label(path_ext->fpe_label_stack[0])) + if (fib_entry_src_valid_out_label(path_ext->fpe_label_stack[0].fml_value)) { /* * found a matching extension. stack it to obtain the forwarding diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c index b4f9971f52e..a8593905438 100644 --- a/src/vnet/fib/fib_path.c +++ b/src/vnet/fib/fib_path.c @@ -1349,7 +1349,8 @@ fib_path_create (fib_node_index_t pl_index, { path->fp_type = FIB_PATH_TYPE_DEAG; path->deag.fp_tbl_id = rpath->frp_fib_index; - } + path->deag.fp_rpf_id = ~0; + } } else { @@ -2238,6 +2239,7 @@ fib_path_contribute_urpf (fib_node_index_t path_index, void fib_path_stack_mpls_disp (fib_node_index_t path_index, dpo_proto_t payload_proto, + fib_mpls_lsp_mode_t mode, dpo_id_t *dpo) { fib_path_t *path; @@ -2253,10 +2255,8 @@ fib_path_stack_mpls_disp (fib_node_index_t path_index, dpo_id_t tmp = DPO_INVALID; dpo_copy(&tmp, dpo); - dpo_set(dpo, - DPO_MPLS_DISPOSITION, - payload_proto, - mpls_disp_dpo_create(payload_proto, ~0, &tmp)); + + mpls_disp_dpo_create(payload_proto, ~0, mode, &tmp, dpo); dpo_reset(&tmp); break; } @@ -2265,12 +2265,10 @@ fib_path_stack_mpls_disp (fib_node_index_t path_index, dpo_id_t tmp = DPO_INVALID; dpo_copy(&tmp, dpo); - dpo_set(dpo, - DPO_MPLS_DISPOSITION, - payload_proto, - mpls_disp_dpo_create(payload_proto, - path->deag.fp_rpf_id, - &tmp)); + + mpls_disp_dpo_create(payload_proto, + path->deag.fp_rpf_id, + mode, &tmp, dpo); dpo_reset(&tmp); break; } diff --git a/src/vnet/fib/fib_path.h b/src/vnet/fib/fib_path.h index 70b2f503aa8..28ec10a98d5 100644 --- a/src/vnet/fib/fib_path.h +++ b/src/vnet/fib/fib_path.h @@ -159,6 +159,7 @@ extern load_balance_path_t * fib_path_append_nh_for_multipath_hash( load_balance_path_t *hash_key); extern void fib_path_stack_mpls_disp(fib_node_index_t path_index, dpo_proto_t payload_proto, + fib_mpls_lsp_mode_t mode, dpo_id_t *dpo); extern void fib_path_contribute_forwarding(fib_node_index_t path_index, fib_forward_chain_type_t type, diff --git a/src/vnet/fib/fib_path_ext.c b/src/vnet/fib/fib_path_ext.c index a285ba07f7c..6b5b841c2ac 100644 --- a/src/vnet/fib/fib_path_ext.c +++ b/src/vnet/fib/fib_path_ext.c @@ -25,6 +25,7 @@ #include <vnet/fib/fib_internal.h> const char *fib_path_ext_adj_flags_names[] = FIB_PATH_EXT_ADJ_ATTR_NAMES; +const char *fib_path_ext_mpls_flags_names[] = FIB_PATH_EXT_MPLS_ATTR_NAMES; u8 * format_fib_path_ext (u8 * s, va_list * args) @@ -38,30 +39,46 @@ format_fib_path_ext (u8 * s, va_list * args) switch (path_ext->fpe_type) { - case FIB_PATH_EXT_MPLS: - s = format(s, "labels:", + case FIB_PATH_EXT_MPLS: { + fib_path_ext_mpls_attr_t attr; + + if (path_ext->fpe_mpls_flags) + { + s = format(s, "mpls-flags:["); + + FOR_EACH_PATH_EXT_MPLS_ATTR(attr) + { + if ((1<<attr) & path_ext->fpe_mpls_flags) { + s = format(s, "%s", fib_path_ext_mpls_flags_names[attr]); + } + } + s = format(s, "]"); + } + s = format(s, " labels:[", path_ext->fpe_path_index); for (ii = 0; ii < vec_len(path_ext->fpe_path.frp_label_stack); ii++) { - s = format(s, "%U ", - format_mpls_unicast_label, - path_ext->fpe_path.frp_label_stack[ii]); + s = format(s, "[%U]", + format_fib_mpls_label, + &path_ext->fpe_path.frp_label_stack[ii]); } + s = format(s, "]"); break; + } case FIB_PATH_EXT_ADJ: { fib_path_ext_adj_attr_t attr; - s = format(s, "adj-flags:"); if (path_ext->fpe_adj_flags) { + s = format(s, "adj-flags:["); FOR_EACH_PATH_EXT_ADJ_ATTR(attr) { - s = format(s, "%s", fib_path_ext_adj_flags_names[attr]); + if ((1<<attr) & path_ext->fpe_adj_flags) + { + s = format(s, "%s", fib_path_ext_adj_flags_names[attr]); + } } - } - else - { - s = format(s, "None"); + s = format(s, "]"); } break; } @@ -121,12 +138,28 @@ fib_path_ext_init (fib_path_ext_t *path_ext, /** * @brief Return true if the label stack is implicit null + * imp-null and pop equate to the same this as this level - + * the label is coming off. */ static int fib_path_ext_is_imp_null (fib_path_ext_t *path_ext) { return ((1 == vec_len(path_ext->fpe_label_stack)) && - (MPLS_IETF_IMPLICIT_NULL_LABEL == path_ext->fpe_label_stack[0])); + ((MPLS_IETF_IMPLICIT_NULL_LABEL == path_ext->fpe_label_stack[0].fml_value) || + (MPLS_LABEL_POP == path_ext->fpe_label_stack[0].fml_value))); +} + +mpls_label_dpo_flags_t +fib_path_ext_mpls_flags_to_mpls_label (fib_path_ext_mpls_flags_t fpe_flags) +{ + mpls_label_dpo_flags_t ml_flags = MPLS_LABEL_DPO_FLAG_NONE; + + if (fpe_flags &FIB_PATH_EXT_MPLS_FLAG_NO_IP_TTL_DECR) + { + ml_flags |= MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR; + } + + return (ml_flags); } load_balance_path_t * @@ -236,24 +269,25 @@ fib_path_ext_stack (fib_path_ext_t *path_ext, * we pickup the correct MPLS imposition nodes to do * ip[46] processing. */ + dpo_id_t parent = DPO_INVALID; dpo_proto_t chain_proto; mpls_eos_bit_t eos; - index_t mldi; eos = (child_fct == FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS ? MPLS_NON_EOS : MPLS_EOS); chain_proto = fib_forw_chain_type_to_dpo_proto(child_fct); - mldi = mpls_label_dpo_create(path_ext->fpe_label_stack, - eos, 255, 0, - chain_proto, - &nh->path_dpo); + dpo_copy(&parent, &nh->path_dpo); + mpls_label_dpo_create(path_ext->fpe_label_stack, + eos, + chain_proto, + fib_path_ext_mpls_flags_to_mpls_label( + path_ext->fpe_mpls_flags), + &parent, + &nh->path_dpo); - dpo_set(&nh->path_dpo, - DPO_MPLS_LABEL, - chain_proto, - mldi); + dpo_reset(&parent); } else if (child_fct == FIB_FORW_CHAIN_TYPE_MPLS_EOS) { @@ -262,6 +296,7 @@ fib_path_ext_stack (fib_path_ext_t *path_ext, */ fib_path_stack_mpls_disp(nh->path_index, fib_forw_chain_type_to_dpo_proto(parent_fct), + path_ext->fpe_label_stack[0].fml_mode, &nh->path_dpo); } } diff --git a/src/vnet/fib/fib_path_ext.h b/src/vnet/fib/fib_path_ext.h index d07941c108b..b49fd977a20 100644 --- a/src/vnet/fib/fib_path_ext.h +++ b/src/vnet/fib/fib_path_ext.h @@ -60,6 +60,32 @@ typedef enum fib_path_ext_adj_flags_t_ _item++) /** + * Flags present on an MPLS label sourced path-extension + */ +typedef enum fib_path_ext_mpls_attr_t_ +{ + /** + * Do not decrement the TTL of IP packet during imposition + */ + FIB_PATH_EXT_MPLS_ATTR_NO_IP_TTL_DECR, +} fib_path_ext_mpls_attr_t; + +typedef enum fib_path_ext_mpls_flags_t_ +{ + FIB_PATH_EXT_MPLS_FLAG_NONE = 0, + FIB_PATH_EXT_MPLS_FLAG_NO_IP_TTL_DECR = (1 << FIB_PATH_EXT_MPLS_ATTR_NO_IP_TTL_DECR), +} fib_path_ext_mpls_flags_t; + +#define FIB_PATH_EXT_MPLS_ATTR_NAMES { \ + [FIB_PATH_EXT_MPLS_ATTR_NO_IP_TTL_DECR] = "no-ip-tll-decr", \ +} + +#define FOR_EACH_PATH_EXT_MPLS_ATTR(_item) \ + for (_item = FIB_PATH_EXT_MPLS_ATTR_NO_IP_TTL_DECR; \ + _item <= FIB_PATH_EXT_MPLS_ATTR_NO_IP_TTL_DECR; \ + _item++) + +/** * A path extension is a per-entry addition to the forwarding information * when packets are sent for that entry over that path. * @@ -86,6 +112,12 @@ typedef struct fib_path_ext_t_ * Flags describing the adj state */ fib_path_ext_adj_flags_t fpe_adj_flags; + /** + * For an MPLS type extension + * + * Flags describing the mpls state + */ + fib_path_ext_mpls_flags_t fpe_mpls_flags; }; /** @@ -98,7 +130,7 @@ typedef struct fib_path_ext_t_ * position in the path-list. */ fib_node_index_t fpe_path_index; -} __attribute__ ((packed)) fib_path_ext_t; +} __attribute__ ((packed)) fib_path_ext_t; extern u8 * format_fib_path_ext(u8 * s, va_list * args); diff --git a/src/vnet/fib/fib_table.c b/src/vnet/fib/fib_table.c index e9173484dec..324a35fe1e8 100644 --- a/src/vnet/fib/fib_table.c +++ b/src/vnet/fib/fib_table.c @@ -520,7 +520,7 @@ fib_table_entry_path_add (u32 fib_index, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, - mpls_label_t *next_hop_labels, + fib_mpls_label_t *next_hop_labels, fib_route_path_flags_t path_flags) { fib_route_path_t path = { @@ -770,7 +770,7 @@ fib_table_entry_update_one_path (u32 fib_index, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, - mpls_label_t *next_hop_labels, + fib_mpls_label_t *next_hop_labels, fib_route_path_flags_t path_flags) { fib_node_index_t fib_entry_index; diff --git a/src/vnet/fib/fib_table.h b/src/vnet/fib/fib_table.h index ddc00e537c2..ffad3c43d3e 100644 --- a/src/vnet/fib/fib_table.h +++ b/src/vnet/fib/fib_table.h @@ -338,7 +338,7 @@ extern fib_node_index_t fib_table_entry_path_add(u32 fib_index, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, - mpls_label_t *next_hop_label_stack, + fib_mpls_label_t *next_hop_label_stack, fib_route_path_flags_t pf); /** * @brief @@ -521,7 +521,7 @@ extern fib_node_index_t fib_table_entry_update_one_path(u32 fib_index, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, - mpls_label_t *next_hop_label_stack, + fib_mpls_label_t *next_hop_label_stack, fib_route_path_flags_t pf); /** diff --git a/src/vnet/fib/fib_test.c b/src/vnet/fib/fib_test.c index 2a30b3cd4cf..8f7bba0369a 100644 --- a/src/vnet/fib/fib_test.c +++ b/src/vnet/fib/fib_test.c @@ -301,7 +301,8 @@ fib_test_validate_rep_v (const replicate_t *rep, { const mpls_label_dpo_t *mld; mpls_label_t hdr; - FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type), + FIB_TEST_LB((mpls_label_dpo_get_type(MPLS_LABEL_DPO_FLAG_NONE) + == dpo->dpoi_type), "bucket %d stacks on %U", bucket, format_dpo_type, dpo->dpoi_type); @@ -375,14 +376,19 @@ fib_test_validate_lb_v (const load_balance_t *lb, case FT_LB_LABEL_STACK_O_ADJ: { const mpls_label_dpo_t *mld; + mpls_label_dpo_flags_t mf; mpls_label_t hdr; u32 ii; - FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type), + mf = ((exp->label_stack_o_adj.mode == + FIB_MPLS_LSP_MODE_UNIFORM) ? + MPLS_LABEL_DPO_FLAG_UNIFORM_MODE : + MPLS_LABEL_DPO_FLAG_NONE); + FIB_TEST_LB((mpls_label_dpo_get_type(mf) == dpo->dpoi_type), "bucket %d stacks on %U", bucket, format_dpo_type, dpo->dpoi_type); - + mld = mpls_label_dpo_get(dpo->dpoi_index); FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels, @@ -433,7 +439,8 @@ fib_test_validate_lb_v (const load_balance_t *lb, { const mpls_label_dpo_t *mld; mpls_label_t hdr; - FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type), + FIB_TEST_LB((mpls_label_dpo_get_type(MPLS_LABEL_DPO_FLAG_NONE) + == dpo->dpoi_type), "bucket %d stacks on %U", bucket, format_dpo_type, dpo->dpoi_type); @@ -468,13 +475,18 @@ fib_test_validate_lb_v (const load_balance_t *lb, case FT_LB_LABEL_O_LB: { const mpls_label_dpo_t *mld; + mpls_label_dpo_flags_t mf; mpls_label_t hdr; - FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type), + mf = ((exp->label_o_lb.mode == + FIB_MPLS_LSP_MODE_UNIFORM) ? + MPLS_LABEL_DPO_FLAG_UNIFORM_MODE : + MPLS_LABEL_DPO_FLAG_NONE); + FIB_TEST_LB((mpls_label_dpo_get_type(mf) == dpo->dpoi_type), "bucket %d stacks on %U", bucket, format_dpo_type, dpo->dpoi_type); - + mld = mpls_label_dpo_get(dpo->dpoi_index); hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl); @@ -515,15 +527,15 @@ fib_test_validate_lb_v (const load_balance_t *lb, bucket, exp->adj.adj); break; - case FT_LB_MPLS_DISP_O_ADJ: + case FT_LB_MPLS_DISP_PIPE_O_ADJ: { const mpls_disp_dpo_t *mdd; - FIB_TEST_I((DPO_MPLS_DISPOSITION == dpo->dpoi_type), + FIB_TEST_I((DPO_MPLS_DISPOSITION_PIPE == dpo->dpoi_type), "bucket %d stacks on %U", bucket, format_dpo_type, dpo->dpoi_type); - + mdd = mpls_disp_dpo_get(dpo->dpoi_index); dpo = &mdd->mdd_dpo; @@ -6332,8 +6344,10 @@ fib_test_label (void) .eos = MPLS_NON_EOS, }, }; - mpls_label_t *l99 = NULL; - vec_add1(l99, 99); + fib_mpls_label_t *l99 = NULL, fml99 = { + .fml_value = 99, + }; + vec_add1(l99, fml99); fib_table_entry_update_one_path(fib_index, &pfx_1_1_1_1_s_32, @@ -6371,8 +6385,10 @@ fib_test_label (void) .adj = ai_mpls_10_10_11_1, }, }; - mpls_label_t *l_imp_null = NULL; - vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL); + fib_mpls_label_t *l_imp_null = NULL, fml_imp_null = { + .fml_value = MPLS_IETF_IMPLICIT_NULL_LABEL, + }; + vec_add1(l_imp_null, fml_imp_null); fei = fib_table_entry_path_add(fib_index, &pfx_1_1_1_1_s_32, @@ -6413,7 +6429,7 @@ fib_test_label (void) .fp_eos = MPLS_NON_EOS, }; fib_test_lb_bucket_t disp_o_10_10_11_1 = { - .type = FT_LB_MPLS_DISP_O_ADJ, + .type = FT_LB_MPLS_DISP_PIPE_O_ADJ, .adj = { .adj = ai_v4_10_10_11_1, }, @@ -6458,7 +6474,7 @@ fib_test_label (void) }, }; fib_test_lb_bucket_t disp_o_10_10_11_2 = { - .type = FT_LB_MPLS_DISP_O_ADJ, + .type = FT_LB_MPLS_DISP_PIPE_O_ADJ, .adj = { .adj = ai_v4_10_10_11_2, }, @@ -6540,24 +6556,27 @@ fib_test_label (void) .lb = non_eos_1_1_1_1.dpoi_index, .label = 1600, .eos = MPLS_EOS, + .mode = FIB_MPLS_LSP_MODE_UNIFORM, }, }; - mpls_label_t *l1600 = NULL; - vec_add1(l1600, 1600); + fib_mpls_label_t *l1600 = NULL, fml1600 = { + .fml_value = 1600, + .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM, + }; + vec_add1(l1600, fml1600); - fib_table_entry_update_one_path(fib_index, - &pfx_2_2_2_2_s_32, - FIB_SOURCE_API, - FIB_ENTRY_FLAG_NONE, - DPO_PROTO_IP4, - &pfx_1_1_1_1_s_32.fp_addr, - ~0, - fib_index, - 1, - l1600, - FIB_ROUTE_PATH_FLAG_NONE); + fei = fib_table_entry_update_one_path(fib_index, + &pfx_2_2_2_2_s_32, + FIB_SOURCE_API, + FIB_ENTRY_FLAG_NONE, + DPO_PROTO_IP4, + &pfx_1_1_1_1_s_32.fp_addr, + ~0, + fib_index, + 1, + l1600, + FIB_ROUTE_PATH_FLAG_NONE); - fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32); FIB_TEST(fib_test_validate_entry(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, @@ -6811,7 +6830,7 @@ fib_test_label (void) * add back the path with the valid label */ l99 = NULL; - vec_add1(l99, 99); + vec_add1(l99, fml99); fib_table_entry_path_add(fib_index, &pfx_1_1_1_1_s_32, @@ -6941,8 +6960,10 @@ fib_test_label (void) .eos = MPLS_EOS, }, }; - mpls_label_t *l101 = NULL; - vec_add1(l101, 101); + fib_mpls_label_t *l101 = NULL, fml101 = { + .fml_value = 101, + }; + vec_add1(l101, fml101); fei = fib_table_entry_update_one_path(fib_index, &pfx_1_1_1_2_s_32, @@ -6981,8 +7002,10 @@ fib_test_label (void) .eos = MPLS_EOS, }, }; - mpls_label_t *l1601 = NULL; - vec_add1(l1601, 1601); + fib_mpls_label_t *l1601 = NULL, fml1601 = { + .fml_value = 1601, + }; + vec_add1(l1601, fml1601); l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index; @@ -7012,7 +7035,7 @@ fib_test_label (void) * the LB for the recursive can use an imp-null */ l_imp_null = NULL; - vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL); + vec_add1(l_imp_null, fml_imp_null); fei = fib_table_entry_update_one_path(fib_index, &pfx_1_1_1_2_s_32, @@ -7176,11 +7199,11 @@ fib_test_label (void) .eos = MPLS_EOS, }, }; - mpls_label_t *label_stack = NULL; + fib_mpls_label_t *label_stack = NULL; vec_validate(label_stack, 7); for (ii = 0; ii < 8; ii++) { - label_stack[ii] = ii + 200; + label_stack[ii].fml_value = ii + 200; } fei = fib_table_entry_update_one_path(fib_index, @@ -8255,12 +8278,13 @@ static int lfib_test (void) { const mpls_label_t deag_label = 50; + dpo_id_t dpo = DPO_INVALID; + const mpls_disp_dpo_t *mdd; const u32 lfib_index = 0; const u32 fib_index = 0; - dpo_id_t dpo = DPO_INVALID; + const lookup_dpo_t *lkd; const dpo_id_t *dpo1; fib_node_index_t lfe; - lookup_dpo_t *lkd; test_main_t *tm; int lb_count; adj_index_t ai_mpls_10_10_10_1; @@ -8327,7 +8351,6 @@ lfib_test (void) format_mpls_eos_bit, MPLS_EOS, format_dpo_proto, lkd->lkd_proto); - /* * A route deag route for EOS */ @@ -8358,7 +8381,14 @@ lfib_test (void) FIB_FORW_CHAIN_TYPE_MPLS_EOS, &dpo); dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0); - lkd = lookup_dpo_get(dpo1->dpoi_index); + mdd = mpls_disp_dpo_get(dpo1->dpoi_index); + + FIB_TEST((FIB_MPLS_LSP_MODE_PIPE == mdd->mdd_mode), + "%U/%U disp is pipe mode", + format_mpls_unicast_label, deag_label, + format_mpls_eos_bit, MPLS_EOS); + + lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index); FIB_TEST((fib_index == lkd->lkd_fib_index), "%U/%U is deag in %d %U", @@ -8383,6 +8413,70 @@ lfib_test (void) "%U/%U not present", format_mpls_unicast_label, deag_label, format_mpls_eos_bit, MPLS_EOS); + dpo_reset(&dpo); + + /* + * A route deag route for EOS with LSP mode uniform + */ + fib_mpls_label_t *l_pops = NULL, l_pop = { + .fml_value = MPLS_LABEL_POP, + .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM, + }; + vec_add1(l_pops, l_pop); + lfe = fib_table_entry_path_add(lfib_index, + &pfx, + FIB_SOURCE_CLI, + FIB_ENTRY_FLAG_NONE, + DPO_PROTO_IP4, + &zero_addr, + ~0, + fib_index, + 1, + l_pops, + FIB_ROUTE_PATH_FLAG_NONE); + + FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)), + "%U/%U present", + format_mpls_unicast_label, deag_label, + format_mpls_eos_bit, MPLS_EOS); + + fib_entry_contribute_forwarding(lfe, + FIB_FORW_CHAIN_TYPE_MPLS_EOS, + &dpo); + dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0); + mdd = mpls_disp_dpo_get(dpo1->dpoi_index); + + FIB_TEST((FIB_MPLS_LSP_MODE_UNIFORM == mdd->mdd_mode), + "%U/%U disp is uniform mode", + format_mpls_unicast_label, deag_label, + format_mpls_eos_bit, MPLS_EOS); + + lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index); + + FIB_TEST((fib_index == lkd->lkd_fib_index), + "%U/%U is deag in %d %U", + format_mpls_unicast_label, deag_label, + format_mpls_eos_bit, MPLS_EOS, + lkd->lkd_fib_index, + format_dpo_id, &dpo, 0); + FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input), + "%U/%U is dst deag", + format_mpls_unicast_label, deag_label, + format_mpls_eos_bit, MPLS_EOS); + FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto), + "%U/%U is %U dst deag", + format_mpls_unicast_label, deag_label, + format_mpls_eos_bit, MPLS_EOS, + format_dpo_proto, lkd->lkd_proto); + + fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI); + + FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index, + &pfx)), + "%U/%U not present", + format_mpls_unicast_label, deag_label, + format_mpls_eos_bit, MPLS_EOS); + dpo_reset(&dpo); /* * A route deag route for non-EOS @@ -8460,11 +8554,15 @@ lfib_test (void) }; dpo_id_t neos_1200 = DPO_INVALID; dpo_id_t ip_1200 = DPO_INVALID; - mpls_label_t *l200 = NULL; - vec_add1(l200, 200); - vec_add1(l200, 300); - vec_add1(l200, 400); - vec_add1(l200, 500); + fib_mpls_label_t *l200 = NULL; + u32 ii; + for (ii = 0; ii < 4; ii++) + { + fib_mpls_label_t fml = { + .fml_value = 200 + (ii * 100), + }; + vec_add1(l200, fml); + }; lfe = fib_table_entry_update_one_path(fib_index, &pfx_1200, @@ -8523,8 +8621,10 @@ lfib_test (void) .ip4.as_u32 = clib_host_to_net_u32(0x02020204), }, }; - mpls_label_t *l999 = NULL; - vec_add1(l999, 999); + fib_mpls_label_t *l999 = NULL, fml_999 = { + .fml_value = 999, + }; + vec_add1(l999, fml_999); rpaths[0].frp_label_stack = l999, fib_table_entry_path_add2(fib_index, @@ -8690,8 +8790,10 @@ lfib_test (void) .adj = idpo.dpoi_index, }, }; - mpls_label_t *l3300 = NULL; - vec_add1(l3300, 3300); + fib_mpls_label_t *l3300 = NULL, fml_3300 = { + .fml_value = 3300, + }; + vec_add1(l3300, fml_3300); lfe = fib_table_entry_update_one_path(lfib_index, &pfx_3500, @@ -8772,6 +8874,9 @@ lfib_test (void) 0, 1); mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API); + FIB_TEST(0 == pool_elts(mpls_disp_dpo_pool), + "mpls_disp_dpo resources freed %d of %d", + 0, pool_elts(mpls_disp_dpo_pool)); FIB_TEST(lb_count == pool_elts(load_balance_pool), "Load-balance resources freed %d of %d", lb_count, pool_elts(load_balance_pool)); diff --git a/src/vnet/fib/fib_test.h b/src/vnet/fib/fib_test.h index 0309b3f2311..8ac068350c4 100644 --- a/src/vnet/fib/fib_test.h +++ b/src/vnet/fib/fib_test.h @@ -29,7 +29,7 @@ typedef enum fib_test_lb_bucket_type_t_ { FT_LB_LABEL_STACK_O_ADJ, FT_LB_LABEL_O_LB, FT_LB_O_LB, - FT_LB_MPLS_DISP_O_ADJ, + FT_LB_MPLS_DISP_PIPE_O_ADJ, FT_LB_INTF, FT_LB_L2, FT_LB_BIER_TABLE, @@ -47,6 +47,7 @@ typedef struct fib_test_lb_bucket_t_ { { mpls_eos_bit_t eos; mpls_label_t label; + fib_mpls_lsp_mode_t mode; u8 ttl; adj_index_t adj; } label_o_adj; @@ -54,6 +55,7 @@ typedef struct fib_test_lb_bucket_t_ { { mpls_eos_bit_t eos; mpls_label_t label_stack[8]; + fib_mpls_lsp_mode_t mode; u8 label_stack_size; u8 ttl; adj_index_t adj; @@ -62,6 +64,7 @@ typedef struct fib_test_lb_bucket_t_ { { mpls_eos_bit_t eos; mpls_label_t label; + fib_mpls_lsp_mode_t mode; u8 ttl; index_t lb; } label_o_lb; diff --git a/src/vnet/fib/fib_types.api b/src/vnet/fib/fib_types.api index 61a0898819d..fde2c337190 100644 --- a/src/vnet/fib/fib_types.api +++ b/src/vnet/fib/fib_types.api @@ -12,6 +12,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +/** \brief MPLS label +*/ +typeonly define fib_mpls_label +{ + u8 is_uniform; + u32 label; + u8 ttl; + u8 exp; +}; /** \brief FIB path @param sw_if_index - index of the interface @@ -20,6 +30,8 @@ is prefered @param is_local - local if non-zero, else remote @param is_drop - Drop the packet + @param is_unreach - Drop the packet and rate limit send ICMP unreachable + @param is_prohibit - Drop the packet and rate limit send ICMP prohibited @param is_udp_encap - The path describes a UDP-o-IP encapsulation. @param afi - the afi of the next hop, IP46_TYPE_IP4=1, IP46_TYPE_IP6=2 @param next_hop[16] - the next hop address @@ -27,7 +39,7 @@ that has a unique identifier. e.g. the UDP encap object */ -typeonly define fib_path3 +typeonly define fib_path { u32 sw_if_index; u32 table_id; @@ -36,10 +48,12 @@ typeonly define fib_path3 u8 is_local; u8 is_drop; u8 is_udp_encap; + u8 is_unreach; + u8 is_prohibit; u8 afi; u8 next_hop[16]; u32 next_hop_id; u32 rpf_id; u8 n_labels; - u32 label_stack[16]; + vl_api_fib_mpls_label_t label_stack[16]; }; diff --git a/src/vnet/fib/fib_types.c b/src/vnet/fib/fib_types.c index f38c8154e0c..8b1faf5fa86 100644 --- a/src/vnet/fib/fib_types.c +++ b/src/vnet/fib/fib_types.c @@ -25,6 +25,7 @@ static const char* fib_protocol_names[] = FIB_PROTOCOLS; static const char* vnet_link_names[] = VNET_LINKS; static const char* fib_forw_chain_names[] = FIB_FORW_CHAINS; +static const char* fib_mpls_lsp_mode_names[] = FIB_MPLS_LSP_MODES; u8 * format_fib_protocol (u8 * s, va_list * ap) @@ -50,6 +51,30 @@ format_fib_forw_chain_type (u8 * s, va_list * args) return (format (s, "%s", fib_forw_chain_names[fct])); } +u8 * +format_fib_mpls_lsp_mode(u8 *s, va_list *ap) +{ + fib_mpls_lsp_mode_t mode = va_arg(*ap, int); + + return (format (s, "%s", fib_mpls_lsp_mode_names[mode])); +} + +u8 * +format_fib_mpls_label (u8 *s, va_list *ap) +{ + fib_mpls_label_t *label = va_arg(*ap, fib_mpls_label_t *); + + s = format(s, "%U %U ttl:%d exp:%d", + format_mpls_unicast_label, + label->fml_value, + format_fib_mpls_lsp_mode, + label->fml_mode, + label->fml_ttl, + label->fml_exp); + + return (s); +} + void fib_prefix_from_ip46_addr (const ip46_address_t *addr, fib_prefix_t *pfx) @@ -307,6 +332,29 @@ fib_forw_chain_type_to_link_type (fib_forward_chain_type_t fct) return (VNET_LINK_IP4); } +fib_forward_chain_type_t +fib_forw_chain_type_from_link_type (vnet_link_t link_type) +{ + switch (link_type) + { + case VNET_LINK_IP4: + return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4); + case VNET_LINK_IP6: + return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6); + case VNET_LINK_MPLS: + return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS); + case VNET_LINK_ETHERNET: + return (FIB_FORW_CHAIN_TYPE_ETHERNET); + case VNET_LINK_NSH: + return (FIB_FORW_CHAIN_TYPE_NSH); + case VNET_LINK_ARP: + break; + } + + ASSERT(0); + return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4); +} + dpo_proto_t fib_forw_chain_type_to_dpo_proto (fib_forward_chain_type_t fct) { @@ -475,7 +523,10 @@ unformat_fib_route_path (unformat_input_t * input, va_list * args) while (unformat (input, "%U", unformat_mpls_unicast_label, &out_label)) { - vec_add1(rpath->frp_label_stack, out_label); + fib_mpls_label_t fml = { + .fml_value = out_label, + }; + vec_add1(rpath->frp_label_stack, fml); } } else if (unformat (input, "%U", diff --git a/src/vnet/fib/fib_types.h b/src/vnet/fib/fib_types.h index 75ed7799f12..7f186ac6f6a 100644 --- a/src/vnet/fib/fib_types.h +++ b/src/vnet/fib/fib_types.h @@ -163,11 +163,16 @@ typedef enum fib_forward_chain_type_t_ { _item++) /** - * @brief Convert from a chain type to the adjacencies link type + * @brief Convert from a chain type to the adjacency's link type */ extern vnet_link_t fib_forw_chain_type_to_link_type(fib_forward_chain_type_t fct); /** + * @brief Convert from a adjacency's link type to chain type + */ +extern fib_forward_chain_type_t fib_forw_chain_type_from_link_type(vnet_link_t lt); + +/** * @brief Convert from a payload-protocol to a chain type. */ extern fib_forward_chain_type_t fib_forw_chain_type_from_dpo_proto(dpo_proto_t proto); @@ -373,6 +378,64 @@ typedef u32 fib_rpf_id_t; #define MFIB_RPF_ID_NONE (0) /** + * MPLS LSP mode - only valid at the head and tail + */ +typedef enum fib_mpls_lsp_mode_t_ +{ + /** + * Pipe Mode - the default. + * TTL and DSCP markings are not carried between the layers + */ + FIB_MPLS_LSP_MODE_PIPE, + /** + * Uniform mode. + * TTL and DSCP are copied between the layers + */ + FIB_MPLS_LSP_MODE_UNIFORM, +} __attribute__((packed)) fib_mpls_lsp_mode_t; + +#define FIB_MPLS_LSP_MODES { \ + [FIB_MPLS_LSP_MODE_PIPE] = "pipe", \ + [FIB_MPLS_LSP_MODE_UNIFORM] = "uniform", \ +} + +/** + * Format an LSP mode type + */ +extern u8 * format_fib_mpls_lsp_mode(u8 *s, va_list *ap); + +/** + * Configuration for each label value in the output-stack + */ +typedef struct fib_mpls_label_t_ +{ + /** + * The label value + */ + mpls_label_t fml_value; + + /** + * The LSP mode + */ + fib_mpls_lsp_mode_t fml_mode; + + /** + * TTL. valid only at imposition. + */ + u8 fml_ttl; + + /** + * EXP bits; valid only at imposition. + */ + u8 fml_exp; +} fib_mpls_label_t; + +/** + * Format an MPLS label + */ +extern u8 * format_fib_mpls_label(u8 *s, va_list *ap); + +/** * @brief * A representation of a path as described by a route producer. * These paramenters will determine the path 'type', of which there are: @@ -444,7 +507,7 @@ typedef struct fib_route_path_t_ { /** * The outgoing MPLS label Stack. NULL implies no label. */ - mpls_label_t *frp_label_stack; + fib_mpls_label_t *frp_label_stack; }; /** * A path that resolves via a BIER Table. diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api index b94d6d748b2..282f531e4fb 100644 --- a/src/vnet/ip/ip.api +++ b/src/vnet/ip/ip.api @@ -19,7 +19,8 @@ called through a shared memory interface. */ -option version = "1.0.1"; +option version = "1.1.0"; +import "vnet/fib/fib_types.api"; /** \brief Add / del table request A table can be added multiple times, but need be deleted only once. @@ -52,33 +53,6 @@ define ip_fib_dump u32 context; }; -/** \brief FIB path - @param sw_if_index - index of the interface - @param weight - The weight, for UCMP - @param preference - The preference of the path. lowest preference is prefered - @param is_local - local if non-zero, else remote - @param is_drop - Drop the packet - @param is_unreach - Drop the packet and rate limit send ICMP unreachable - @param is_prohibit - Drop the packet and rate limit send ICMP prohibited - @param afi - the afi of the next hop, IP46_TYPE_IP4=1, IP46_TYPE_IP6=2 - @param next_hop[16] - the next hop address - - WARNING: this type is replicated, pending cleanup completion -*/ -typeonly manual_print manual_endian define fib_path -{ - u32 sw_if_index; - u32 table_id; - u8 weight; - u8 preference; - u8 is_local; - u8 is_drop; - u8 is_unreach; - u8 is_prohibit; - u8 afi; - u8 next_hop[16]; -}; - /** \brief IP FIB table response @param table_id - IP fib table id @address_length - mask length @@ -420,7 +394,7 @@ autoreply define ip_add_del_route u8 next_hop_address[16]; u8 next_hop_n_out_labels; u32 next_hop_via_label; - u32 next_hop_out_label_stack[next_hop_n_out_labels]; + vl_api_fib_mpls_label_t next_hop_out_label_stack[next_hop_n_out_labels]; }; /** \brief Add / del route request diff --git a/src/vnet/ip/ip6_packet.h b/src/vnet/ip/ip6_packet.h index 76e3c1f93f0..a02f8b2ea8e 100644 --- a/src/vnet/ip/ip6_packet.h +++ b/src/vnet/ip/ip6_packet.h @@ -342,11 +342,27 @@ typedef struct } ip6_header_t; always_inline u8 -ip6_traffic_class (ip6_header_t * i) +ip6_traffic_class (const ip6_header_t * i) { return (i->ip_version_traffic_class_and_flow_label & 0x0FF00000) >> 20; } +static_always_inline u8 +ip6_traffic_class_network_order (const ip6_header_t * ip6) +{ + return (clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label) + & 0x0ff00000) >> 20; +} + +static_always_inline void +ip6_set_traffic_class_network_order (ip6_header_t * ip6, u8 dscp) +{ + u32 tmp = + clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label); + tmp |= (dscp << 20); + ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (tmp); +} + always_inline void * ip6_next_header (ip6_header_t * i) { diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c index 60fa2faf926..726d24ca5a8 100644 --- a/src/vnet/ip/ip_api.c +++ b/src/vnet/ip/ip_api.c @@ -867,7 +867,7 @@ add_del_route_t_handler (u8 is_multipath, u16 next_hop_weight, u16 next_hop_preference, mpls_label_t next_hop_via_label, - mpls_label_t * next_hop_out_label_stack) + fib_mpls_label_t * next_hop_out_label_stack) { vnet_classify_main_t *cm = &vnet_classify_main; fib_route_path_flags_t path_flags = FIB_ROUTE_PATH_FLAG_NONE; @@ -1071,7 +1071,7 @@ static int ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) { u32 fib_index, next_hop_fib_index; - mpls_label_t *label_stack = NULL; + fib_mpls_label_t *label_stack = NULL; int rv, ii, n_labels;; rv = add_del_route_check (FIB_PROTOCOL_IP4, @@ -1097,13 +1097,19 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) n_labels = mp->next_hop_n_out_labels; if (n_labels == 0) ; - else if (1 == n_labels) - vec_add1 (label_stack, ntohl (mp->next_hop_out_label_stack[0])); else { vec_validate (label_stack, n_labels - 1); for (ii = 0; ii < n_labels; ii++) - label_stack[ii] = ntohl (mp->next_hop_out_label_stack[ii]); + { + label_stack[ii].fml_value = + ntohl (mp->next_hop_out_label_stack[ii].label); + label_stack[ii].fml_ttl = mp->next_hop_out_label_stack[ii].ttl; + label_stack[ii].fml_exp = mp->next_hop_out_label_stack[ii].exp; + label_stack[ii].fml_mode = + (mp->next_hop_out_label_stack[ii].is_uniform ? + FIB_MPLS_LSP_MODE_UNIFORM : FIB_MPLS_LSP_MODE_PIPE); + } } return (add_del_route_t_handler (mp->is_multipath, @@ -1133,8 +1139,8 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) static int ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) { + fib_mpls_label_t *label_stack = NULL; u32 fib_index, next_hop_fib_index; - mpls_label_t *label_stack = NULL; int rv, ii, n_labels;; rv = add_del_route_check (FIB_PROTOCOL_IP6, @@ -1160,13 +1166,19 @@ ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) n_labels = mp->next_hop_n_out_labels; if (n_labels == 0) ; - else if (1 == n_labels) - vec_add1 (label_stack, ntohl (mp->next_hop_out_label_stack[0])); else { vec_validate (label_stack, n_labels - 1); for (ii = 0; ii < n_labels; ii++) - label_stack[ii] = ntohl (mp->next_hop_out_label_stack[ii]); + { + label_stack[ii].fml_value = + ntohl (mp->next_hop_out_label_stack[ii].label); + label_stack[ii].fml_ttl = mp->next_hop_out_label_stack[ii].ttl; + label_stack[ii].fml_exp = mp->next_hop_out_label_stack[ii].exp; + label_stack[ii].fml_mode = + (mp->next_hop_out_label_stack[ii].is_uniform ? + FIB_MPLS_LSP_MODE_UNIFORM : FIB_MPLS_LSP_MODE_PIPE); + } } return (add_del_route_t_handler (mp->is_multipath, diff --git a/src/vnet/mfib/mfib_test.c b/src/vnet/mfib/mfib_test.c index 2cb663a5eb6..f60d428cfcf 100644 --- a/src/vnet/mfib/mfib_test.c +++ b/src/vnet/mfib/mfib_test.c @@ -1108,8 +1108,10 @@ mfib_test_i (fib_protocol_t PROTO, .eos = MPLS_EOS, }, }; - mpls_label_t *l3300 = NULL; - vec_add1(l3300, 3300); + fib_mpls_label_t *l3300 = NULL, fml3300 = { + .fml_value = 3300, + }; + vec_add1(l3300, fml3300); /* * MPLS enable an interface so we get the MPLS table created diff --git a/src/vnet/mpls/mpls.api b/src/vnet/mpls/mpls.api index 572ac915a4a..6047d255aa7 100644 --- a/src/vnet/mpls/mpls.api +++ b/src/vnet/mpls/mpls.api @@ -13,7 +13,8 @@ * limitations under the License. */ -option version = "1.0.1"; +option version = "1.1.0"; +import "vnet/fib/fib_types.api"; /** \brief Bind/Unbind an MPLS local label to an IP prefix. i.e. create a per-prefix label entry. @@ -40,21 +41,6 @@ autoreply define mpls_ip_bind_unbind u8 mb_address[16]; }; -/** \brief MPLS tunnel Add / del route - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param mt_is_add - Is this a route add or delete - @param mt_sw_if_index - The SW interface index of the tunnel to delete - @param mt_is_multicast - Is the tunnel's underlying LSP multicast - @param mt_next_hop_proto_is_ip4 - The next-hop is IPV4 - @param mt_next_hop_weight - The weight, for UCMP - @param mt_next_hop_preference - The preference - @param mt_next_hop[16] - the nextop address - @param mt_next_hop_sw_if_index - the next-hop SW interface - @param mt_next_hop_table_id - the next-hop table-id (if appropriate) - @param mt_next_hop_n_out_labels - the number of next-hop output labels - @param mt_next_hop_out_label_stack - the next-hop output label stack, outer most first -*/ define mpls_tunnel_add_del { u32 client_index; @@ -70,7 +56,7 @@ define mpls_tunnel_add_del u8 mt_next_hop_n_out_labels; u32 mt_next_hop_sw_if_index; u32 mt_next_hop_table_id; - u32 mt_next_hop_out_label_stack[mt_next_hop_n_out_labels]; + vl_api_fib_mpls_label_t mt_next_hop_out_label_stack[mt_next_hop_n_out_labels]; }; /** \brief Reply for MPLS tunnel add / del request @@ -96,34 +82,6 @@ define mpls_tunnel_dump i32 tunnel_index; }; -/** \brief FIB path - @param sw_if_index - index of the interface - @param weight - The weight, for UCMP - @param is_local - local if non-zero, else remote - @param is_drop - Drop the packet - @param is_unreach - Drop the packet and rate limit send ICMP unreachable - @param is_prohibit - Drop the packet and rate limit send ICMP prohibited - @param afi - the afi of the next hop, IP46_TYPE_IP4=1, IP46_TYPE_IP6=2 - @param next_hop[16] - the next hop address - - WARNING: this type is replicated, pending cleanup completion - -*/ -typeonly manual_print manual_endian define fib_path2 -{ - u32 sw_if_index; - u32 table_id; - u8 weight; - u8 preference; - u8 is_local; - u8 is_drop; - u8 is_unreach; - u8 is_prohibit; - u8 afi; - u8 next_hop[16]; - u32 labels[16]; -}; - /** \brief mpls tunnel details */ manual_endian manual_print define mpls_tunnel_details @@ -134,7 +92,7 @@ manual_endian manual_print define mpls_tunnel_details u8 mt_l2_only; u8 mt_is_multicast; u32 mt_count; - vl_api_fib_path2_t mt_paths[mt_count]; + vl_api_fib_path_t mt_paths[mt_count]; }; /** \brief MPLS Route Add / del route @@ -207,7 +165,7 @@ autoreply define mpls_route_add_del u32 mr_next_hop_sw_if_index; u32 mr_next_hop_table_id; u32 mr_next_hop_via_label; - u32 mr_next_hop_out_label_stack[mr_next_hop_n_out_labels]; + vl_api_fib_mpls_label_t mr_next_hop_out_label_stack[mr_next_hop_n_out_labels]; }; /** \brief Dump MPLS fib table @@ -234,7 +192,7 @@ manual_endian manual_print define mpls_fib_details u8 eos_bit; u32 label; u32 count; - vl_api_fib_path2_t path[count]; + vl_api_fib_path_t path[count]; }; /** \brief Enable or Disable MPLS on and interface diff --git a/src/vnet/mpls/mpls.c b/src/vnet/mpls/mpls.c index 25957fb3fea..be72d3f829f 100644 --- a/src/vnet/mpls/mpls.c +++ b/src/vnet/mpls/mpls.c @@ -47,6 +47,9 @@ u8 * format_mpls_unicast_label (u8 * s, va_list * args) case MPLS_IETF_GAL_LABEL: s = format (s, "%s", MPLS_IETF_GAL_STRING); break; + case MPLS_LABEL_POP: + s = format (s, "pop"); + break; default: s = format (s, "%d", label); break; diff --git a/src/vnet/mpls/mpls_api.c b/src/vnet/mpls/mpls_api.c index 36fa610e8ca..169ee406a91 100644 --- a/src/vnet/mpls/mpls_api.c +++ b/src/vnet/mpls/mpls_api.c @@ -170,8 +170,8 @@ static int mpls_route_add_del_t_handler (vnet_main_t * vnm, vl_api_mpls_route_add_del_t * mp) { + fib_mpls_label_t *label_stack = NULL; u32 fib_index, next_hop_fib_index; - mpls_label_t *label_stack = NULL; int rv, ii, n_labels;; fib_prefix_t pfx = { @@ -211,13 +211,19 @@ mpls_route_add_del_t_handler (vnet_main_t * vnm, n_labels = mp->mr_next_hop_n_out_labels; if (n_labels == 0) ; - else if (1 == n_labels) - vec_add1 (label_stack, ntohl (mp->mr_next_hop_out_label_stack[0])); else { vec_validate (label_stack, n_labels - 1); for (ii = 0; ii < n_labels; ii++) - label_stack[ii] = ntohl (mp->mr_next_hop_out_label_stack[ii]); + { + label_stack[ii].fml_value = + ntohl (mp->mr_next_hop_out_label_stack[ii].label); + label_stack[ii].fml_ttl = mp->mr_next_hop_out_label_stack[ii].ttl; + label_stack[ii].fml_exp = mp->mr_next_hop_out_label_stack[ii].exp; + label_stack[ii].fml_mode = + (mp->mr_next_hop_out_label_stack[ii].is_uniform ? + FIB_MPLS_LSP_MODE_UNIFORM : FIB_MPLS_LSP_MODE_PIPE); + } } /* *INDENT-OFF* */ @@ -323,8 +329,16 @@ vl_api_mpls_tunnel_add_del_t_handler (vl_api_mpls_tunnel_add_del_t * mp) if (mp->mt_is_add) { for (ii = 0; ii < mp->mt_next_hop_n_out_labels; ii++) - vec_add1 (rpath.frp_label_stack, - ntohl (mp->mt_next_hop_out_label_stack[ii])); + { + fib_mpls_label_t fml = { + .fml_value = ntohl (mp->mt_next_hop_out_label_stack[ii].label), + .fml_ttl = mp->mt_next_hop_out_label_stack[ii].ttl, + .fml_exp = mp->mt_next_hop_out_label_stack[ii].exp, + .fml_mode = (mp->mt_next_hop_out_label_stack[ii].is_uniform ? + FIB_MPLS_LSP_MODE_UNIFORM : FIB_MPLS_LSP_MODE_PIPE), + }; + vec_add1 (rpath.frp_label_stack, fml); + } } vec_add1 (rpaths, rpath); @@ -388,7 +402,7 @@ send_mpls_tunnel_entry (u32 mti, void *arg) mpls_tunnel_send_walk_ctx_t *ctx; vl_api_mpls_tunnel_details_t *mp; const mpls_tunnel_t *mt; - vl_api_fib_path2_t *fp; + vl_api_fib_path_t *fp; u32 n; ctx = arg; @@ -399,8 +413,8 @@ send_mpls_tunnel_entry (u32 mti, void *arg) mt = mpls_tunnel_get (mti); n = fib_path_list_get_n_paths (mt->mt_path_list); - mp = vl_msg_api_alloc (sizeof (*mp) + n * sizeof (vl_api_fib_path2_t)); - memset (mp, 0, sizeof (*mp) + n * sizeof (vl_api_fib_path2_t)); + mp = vl_msg_api_alloc (sizeof (*mp) + n * sizeof (vl_api_fib_path_t)); + memset (mp, 0, sizeof (*mp) + n * sizeof (vl_api_fib_path_t)); mp->_vl_msg_id = ntohs (VL_API_MPLS_TUNNEL_DETAILS); mp->context = ctx->context; @@ -456,7 +470,7 @@ send_mpls_fib_details (vpe_api_main_t * am, { vl_api_mpls_fib_details_t *mp; fib_route_path_encode_t *api_rpath; - vl_api_fib_path2_t *fp; + vl_api_fib_path_t *fp; int path_count; path_count = vec_len (api_rpaths); diff --git a/src/vnet/mpls/mpls_input.c b/src/vnet/mpls/mpls_input.c index 86ad8bba270..d1881d4050b 100644 --- a/src/vnet/mpls/mpls_input.c +++ b/src/vnet/mpls/mpls_input.c @@ -51,10 +51,11 @@ format_mpls_input_trace (u8 * s, va_list * args) foreach_mpls_input_next; #undef _ - s = format (s, "MPLS: next %s[%d] label %d ttl %d", + s = format (s, "MPLS: next %s[%d] label %d ttl %d exp %d", next_name, t->next_index, vnet_mpls_uc_get_label(label), - vnet_mpls_uc_get_ttl(label)); + vnet_mpls_uc_get_ttl(label), + vnet_mpls_uc_get_exp(label)); return s; } @@ -74,21 +75,13 @@ mpls_input_inline (vlib_main_t * vm, vlib_frame_t * from_frame) { u32 n_left_from, next_index, * from, * to_next; - mpls_input_runtime_t * rt; - mpls_main_t * mm; + mpls_main_t * mm = &mpls_main; u32 thread_index = vlib_get_thread_index(); vlib_simple_counter_main_t * cm; vnet_main_t * vnm = vnet_get_main(); from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; - rt = vlib_node_get_runtime_data (vm, mpls_input_node.index); - mm = rt->mpls_main; - /* - * Force an initial lookup every time, in case the control-plane - * changed the label->FIB mapping. - */ - rt->last_label = ~0; next_index = node->cached_next_index; @@ -279,18 +272,11 @@ VLIB_NODE_FUNCTION_MULTIARCH (mpls_input_node, mpls_input) static void mpls_setup_nodes (vlib_main_t * vm) { - mpls_input_runtime_t * rt; pg_node_t * pn; pn = pg_get_node (mpls_input_node.index); pn->unformat_edit = unformat_pg_mpls_header; - rt = vlib_node_get_runtime_data (vm, mpls_input_node.index); - rt->last_label = (u32) ~0; - rt->last_inner_fib_index = 0; - rt->last_outer_fib_index = 0; - rt->mpls_main = &mpls_main; - ethernet_register_input_type (vm, ETHERNET_TYPE_MPLS, mpls_input_node.index); } @@ -309,16 +295,3 @@ static clib_error_t * mpls_input_init (vlib_main_t * vm) } VLIB_INIT_FUNCTION (mpls_input_init); - -static clib_error_t * mpls_input_worker_init (vlib_main_t * vm) -{ - mpls_input_runtime_t * rt; - rt = vlib_node_get_runtime_data (vm, mpls_input_node.index); - rt->last_label = (u32) ~0; - rt->last_inner_fib_index = 0; - rt->last_outer_fib_index = 0; - rt->mpls_main = &mpls_main; - return 0; -} - -VLIB_WORKER_INIT_FUNCTION (mpls_input_worker_init); diff --git a/src/vnet/mpls/mpls_tunnel.c b/src/vnet/mpls/mpls_tunnel.c index 8ed2c409ce8..c2067d81b00 100644 --- a/src/vnet/mpls/mpls_tunnel.c +++ b/src/vnet/mpls/mpls_tunnel.c @@ -123,6 +123,12 @@ mpls_tunnel_collect_forwarding (fib_node_index_t pl_index, path_ext = fib_path_ext_list_find_by_path_index(&ctx->mt->mt_path_exts, path_index); + /* + * we don't want IP TTL decrements for packets hitting the MPLS labels + * we stack on, since the IP TTL decrement is done by the adj + */ + path_ext->fpe_mpls_flags |= FIB_PATH_EXT_MPLS_FLAG_NO_IP_TTL_DECR; + if (NULL != path_ext) { /* @@ -273,9 +279,8 @@ mpls_tunnel_stack (adj_index_t ai) mpls_tunnel_mk_lb(mt, adj->ia_link, - (VNET_LINK_MPLS == adj_get_link_type(ai) ? - FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS: - FIB_FORW_CHAIN_TYPE_MPLS_EOS), + fib_forw_chain_type_from_link_type( + adj_get_link_type(ai)), &dpo); adj_nbr_midchain_stack(ai, &dpo); @@ -521,6 +526,11 @@ mpls_tunnel_tx (vlib_main_t * vm, b0 = vlib_get_buffer(vm, bi0); vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mt->mt_l2_lb.dpoi_index; + /* since we are coming out of the L2 world, where the vlib_buffer + * union is used for other things, make sure it is clean for + * MPLS from now on. + */ + vnet_buffer(b0)->mpls.first = 0; if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { diff --git a/src/vnet/mpls/mpls_types.h b/src/vnet/mpls/mpls_types.h index f1c3191e00c..c21bdf1eace 100644 --- a/src/vnet/mpls/mpls_types.h +++ b/src/vnet/mpls/mpls_types.h @@ -47,6 +47,14 @@ #define MPLS_LABEL_INVALID (MPLS_IETF_MAX_LABEL+1) +/** + * A value that is explicit about the end of the LSP. Specifying + * a label value is needed when the mode configuration (pipe/uniform) + * is also requested. + * imp-null implies a label swap. pop can be used for a deag. + */ +#define MPLS_LABEL_POP (MPLS_IETF_MAX_LABEL+2) + #define MPLS_LABEL_IS_REAL(_lbl) \ (((_lbl) > MPLS_IETF_MIN_UNRES_LABEL) && \ ((_lbl) <= MPLS_IETF_MAX_UNRES_LABEL)) diff --git a/src/vnet/mpls/packet.h b/src/vnet/mpls/packet.h index bc67445be89..ca6ac407686 100644 --- a/src/vnet/mpls/packet.h +++ b/src/vnet/mpls/packet.h @@ -42,6 +42,32 @@ typedef enum mpls_eos_bit_t_ [MPLS_EOS] = "eos", \ } +/** + * The Default TTL added to MPLS label headers when no other value is available + */ +#define MPLS_LABEL_DEFAULT_TTL 64 + +/** + * The Default EXP added to MPLS label headers when no other value is available + */ +#define MPLS_LABEL_DEFAULT_EXP 0 + +/** + * When in uniform mode convert an IPv[46] DSCP value to an MPLS EXP value + */ +static inline u8 ip_dscp_to_mpls_exp (u8 tos) +{ + return (tos >> 5); +} + +/** + * When in uniform mode convert an MPLS EXP value to an IPv[46] DSCP value + */ +static inline u8 mpls_exp_to_ip_dscp (u8 exp) +{ + return (exp << 5); +} + #define FOR_EACH_MPLS_EOS_BIT(_eos) \ for (_eos = MPLS_NON_EOS; _eos <= MPLS_EOS; _eos++) diff --git a/src/vnet/srmpls/sr_mpls_policy.c b/src/vnet/srmpls/sr_mpls_policy.c index 1a5ba6c6c30..4a563248ce0 100755 --- a/src/vnet/srmpls/sr_mpls_policy.c +++ b/src/vnet/srmpls/sr_mpls_policy.c @@ -34,9 +34,6 @@ #include <vnet/srmpls/sr_mpls.h> #include <vnet/fib/mpls_fib.h> #include <vnet/dpo/dpo.h> -#include <vnet/dpo/replicate_dpo.h> -#include <vnet/dpo/mpls_label_dpo.h> -#include <vnet/dpo/lookup_dpo.h> #include <vnet/ip/ip.h> #include <vppinfra/error.h> @@ -763,7 +760,11 @@ sr_mpls_policy_assign_endpoint_color (mpls_label_t bsid, FIB_SOURCE_SR, FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths); - vec_add1 (path.frp_label_stack, MPLS_IETF_IMPLICIT_NULL_LABEL); + fib_mpls_label_t fml = { + .fml_value = MPLS_IETF_IMPLICIT_NULL_LABEL, + }; + + vec_add1 (path.frp_label_stack, fml); pfx.fp_eos = MPLS_NON_EOS; path.frp_eos = MPLS_NON_EOS; diff --git a/src/vnet/srmpls/sr_mpls_steering.c b/src/vnet/srmpls/sr_mpls_steering.c index 0bd34665c3d..8bb072c8812 100755 --- a/src/vnet/srmpls/sr_mpls_steering.c +++ b/src/vnet/srmpls/sr_mpls_steering.c @@ -301,7 +301,10 @@ compute_sr_te_automated_steering_fib_entry (mpls_sr_steering_policy_t * if (steer_pl->vpn_label != (u32) ~ 0) { - vec_add1 (path.frp_label_stack, steer_pl->vpn_label); + fib_mpls_label_t fml = { + .fml_value = steer_pl->vpn_label, + }; + vec_add1 (path.frp_label_stack, fml); path.frp_eos = MPLS_NON_EOS; } @@ -480,7 +483,12 @@ sr_mpls_steering_policy_add (mpls_label_t bsid, u32 table_id, fib_route_path_t *paths = NULL; if (steer_pl->vpn_label != (u32) ~ 0) - vec_add1 (path.frp_label_stack, steer_pl->vpn_label); + { + fib_mpls_label_t fml = { + .fml_value = steer_pl->vpn_label, + }; + vec_add1 (path.frp_label_stack, fml); + } /* FIB API calls - Recursive route through the BindingSID */ if (traffic_type == SR_STEER_IPV6) diff --git a/src/vnet/vxlan/vxlan.api b/src/vnet/vxlan/vxlan.api index 3a07d92f79b..dae96af6e10 100644 --- a/src/vnet/vxlan/vxlan.api +++ b/src/vnet/vxlan/vxlan.api @@ -28,7 +28,6 @@ option version = "1.1.0"; @param decap_next_index - Name of decap next graph node @param vni - The VXLAN Network Identifier, uint24 */ - define vxlan_add_del_tunnel { u32 client_index; |