From 31ed74407643595fdce206e9d7487108fb8b33ab Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Fri, 23 Feb 2018 05:29:09 -0800 Subject: [PATCH] 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 --- src/vat/api_format.c | 16 +- src/vnet/adj/adj_l2.c | 5 + src/vnet/bier/bier.api | 10 +- src/vnet/bier/bier_api.c | 20 +- src/vnet/bier/bier_fmask.c | 9 +- src/vnet/bier/bier_output.c | 4 +- src/vnet/bier/bier_test.c | 30 +- src/vnet/buffer.h | 2 + src/vnet/dpo/dpo.h | 8 +- src/vnet/dpo/mpls_disposition.c | 316 ++++++++--- src/vnet/dpo/mpls_disposition.h | 15 +- src/vnet/dpo/mpls_label_dpo.c | 1075 ++++++++++++++++++++++++++++-------- src/vnet/dpo/mpls_label_dpo.h | 65 ++- src/vnet/fib/fib_api.h | 2 +- src/vnet/fib/fib_entry_src.c | 4 +- src/vnet/fib/fib_path.c | 20 +- src/vnet/fib/fib_path.h | 1 + src/vnet/fib/fib_path_ext.c | 77 ++- src/vnet/fib/fib_path_ext.h | 34 +- src/vnet/fib/fib_table.c | 4 +- src/vnet/fib/fib_table.h | 4 +- src/vnet/fib/fib_test.c | 205 +++++-- src/vnet/fib/fib_test.h | 5 +- src/vnet/fib/fib_types.api | 18 +- src/vnet/fib/fib_types.c | 53 +- src/vnet/fib/fib_types.h | 67 ++- src/vnet/ip/ip.api | 32 +- src/vnet/ip/ip6_packet.h | 18 +- src/vnet/ip/ip_api.c | 30 +- src/vnet/mfib/mfib_test.c | 6 +- src/vnet/mpls/mpls.api | 54 +- src/vnet/mpls/mpls.c | 3 + src/vnet/mpls/mpls_api.c | 34 +- src/vnet/mpls/mpls_input.c | 35 +- src/vnet/mpls/mpls_tunnel.c | 16 +- src/vnet/mpls/mpls_types.h | 8 + src/vnet/mpls/packet.h | 26 + src/vnet/srmpls/sr_mpls_policy.c | 9 +- src/vnet/srmpls/sr_mpls_steering.c | 12 +- src/vnet/vxlan/vxlan.api | 1 - test/test_bier.py | 29 +- test/test_mpls.py | 841 ++++++++++++++++------------ test/test_udp.py | 12 +- test/vpp_bier.py | 29 +- test/vpp_ip_route.py | 44 +- test/vpp_mpls_tunnel_interface.py | 8 +- test/vpp_papi_provider.py | 21 +- 47 files changed, 2324 insertions(+), 1013 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 #include +/** + * 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 */ @@ -46,10 +82,15 @@ 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 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<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<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 @@ -59,6 +59,32 @@ typedef enum fib_path_ext_adj_flags_t_ _item <= FIB_PATH_EXT_ADJ_ATTR_REFINES_COVER; \ _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,10 +163,15 @@ 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. */ @@ -372,6 +377,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. @@ -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 #include #include -#include -#include -#include #include #include @@ -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; diff --git a/test/test_bier.py b/test/test_bier.py index ae7b46a130c..c7ec0eed127 100644 --- a/test/test_bier.py +++ b/test/test_bier.py @@ -6,7 +6,8 @@ import socket from framework import VppTestCase, VppTestRunner, running_extended_tests from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \ VppMplsTable, VppIpMRoute, VppMRoutePath, VppIpTable, \ - MRouteEntryFlags, MRouteItfFlags, MPLS_LABEL_INVALID, DpoProto + MRouteEntryFlags, MRouteItfFlags, MPLS_LABEL_INVALID, DpoProto, \ + VppMplsLabel from vpp_bier import * from vpp_udp_encap import * @@ -99,15 +100,17 @@ class TestBier(VppTestCase): bier_routes = [] for i in range(1, max_bp+1): nh = "10.0.%d.%d" % (i / 255, i % 255) - nh_routes.append(VppIpRoute(self, nh, 32, - [VppRoutePath(self.pg1.remote_ip4, - self.pg1.sw_if_index, - labels=[2000+i])])) + nh_routes.append( + VppIpRoute(self, nh, 32, + [VppRoutePath(self.pg1.remote_ip4, + self.pg1.sw_if_index, + labels=[VppMplsLabel(2000+i)])])) nh_routes[-1].add_vpp_config() - bier_routes.append(VppBierRoute(self, bti, i, - [VppRoutePath(nh, 0xffffffff, - labels=[100+i])])) + bier_routes.append( + VppBierRoute(self, bti, i, + [VppRoutePath(nh, 0xffffffff, + labels=[VppMplsLabel(100+i)])])) bier_routes[-1].add_vpp_config() # @@ -216,20 +219,20 @@ class TestBier(VppTestCase): ip_route_1 = VppIpRoute(self, nh1, 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, - labels=[2001])]) + labels=[VppMplsLabel(2001)])]) ip_route_2 = VppIpRoute(self, nh2, 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, - labels=[2002])]) + labels=[VppMplsLabel(2002)])]) ip_route_1.add_vpp_config() ip_route_2.add_vpp_config() bier_route_1 = VppBierRoute(self, bti, 1, [VppRoutePath(nh1, 0xffffffff, - labels=[101])]) + labels=[VppMplsLabel(101)])]) bier_route_2 = VppBierRoute(self, bti, 2, [VppRoutePath(nh2, 0xffffffff, - labels=[102])]) + labels=[VppMplsLabel(102)])]) bier_route_1.add_vpp_config() bier_route_2.add_vpp_config() @@ -561,7 +564,7 @@ class TestBier(VppTestCase): ip_route = VppIpRoute(self, nh1, 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, - labels=[2001])]) + labels=[VppMplsLabel(2001)])]) ip_route.add_vpp_config() udp_encap = VppUdpEncap(self, 4, diff --git a/test/test_mpls.py b/test/test_mpls.py index aa5e67439b7..33fed680dbe 100644 --- a/test/test_mpls.py +++ b/test/test_mpls.py @@ -6,7 +6,8 @@ import socket from framework import VppTestCase, VppTestRunner from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \ VppMplsIpBind, VppIpMRoute, VppMRoutePath, \ - MRouteItfFlags, MRouteEntryFlags, DpoProto, VppIpTable, VppMplsTable + MRouteItfFlags, MRouteEntryFlags, DpoProto, VppIpTable, VppMplsTable, \ + VppMplsLabel, MplsLspMode from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface from scapy.packet import Raw @@ -25,7 +26,7 @@ def verify_filter(capture, sent): return capture -def verify_mpls_stack(tst, rx, mpls_labels, ttl=255, num=0): +def verify_mpls_stack(tst, rx, mpls_labels): # the rx'd packet has the MPLS label popped eth = rx[Ether] tst.assertEqual(eth.type, 0x8847) @@ -33,12 +34,10 @@ def verify_mpls_stack(tst, rx, mpls_labels, ttl=255, num=0): rx_mpls = rx[MPLS] for ii in range(len(mpls_labels)): - tst.assertEqual(rx_mpls.label, mpls_labels[ii]) - tst.assertEqual(rx_mpls.cos, 0) - if ii == num: - tst.assertEqual(rx_mpls.ttl, ttl) - else: - tst.assertEqual(rx_mpls.ttl, 255) + tst.assertEqual(rx_mpls.label, mpls_labels[ii].value) + tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp) + tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl) + if ii == len(mpls_labels) - 1: tst.assertEqual(rx_mpls.s, 1) else: @@ -102,11 +101,11 @@ class TestMPLS(VppTestCase): self, src_if, mpls_labels, - mpls_ttl=255, ping=0, ip_itf=None, dst_ip=None, chksum=None, + ip_ttl=64, n=257): self.reset_packet_infos() pkts = [] @@ -116,22 +115,24 @@ class TestMPLS(VppTestCase): p = Ether(dst=src_if.local_mac, src=src_if.remote_mac) for ii in range(len(mpls_labels)): - if ii == len(mpls_labels) - 1: - p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=1) - else: - p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=0) + p = p / MPLS(label=mpls_labels[ii].value, + ttl=mpls_labels[ii].ttl, + cos=mpls_labels[ii].exp) if not ping: if not dst_ip: - p = (p / IP(src=src_if.local_ip4, dst=src_if.remote_ip4) / + p = (p / IP(src=src_if.local_ip4, + dst=src_if.remote_ip4, + ttl=ip_ttl) / UDP(sport=1234, dport=1234) / Raw(payload)) else: - p = (p / IP(src=src_if.local_ip4, dst=dst_ip) / + p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) / UDP(sport=1234, dport=1234) / Raw(payload)) else: p = (p / IP(src=ip_itf.remote_ip4, - dst=ip_itf.local_ip4) / + dst=ip_itf.local_ip4, + ttl=ip_ttl) / ICMP()) if chksum: @@ -140,39 +141,58 @@ class TestMPLS(VppTestCase): pkts.append(p) return pkts - def create_stream_ip4(self, src_if, dst_ip): + def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0): self.reset_packet_infos() pkts = [] for i in range(0, 257): info = self.create_packet_info(src_if, src_if) payload = self.info_to_payload(info) p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / - IP(src=src_if.remote_ip4, dst=dst_ip) / + IP(src=src_if.remote_ip4, dst=dst_ip, + ttl=ip_ttl, tos=ip_dscp) / UDP(sport=1234, dport=1234) / Raw(payload)) info.data = p.copy() pkts.append(p) return pkts - def create_stream_labelled_ip6(self, src_if, mpls_label, mpls_ttl, - dst_ip=None, hlim=64): - if dst_ip is None: - dst_ip = src_if.remote_ip6 + def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0): self.reset_packet_infos() pkts = [] for i in range(0, 257): info = self.create_packet_info(src_if, src_if) payload = self.info_to_payload(info) p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / - MPLS(label=mpls_label, ttl=mpls_ttl) / - IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) / + IPv6(src=src_if.remote_ip6, dst=dst_ip, + hlim=ip_ttl, tc=ip_dscp) / UDP(sport=1234, dport=1234) / Raw(payload)) info.data = p.copy() pkts.append(p) return pkts - def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0): + def create_stream_labelled_ip6(self, src_if, mpls_labels, + hlim=64, dst_ip=None): + if dst_ip is None: + dst_ip = src_if.remote_ip6 + self.reset_packet_infos() + pkts = [] + for i in range(0, 257): + info = self.create_packet_info(src_if, src_if) + payload = self.info_to_payload(info) + p = Ether(dst=src_if.local_mac, src=src_if.remote_mac) + for l in mpls_labels: + p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp) + + p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) / + UDP(sport=1234, dport=1234) / + Raw(payload)) + info.data = p.copy() + pkts.append(p) + return pkts + + def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0, + ip_ttl=None, ip_dscp=0): try: capture = verify_filter(capture, sent) @@ -192,8 +212,12 @@ class TestMPLS(VppTestCase): if not ping_resp: self.assertEqual(rx_ip.src, tx_ip.src) self.assertEqual(rx_ip.dst, tx_ip.dst) - # IP processing post pop has decremented the TTL - self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl) + self.assertEqual(rx_ip.tos, ip_dscp) + if not ip_ttl: + # IP processing post pop has decremented the TTL + self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl) + else: + self.assertEqual(rx_ip.ttl, ip_ttl) else: self.assertEqual(rx_ip.src, tx_ip.dst) self.assertEqual(rx_ip.dst, tx_ip.src) @@ -202,7 +226,7 @@ class TestMPLS(VppTestCase): raise def verify_capture_labelled_ip4(self, src_if, capture, sent, - mpls_labels): + mpls_labels, ip_ttl=None): try: capture = verify_filter(capture, sent) @@ -214,22 +238,46 @@ class TestMPLS(VppTestCase): tx_ip = tx[IP] rx_ip = rx[IP] - # the MPLS TTL is copied from the IP - verify_mpls_stack(self, rx, mpls_labels, rx_ip.ttl, - len(mpls_labels) - 1) + verify_mpls_stack(self, rx, mpls_labels) self.assertEqual(rx_ip.src, tx_ip.src) self.assertEqual(rx_ip.dst, tx_ip.dst) - # IP processing post pop has decremented the TTL - self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl) + if not ip_ttl: + # IP processing post pop has decremented the TTL + self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl) + else: + self.assertEqual(rx_ip.ttl, ip_ttl) + + except: + raise + + def verify_capture_labelled_ip6(self, src_if, capture, sent, + mpls_labels, ip_ttl=None): + try: + capture = verify_filter(capture, sent) + + self.assertEqual(len(capture), len(sent)) + + for i in range(len(capture)): + tx = sent[i] + rx = capture[i] + tx_ip = tx[IPv6] + rx_ip = rx[IPv6] + + verify_mpls_stack(self, rx, mpls_labels) + + self.assertEqual(rx_ip.src, tx_ip.src) + self.assertEqual(rx_ip.dst, tx_ip.dst) + if not ip_ttl: + # IP processing post pop has decremented the TTL + self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim) + else: + self.assertEqual(rx_ip.hlim, ip_ttl) except: raise - def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels, - ttl=255, top=None): - if top is None: - top = len(mpls_labels) - 1 + def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels): try: capture = verify_filter(capture, sent) @@ -241,8 +289,7 @@ class TestMPLS(VppTestCase): tx_ip = tx[IP] rx_ip = rx[IP] - # the MPLS TTL is 255 since it enters a new tunnel - verify_mpls_stack(self, rx, mpls_labels, ttl, top) + verify_mpls_stack(self, rx, mpls_labels) self.assertEqual(rx_ip.src, tx_ip.src) self.assertEqual(rx_ip.dst, tx_ip.dst) @@ -253,7 +300,7 @@ class TestMPLS(VppTestCase): raise def verify_capture_labelled(self, src_if, capture, sent, - mpls_labels, ttl=254, num=0): + mpls_labels): try: capture = verify_filter(capture, sent) @@ -261,11 +308,12 @@ class TestMPLS(VppTestCase): for i in range(len(capture)): rx = capture[i] - verify_mpls_stack(self, rx, mpls_labels, ttl, num) + verify_mpls_stack(self, rx, mpls_labels) except: raise - def verify_capture_ip6(self, src_if, capture, sent): + def verify_capture_ip6(self, src_if, capture, sent, + ip_hlim=None, ip_dscp=0): try: self.assertEqual(len(capture), len(sent)) @@ -282,8 +330,12 @@ class TestMPLS(VppTestCase): self.assertEqual(rx_ip.src, tx_ip.src) self.assertEqual(rx_ip.dst, tx_ip.dst) + self.assertEqual(rx_ip.tc, ip_dscp) # IP processing post pop has decremented the TTL - self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim) + if not ip_hlim: + self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim) + else: + self.assertEqual(rx_ip.hlim, ip_hlim) except: raise @@ -323,22 +375,18 @@ class TestMPLS(VppTestCase): route_32_eos = VppMplsRoute(self, 32, 1, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, - labels=[33])]) + labels=[VppMplsLabel(33)])]) route_32_eos.add_vpp_config() # # a stream that matches the route for 10.0.0.1 # PG0 is in the default table # - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [32]) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() - self.verify_capture_labelled(self.pg0, rx, tx, [33]) + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(32, ttl=32, exp=1)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled(self.pg0, rx, tx, + [VppMplsLabel(33, ttl=31, exp=1)]) # # A simple MPLS xconnect - non-eos label in label out @@ -346,22 +394,38 @@ class TestMPLS(VppTestCase): route_32_neos = VppMplsRoute(self, 32, 0, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, - labels=[33])]) + labels=[VppMplsLabel(33)])]) route_32_neos.add_vpp_config() # # a stream that matches the route for 10.0.0.1 # PG0 is in the default table # - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [32, 99]) - self.pg0.add_stream(tx) + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(32, ttl=21, exp=7), + VppMplsLabel(99)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled(self.pg0, rx, tx, + [VppMplsLabel(33, ttl=20, exp=7), + VppMplsLabel(99)]) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() + # + # A simple MPLS xconnect - non-eos label in label out, uniform mode + # + route_42_neos = VppMplsRoute( + self, 42, 0, + [VppRoutePath(self.pg0.remote_ip4, + self.pg0.sw_if_index, + labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])]) + route_42_neos.add_vpp_config() - rx = self.pg0.get_capture() - self.verify_capture_labelled(self.pg0, rx, tx, [33, 99]) + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(42, ttl=21, exp=7), + VppMplsLabel(99)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled(self.pg0, rx, tx, + [VppMplsLabel(43, ttl=20, exp=7), + VppMplsLabel(99)]) # # An MPLS xconnect - EOS label in IP out @@ -372,25 +436,40 @@ class TestMPLS(VppTestCase): labels=[])]) route_33_eos.add_vpp_config() - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [33]) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() + tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_capture_ip4(self.pg0, rx, tx) # # disposed packets have an invalid IPv4 checkusm # - tx = self.create_stream_labelled_ip4(self.pg0, [33], + tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)], dst_ip=self.pg0.remote_ip4, n=65, chksum=1) self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum") + # + # An MPLS xconnect - EOS label in IP out, uniform mode + # + route_3333_eos = VppMplsRoute( + self, 3333, 1, + [VppRoutePath(self.pg0.remote_ip4, + self.pg0.sw_if_index, + labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])]) + route_3333_eos.add_vpp_config() + + tx = self.create_stream_labelled_ip4( + self.pg0, + [VppMplsLabel(3333, ttl=55, exp=3)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60) + tx = self.create_stream_labelled_ip4( + self.pg0, + [VppMplsLabel(3333, ttl=66, exp=4)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80) + # # An MPLS xconnect - EOS label in IPv6 out # @@ -402,33 +481,18 @@ class TestMPLS(VppTestCase): proto=DpoProto.DPO_PROTO_IP6)]) route_333_eos.add_vpp_config() - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip6(self.pg0, [333], 64) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() + tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_capture_ip6(self.pg0, rx, tx) # # disposed packets have an TTL expired # - tx = self.create_stream_labelled_ip6(self.pg0, [333], 64, + tx = self.create_stream_labelled_ip6(self.pg0, + [VppMplsLabel(333, ttl=64)], dst_ip=self.pg1.remote_ip6, hlim=1) - - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip6(self.pg0, [333], 64, - dst_ip=self.pg1.remote_ip6, - hlim=0) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() + rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_capture_ip6_icmp(self.pg0, rx, tx) # @@ -438,33 +502,39 @@ class TestMPLS(VppTestCase): self, 334, 1, [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, - labels=[3], + labels=[VppMplsLabel(3)], proto=DpoProto.DPO_PROTO_IP6)]) route_334_eos.add_vpp_config() - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip6(self.pg0, [334], 64) - self.pg0.add_stream(tx) + tx = self.create_stream_labelled_ip6(self.pg0, + [VppMplsLabel(334, ttl=64)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_ip6(self.pg0, rx, tx) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() + # + # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode + # + route_335_eos = VppMplsRoute( + self, 335, 1, + [VppRoutePath(self.pg0.remote_ip6, + self.pg0.sw_if_index, + labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)], + proto=DpoProto.DPO_PROTO_IP6)]) + route_335_eos.add_vpp_config() - rx = self.pg0.get_capture() - self.verify_capture_ip6(self.pg0, rx, tx) + tx = self.create_stream_labelled_ip6( + self.pg0, + [VppMplsLabel(335, ttl=27, exp=4)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80) # # disposed packets have an TTL expired # - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip6(self.pg0, [334], 64, + tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)], dst_ip=self.pg1.remote_ip6, hlim=0) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() + rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_capture_ip6_icmp(self.pg0, rx, tx) # @@ -477,33 +547,51 @@ class TestMPLS(VppTestCase): labels=[])]) route_33_neos.add_vpp_config() - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [33, 99]) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.assert_nothing_captured( - remark="MPLS non-EOS packets popped and forwarded") + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(33), + VppMplsLabel(99)]) + self.send_and_assert_no_replies( + self.pg0, tx, + "MPLS non-EOS packets popped and forwarded") # # A recursive EOS x-connect, which resolves through another x-connect + # in pipe mode # route_34_eos = VppMplsRoute(self, 34, 1, [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=32, - labels=[44, 45])]) + labels=[VppMplsLabel(44), + VppMplsLabel(45)])]) route_34_eos.add_vpp_config() - tx = self.create_stream_labelled_ip4(self.pg0, [34]) - self.pg0.add_stream(tx) + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(34, ttl=3)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled(self.pg0, rx, tx, + [VppMplsLabel(33), + VppMplsLabel(44), + VppMplsLabel(45, ttl=2)]) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() + # + # A recursive EOS x-connect, which resolves through another x-connect + # in uniform mode + # + route_35_eos = VppMplsRoute( + self, 35, 1, + [VppRoutePath("0.0.0.0", + 0xffffffff, + nh_via_label=42, + labels=[VppMplsLabel(44)])]) + route_35_eos.add_vpp_config() - rx = self.pg0.get_capture() - self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 45], num=2) + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(35, ttl=3)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled(self.pg0, rx, tx, + [VppMplsLabel(43, ttl=2), + VppMplsLabel(44, ttl=2)]) # # A recursive non-EOS x-connect, which resolves through another @@ -513,19 +601,20 @@ class TestMPLS(VppTestCase): [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=32, - labels=[44, 46])]) + labels=[VppMplsLabel(44), + VppMplsLabel(46)])]) route_34_neos.add_vpp_config() - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [34, 99]) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(34, ttl=45), + VppMplsLabel(99)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) # it's the 2nd (counting from 0) label in the stack that is swapped - self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 46, 99], num=2) + self.verify_capture_labelled(self.pg0, rx, tx, + [VppMplsLabel(33), + VppMplsLabel(44), + VppMplsLabel(46, ttl=44), + VppMplsLabel(99)]) # # an recursive IP route that resolves through the recursive non-eos @@ -535,18 +624,16 @@ class TestMPLS(VppTestCase): [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=34, - labels=[55])]) + labels=[VppMplsLabel(55)])]) ip_10_0_0_1.add_vpp_config() - self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "10.0.0.1") - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() - self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33, 44, 46, 55]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled_ip4(self.pg0, rx, tx, + [VppMplsLabel(33), + VppMplsLabel(44), + VppMplsLabel(46), + VppMplsLabel(55)]) ip_10_0_0_1.remove_vpp_config() route_34_neos.remove_vpp_config() @@ -565,7 +652,7 @@ class TestMPLS(VppTestCase): route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, - labels=[45])]) + labels=[VppMplsLabel(45)])]) route_10_0_0_1.add_vpp_config() # bind a local label to the route @@ -573,37 +660,24 @@ class TestMPLS(VppTestCase): binding.add_vpp_config() # non-EOS stream - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [44, 99]) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() - self.verify_capture_labelled(self.pg0, rx, tx, [45, 99]) + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(44), + VppMplsLabel(99)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled(self.pg0, rx, tx, + [VppMplsLabel(45, ttl=63), + VppMplsLabel(99)]) # EOS stream - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [44]) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() - self.verify_capture_labelled(self.pg0, rx, tx, [45]) + tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled(self.pg0, rx, tx, + [VppMplsLabel(45, ttl=63)]) # IP stream - self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "10.0.0.1") - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() - self.verify_capture_labelled_ip4(self.pg0, rx, tx, [45]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)]) # # cleanup @@ -620,22 +694,16 @@ class TestMPLS(VppTestCase): route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, - labels=[32])]) + labels=[VppMplsLabel(32)])]) route_10_0_0_1.add_vpp_config() # # a stream that matches the route for 10.0.0.1 # PG0 is in the default table # - self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "10.0.0.1") - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() - self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)]) # # Add a non-recursive route with a 3 out labels @@ -643,22 +711,56 @@ class TestMPLS(VppTestCase): route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, - labels=[32, 33, 34])]) + labels=[VppMplsLabel(32), + VppMplsLabel(33), + VppMplsLabel(34)])]) route_10_0_0_2.add_vpp_config() + tx = self.create_stream_ip4(self.pg0, "10.0.0.2", + ip_ttl=44, ip_dscp=0xff) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled_ip4(self.pg0, rx, tx, + [VppMplsLabel(32), + VppMplsLabel(33), + VppMplsLabel(34)], + ip_ttl=43) + # - # a stream that matches the route for 10.0.0.1 - # PG0 is in the default table + # Add a non-recursive route with a single out label in uniform mode # - self.vapi.cli("clear trace") - tx = self.create_stream_ip4(self.pg0, "10.0.0.2") - self.pg0.add_stream(tx) + route_10_0_0_3 = VppIpRoute( + self, "10.0.0.3", 32, + [VppRoutePath(self.pg0.remote_ip4, + self.pg0.sw_if_index, + labels=[VppMplsLabel(32, + mode=MplsLspMode.UNIFORM)])]) + route_10_0_0_3.add_vpp_config() - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() + tx = self.create_stream_ip4(self.pg0, "10.0.0.3", + ip_ttl=54, ip_dscp=0xbe) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled_ip4(self.pg0, rx, tx, + [VppMplsLabel(32, ttl=53, exp=5)]) - rx = self.pg0.get_capture() - self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 33, 34]) + # + # Add a IPv6 non-recursive route with a single out label in + # uniform mode + # + route_2001_3 = VppIpRoute( + self, "2001::3", 128, + [VppRoutePath(self.pg0.remote_ip6, + self.pg0.sw_if_index, + proto=DpoProto.DPO_PROTO_IP6, + labels=[VppMplsLabel(32, + mode=MplsLspMode.UNIFORM)])], + is_ip6=1) + route_2001_3.add_vpp_config() + + tx = self.create_stream_ip6(self.pg0, "2001::3", + ip_ttl=54, ip_dscp=0xbe) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled_ip6(self.pg0, rx, tx, + [VppMplsLabel(32, ttl=53, exp=5)]) # # add a recursive path, with output label, via the 1 label route @@ -666,22 +768,18 @@ class TestMPLS(VppTestCase): route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32, [VppRoutePath("10.0.0.1", 0xffffffff, - labels=[44])]) + labels=[VppMplsLabel(44)])]) route_11_0_0_1.add_vpp_config() # # a stream that matches the route for 11.0.0.1, should pick up # the label stack for 11.0.0.1 and 10.0.0.1 # - self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "11.0.0.1") - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() - self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 44]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled_ip4(self.pg0, rx, tx, + [VppMplsLabel(32), + VppMplsLabel(44)]) # # add a recursive path, with 2 labels, via the 3 label route @@ -689,23 +787,22 @@ class TestMPLS(VppTestCase): route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32, [VppRoutePath("10.0.0.2", 0xffffffff, - labels=[44, 45])]) + labels=[VppMplsLabel(44), + VppMplsLabel(45)])]) route_11_0_0_2.add_vpp_config() # # a stream that matches the route for 11.0.0.1, should pick up # the label stack for 11.0.0.1 and 10.0.0.1 # - self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "11.0.0.2") - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() - self.verify_capture_labelled_ip4( - self.pg0, rx, tx, [32, 33, 34, 44, 45]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) + self.verify_capture_labelled_ip4(self.pg0, rx, tx, + [VppMplsLabel(32), + VppMplsLabel(33), + VppMplsLabel(34), + VppMplsLabel(44), + VppMplsLabel(45)]) # # cleanup @@ -715,16 +812,18 @@ class TestMPLS(VppTestCase): route_10_0_0_2.remove_vpp_config() route_10_0_0_1.remove_vpp_config() - def test_tunnel(self): - """ MPLS Tunnel Tests """ + def test_tunnel_pipe(self): + """ MPLS Tunnel Tests - Pipe """ # # Create a tunnel with a single out label # - mpls_tun = VppMPLSTunnelInterface(self, - [VppRoutePath(self.pg0.remote_ip4, - self.pg0.sw_if_index, - labels=[44, 46])]) + mpls_tun = VppMPLSTunnelInterface( + self, + [VppRoutePath(self.pg0.remote_ip4, + self.pg0.sw_if_index, + labels=[VppMplsLabel(44), + VppMplsLabel(46)])]) mpls_tun.add_vpp_config() mpls_tun.admin_up() @@ -744,7 +843,9 @@ class TestMPLS(VppTestCase): self.pg_start() rx = self.pg0.get_capture() - self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46]) + self.verify_capture_tunneled_ip4(self.pg0, rx, tx, + [VppMplsLabel(44), + VppMplsLabel(46)]) # # add a labelled route through the new tunnel @@ -763,35 +864,88 @@ class TestMPLS(VppTestCase): self.pg_start() rx = self.pg0.get_capture() - self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46, 33], - ttl=63, top=2) + self.verify_capture_tunneled_ip4(self.pg0, rx, tx, + [VppMplsLabel(44), + VppMplsLabel(46), + VppMplsLabel(33, ttl=255)]) - def test_v4_exp_null(self): - """ MPLS V4 Explicit NULL test """ + def test_tunnel_uniform(self): + """ MPLS Tunnel Tests - Uniform """ # - # The first test case has an MPLS TTL of 0 - # all packet should be dropped + # Create a tunnel with a single out label + # The label stack is specified here from outer to inner # - tx = self.create_stream_labelled_ip4(self.pg0, [0], 0) + mpls_tun = VppMPLSTunnelInterface( + self, + [VppRoutePath(self.pg0.remote_ip4, + self.pg0.sw_if_index, + labels=[VppMplsLabel(44, ttl=32), + VppMplsLabel(46, MplsLspMode.UNIFORM)])]) + mpls_tun.add_vpp_config() + mpls_tun.admin_up() + + # + # add an unlabelled route through the new tunnel + # + route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32, + [VppRoutePath("0.0.0.0", + mpls_tun._sw_if_index)]) + route_10_0_0_3.add_vpp_config() + + self.vapi.cli("clear trace") + tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - self.pg0.assert_nothing_captured(remark="MPLS TTL=0 packets forwarded") + rx = self.pg0.get_capture() + self.verify_capture_tunneled_ip4(self.pg0, rx, tx, + [VppMplsLabel(44, ttl=32), + VppMplsLabel(46, ttl=23)]) # - # a stream with a non-zero MPLS TTL - # PG0 is in the default table + # add a labelled route through the new tunnel # - tx = self.create_stream_labelled_ip4(self.pg0, [0]) + route_10_0_0_4 = VppIpRoute( + self, "10.0.0.4", 32, + [VppRoutePath("0.0.0.0", + mpls_tun._sw_if_index, + labels=[VppMplsLabel(33, ttl=47)])]) + route_10_0_0_4.add_vpp_config() + + self.vapi.cli("clear trace") + tx = self.create_stream_ip4(self.pg0, "10.0.0.4") self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() + self.verify_capture_tunneled_ip4(self.pg0, rx, tx, + [VppMplsLabel(44, ttl=32), + VppMplsLabel(46, ttl=47), + VppMplsLabel(33, ttl=47)]) + + def test_v4_exp_null(self): + """ MPLS V4 Explicit NULL test """ + + # + # The first test case has an MPLS TTL of 0 + # all packet should be dropped + # + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(0, ttl=0)]) + self.send_and_assert_no_replies(self.pg0, tx, + "MPLS TTL=0 packets forwarded") + + # + # a stream with a non-zero MPLS TTL + # PG0 is in the default table + # + tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_capture_ip4(self.pg0, rx, tx) # @@ -799,15 +953,9 @@ class TestMPLS(VppTestCase): # PG1 is in table 1 # we are ensuring the post-pop lookup occurs in the VRF table # - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg1, [0]) - self.pg1.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg1.get_capture() - self.verify_capture_ip4(self.pg0, rx, tx) + tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)]) + rx = self.send_and_expect(self.pg1, tx, self.pg1) + self.verify_capture_ip4(self.pg1, rx, tx) def test_v6_exp_null(self): """ MPLS V6 Explicit NULL test """ @@ -816,14 +964,8 @@ class TestMPLS(VppTestCase): # a stream with a non-zero MPLS TTL # PG0 is in the default table # - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip6(self.pg0, 2, 2) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() + tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)]) + rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_capture_ip6(self.pg0, rx, tx) # @@ -831,14 +973,8 @@ class TestMPLS(VppTestCase): # PG1 is in table 1 # we are ensuring the post-pop lookup occurs in the VRF table # - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip6(self.pg1, 2, 2) - self.pg1.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg1.get_capture() + tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)]) + rx = self.send_and_expect(self.pg1, tx, self.pg1) self.verify_capture_ip6(self.pg0, rx, tx) def test_deag(self): @@ -857,15 +993,11 @@ class TestMPLS(VppTestCase): # ping an interface in the default table # PG0 is in the default table # - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [34], ping=1, + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(34)], + ping=1, ip_itf=self.pg0) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture() + rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1) # @@ -882,16 +1014,9 @@ class TestMPLS(VppTestCase): # PG0 is in the default table. packet arrive labelled in the # default table and egress unlabelled in the non-default # - self.vapi.cli("clear trace") tx = self.create_stream_labelled_ip4( - self.pg0, [35], ping=1, ip_itf=self.pg1) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - packet_count = self.get_packet_count_for_if_idx(self.pg0.sw_if_index) - rx = self.pg1.get_capture(packet_count) + self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1) + rx = self.send_and_expect(self.pg0, tx, self.pg1) self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1) # @@ -902,15 +1027,11 @@ class TestMPLS(VppTestCase): 0xffffffff)]) route_36_neos.add_vpp_config() - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [36, 35], + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(36), + VppMplsLabel(35)], ping=1, ip_itf=self.pg1) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg1.get_capture(len(tx)) + rx = self.send_and_expect(self.pg0, tx, self.pg1) self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1) route_36_neos.remove_vpp_config() @@ -948,15 +1069,10 @@ class TestMPLS(VppTestCase): # ping an interface in the default table # PG0 is in the default table # - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [34], n=257, + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(34)], dst_ip="10.0.0.1") - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg1.get_capture(257) + rx = self.send_and_expect(self.pg0, tx, self.pg1) self.verify_capture_ip4(self.pg1, rx, tx) def test_mcast_mid_point(self): @@ -976,17 +1092,18 @@ class TestMPLS(VppTestCase): # Add a mcast entry that replicate to pg2 and pg3 # and replicate to a interface-rx (like a bud node would) # - route_3400_eos = VppMplsRoute(self, 3400, 1, - [VppRoutePath(self.pg2.remote_ip4, - self.pg2.sw_if_index, - labels=[3401]), - VppRoutePath(self.pg3.remote_ip4, - self.pg3.sw_if_index, - labels=[3402]), - VppRoutePath("0.0.0.0", - self.pg1.sw_if_index, - is_interface_rx=1)], - is_multicast=1) + route_3400_eos = VppMplsRoute( + self, 3400, 1, + [VppRoutePath(self.pg2.remote_ip4, + self.pg2.sw_if_index, + labels=[VppMplsLabel(3401)]), + VppRoutePath(self.pg3.remote_ip4, + self.pg3.sw_if_index, + labels=[VppMplsLabel(3402)]), + VppRoutePath("0.0.0.0", + self.pg1.sw_if_index, + is_interface_rx=1)], + is_multicast=1) route_3400_eos.add_vpp_config() # @@ -994,7 +1111,9 @@ class TestMPLS(VppTestCase): # PG0 is in the default table # self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [3400], n=257, + tx = self.create_stream_labelled_ip4(self.pg0, + [VppMplsLabel(3400, ttl=64)], + n=257, dst_ip="10.0.0.1") self.pg0.add_stream(tx) @@ -1005,9 +1124,11 @@ class TestMPLS(VppTestCase): self.verify_capture_ip4(self.pg1, rx, tx) rx = self.pg2.get_capture(257) - self.verify_capture_labelled(self.pg2, rx, tx, [3401]) + self.verify_capture_labelled(self.pg2, rx, tx, + [VppMplsLabel(3401, ttl=63)]) rx = self.pg3.get_capture(257) - self.verify_capture_labelled(self.pg3, rx, tx, [3402]) + self.verify_capture_labelled(self.pg3, rx, tx, + [VppMplsLabel(3402, ttl=63)]) def test_mcast_head(self): """ MPLS Multicast Head-end """ @@ -1015,14 +1136,15 @@ class TestMPLS(VppTestCase): # # Create a multicast tunnel with two replications # - mpls_tun = VppMPLSTunnelInterface(self, - [VppRoutePath(self.pg2.remote_ip4, - self.pg2.sw_if_index, - labels=[42]), - VppRoutePath(self.pg3.remote_ip4, - self.pg3.sw_if_index, - labels=[43])], - is_multicast=1) + mpls_tun = VppMPLSTunnelInterface( + self, + [VppRoutePath(self.pg2.remote_ip4, + self.pg2.sw_if_index, + labels=[VppMplsLabel(42)]), + VppRoutePath(self.pg3.remote_ip4, + self.pg3.sw_if_index, + labels=[VppMplsLabel(43)])], + is_multicast=1) mpls_tun.add_vpp_config() mpls_tun.admin_up() @@ -1042,9 +1164,9 @@ class TestMPLS(VppTestCase): self.pg_start() rx = self.pg2.get_capture(257) - self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42]) + self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)]) rx = self.pg3.get_capture(257) - self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43]) + self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)]) # # An an IP multicast route via the tunnel @@ -1070,9 +1192,9 @@ class TestMPLS(VppTestCase): self.pg_start() rx = self.pg2.get_capture(257) - self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42]) + self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)]) rx = self.pg3.get_capture(257) - self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43]) + self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)]) def test_mcast_ip4_tail(self): """ MPLS IPv4 Multicast Tail """ @@ -1112,7 +1234,7 @@ class TestMPLS(VppTestCase): # Drop due to interface lookup miss # self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [34], + tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1", n=1) self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none") @@ -1121,30 +1243,24 @@ class TestMPLS(VppTestCase): # route_232_1_1_1.update_rpf_id(55) - self.vapi.cli("clear trace") - tx = self.create_stream_labelled_ip4(self.pg0, [34], - dst_ip="232.1.1.1", n=257) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg1.get_capture(257) + tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)], + dst_ip="232.1.1.1") + rx = self.send_and_expect(self.pg0, tx, self.pg1) self.verify_capture_ip4(self.pg1, rx, tx) # # disposed packets have an invalid IPv4 checkusm # - tx = self.create_stream_labelled_ip4(self.pg0, [34], + tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1", n=65, chksum=1) self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum") # - # set the RPF-ID of the enrtry to not match the input packet's + # set the RPF-ID of the entry to not match the input packet's # route_232_1_1_1.update_rpf_id(56) - tx = self.create_stream_labelled_ip4(self.pg0, [34], + tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1") self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56") @@ -1188,42 +1304,36 @@ class TestMPLS(VppTestCase): # # Drop due to interface lookup miss # - tx = self.create_stream_labelled_ip6(self.pg0, [34], 255, + tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1") + self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss") # # set the RPF-ID of the enrtry to match the input packet's # route_ff.update_rpf_id(55) - tx = self.create_stream_labelled_ip6(self.pg0, [34], 255, + tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1") - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg1.get_capture(257) + rx = self.send_and_expect(self.pg0, tx, self.pg1) self.verify_capture_ip6(self.pg1, rx, tx) # # disposed packets have hop-limit = 1 # - tx = self.create_stream_labelled_ip6(self.pg0, [34], 255, - dst_ip="ff01::1", hlim=1) - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture(257) + tx = self.create_stream_labelled_ip6(self.pg0, + [VppMplsLabel(34)], + dst_ip="ff01::1", + hlim=1) + rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_capture_ip6_icmp(self.pg0, rx, tx) # # set the RPF-ID of the enrtry to not match the input packet's # route_ff.update_rpf_id(56) - tx = self.create_stream_labelled_ip6(self.pg0, [34], 225, + tx = self.create_stream_labelled_ip6(self.pg0, + [VppMplsLabel(34)], dst_ip="ff01::1") self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56") @@ -1709,11 +1819,7 @@ class TestMPLSL2(VppTestCase): self.pg0.admin_down() super(TestMPLSL2, self).tearDown() - def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels, - ttl=255, top=None): - if top is None: - top = len(mpls_labels) - 1 - + def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels): capture = verify_filter(capture, sent) self.assertEqual(len(capture), len(sent)) @@ -1723,7 +1829,7 @@ class TestMPLSL2(VppTestCase): rx = capture[i] # the MPLS TTL is 255 since it enters a new tunnel - verify_mpls_stack(self, rx, mpls_labels, ttl, top) + verify_mpls_stack(self, rx, mpls_labels) tx_eth = tx[Ether] rx_eth = Ether(str(rx[MPLS].payload)) @@ -1736,12 +1842,15 @@ class TestMPLSL2(VppTestCase): # # Create an MPLS tunnel that pushes 1 label + # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos + # information is not in the packet, but we test it works anyway # - mpls_tun_1 = VppMPLSTunnelInterface(self, - [VppRoutePath(self.pg0.remote_ip4, - self.pg0.sw_if_index, - labels=[42])], - is_l2=1) + mpls_tun_1 = VppMPLSTunnelInterface( + self, + [VppRoutePath(self.pg0.remote_ip4, + self.pg0.sw_if_index, + labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])], + is_l2=1) mpls_tun_1.add_vpp_config() mpls_tun_1.admin_up() @@ -1778,37 +1887,32 @@ class TestMPLSL2(VppTestCase): UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) - self.pg0.add_stream(pcore * 65) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() + tx0 = pcore * 65 + rx0 = self.send_and_expect(self.pg0, tx0, self.pg1) + payload = pcore[MPLS].payload - rx0 = self.pg1.get_capture(65) - tx = pcore[MPLS].payload - - self.assertEqual(rx0[0][Ether].dst, tx[Ether].dst) - self.assertEqual(rx0[0][Ether].src, tx[Ether].src) + self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst) + self.assertEqual(rx0[0][Ether].src, payload[Ether].src) # # Inject a packet from the custoer/L2 side # - self.pg1.add_stream(tx * 65) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx0 = self.pg0.get_capture(65) + tx1 = pcore[MPLS].payload * 65 + rx1 = self.send_and_expect(self.pg1, tx1, self.pg0) - self.verify_capture_tunneled_ethernet(rx0, tx*65, [42]) + self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)]) def test_vpls(self): """ Virtual Private LAN Service """ # # Create an L2 MPLS tunnel # - mpls_tun = VppMPLSTunnelInterface(self, - [VppRoutePath(self.pg0.remote_ip4, - self.pg0.sw_if_index, - labels=[42])], - is_l2=1) + mpls_tun = VppMPLSTunnelInterface( + self, + [VppRoutePath(self.pg0.remote_ip4, + self.pg0.sw_if_index, + labels=[VppMplsLabel(42)])], + is_l2=1) mpls_tun.add_vpp_config() mpls_tun.admin_up() @@ -1875,7 +1979,8 @@ class TestMPLSL2(VppTestCase): rx0 = self.pg0.get_capture(65) - self.verify_capture_tunneled_ethernet(rx0, p_cust*65, [42]) + self.verify_capture_tunneled_ethernet(rx0, p_cust*65, + [VppMplsLabel(42)]) # # remove interfaces from customers bridge-domain diff --git a/test/test_udp.py b/test/test_udp.py index 68b023c5e2f..322d8133b0d 100644 --- a/test/test_udp.py +++ b/test/test_udp.py @@ -2,7 +2,7 @@ from framework import VppTestCase, VppTestRunner from vpp_udp_encap import * -from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable +from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, VppMplsLabel from scapy.packet import Raw from scapy.layers.l2 import Ether, ARP @@ -67,12 +67,12 @@ class TestUdpEncap(VppTestCase): self.assertEqual(rx[UDP].dport, encap_obj.dst_port) def validate_inner4(self, rx, tx, ttl=None): - self.assertEqual(rx.src, tx[IP].src) - self.assertEqual(rx.dst, tx[IP].dst) + self.assertEqual(rx[IP].src, tx[IP].src) + self.assertEqual(rx[IP].dst, tx[IP].dst) if ttl: - self.assertEqual(rx.ttl, ttl) + self.assertEqual(rx[IP].ttl, ttl) else: - self.assertEqual(rx.ttl, tx[IP].ttl) + self.assertEqual(rx[IP].ttl, tx[IP].ttl) def validate_inner6(self, rx, tx): self.assertEqual(rx.src, tx[IPv6].src) @@ -208,7 +208,7 @@ class TestUdpEncap(VppTestCase): 0xFFFFFFFF, is_udp_encap=1, next_hop_id=1, - labels=[66])]) + labels=[VppMplsLabel(66)])]) route_4oMPLSo4.add_vpp_config() p_4omo4 = (Ether(src=self.pg0.remote_mac, diff --git a/test/vpp_bier.py b/test/vpp_bier.py index ef9a9ab75ec..7566b1f95ab 100644 --- a/test/vpp_bier.py +++ b/test/vpp_bier.py @@ -4,7 +4,7 @@ import socket from vpp_object import VppObject -from vpp_ip_route import MPLS_LABEL_INVALID, VppRoutePath +from vpp_ip_route import MPLS_LABEL_INVALID, VppRoutePath, VppMplsLabel class BIER_HDR_PAYLOAD: @@ -120,11 +120,34 @@ class VppBierRoute(VppObject): self.bp = bp self.paths = paths + def encode_paths(self): + br_paths = [] + for p in self.paths: + lstack = [] + for l in p.nh_labels: + if type(l) == VppMplsLabel: + lstack.append(l.encode()) + else: + lstack.append({'label': l, 'ttl': 255}) + n_labels = len(lstack) + while (len(lstack) < 16): + lstack.append({}) + br_paths.append({'next_hop': p.nh_addr, + 'weight': 1, + 'afi': 0, + 'preference': 0, + 'table_id': p.nh_table_id, + 'next_hop_id': p.next_hop_id, + 'is_udp_encap': p.is_udp_encap, + 'n_labels': n_labels, + 'label_stack': lstack}) + return br_paths + def add_vpp_config(self): self._test.vapi.bier_route_add_del( self.tbl_id, self.bp, - self.paths, + self.encode_paths(), is_add=1) self._test.registry.register(self, self._test.logger) @@ -132,7 +155,7 @@ class VppBierRoute(VppObject): self._test.vapi.bier_route_add_del( self.tbl_id, self.bp, - self.paths, + self.encode_paths(), is_add=0) def __str__(self): diff --git a/test/vpp_ip_route.py b/test/vpp_ip_route.py index 2d34f55efdf..ca0ae1ad47d 100644 --- a/test/vpp_ip_route.py +++ b/test/vpp_ip_route.py @@ -38,6 +38,11 @@ class DpoProto: DPO_PROTO_NSH = 5 +class MplsLspMode: + PIPE = 0 + UNIFORM = 1 + + def find_route(test, ip_addr, len, table_id=0, inet=AF_INET): if inet == AF_INET: s = 4 @@ -95,6 +100,21 @@ class VppIpTable(VppObject): self.table_id)) +class VppMplsLabel(object): + def __init__(self, value, mode=MplsLspMode.PIPE, ttl=64, exp=0): + self.value = value + self.mode = mode + self.ttl = ttl + self.exp = exp + + def encode(self): + is_uniform = 0 if self.mode is MplsLspMode.PIPE else 1 + return {'label': self.value, + 'ttl': self.ttl, + 'exp': self.exp, + 'is_uniform': is_uniform} + + class VppRoutePath(object): def __init__( @@ -138,6 +158,16 @@ class VppRoutePath(object): self.next_hop_id = next_hop_id self.is_dvr = is_dvr + def encode_labels(self): + lstack = [] + for l in self.nh_labels: + if type(l) == VppMplsLabel: + lstack.append(l.encode()) + else: + lstack.append({'label': l, + 'ttl': 255}) + return lstack + class VppMRoutePath(VppRoutePath): @@ -195,15 +225,16 @@ class VppIpRoute(VppObject): is_ipv6=self.is_ip6) else: for path in self.paths: + lstack = path.encode_labels() + self._test.vapi.ip_add_del_route( self.dest_addr, self.dest_addr_len, path.nh_addr, path.nh_itf, table_id=self.table_id, - next_hop_out_label_stack=path.nh_labels, - next_hop_n_out_labels=len( - path.nh_labels), + next_hop_out_label_stack=lstack, + next_hop_n_out_labels=len(lstack), next_hop_via_label=path.nh_via_label, next_hop_table_id=path.nh_table_id, next_hop_id=path.next_hop_id, @@ -513,6 +544,8 @@ class VppMplsRoute(VppObject): def add_vpp_config(self): is_multipath = len(self.paths) > 1 for path in self.paths: + lstack = path.encode_labels() + self._test.vapi.mpls_route_add_del( self.local_label, self.eos_bit, @@ -524,9 +557,8 @@ class VppMplsRoute(VppObject): table_id=self.table_id, is_interface_rx=path.is_interface_rx, is_rpf_id=path.is_rpf_id, - next_hop_out_label_stack=path.nh_labels, - next_hop_n_out_labels=len( - path.nh_labels), + next_hop_out_label_stack=lstack, + next_hop_n_out_labels=len(lstack), next_hop_via_label=path.nh_via_label, next_hop_table_id=path.nh_table_id) self._test.registry.register(self, self._test.logger) diff --git a/test/vpp_mpls_tunnel_interface.py b/test/vpp_mpls_tunnel_interface.py index 0542b05c05f..c789c3f1dd0 100644 --- a/test/vpp_mpls_tunnel_interface.py +++ b/test/vpp_mpls_tunnel_interface.py @@ -1,6 +1,6 @@ from vpp_interface import VppInterface -from vpp_ip_route import VppRoutePath +from vpp_ip_route import VppRoutePath, VppMplsLabel import socket @@ -21,6 +21,8 @@ class VppMPLSTunnelInterface(VppInterface): def add_vpp_config(self): self._sw_if_index = 0xffffffff for path in self.t_paths: + lstack = path.encode_labels() + reply = self.test.vapi.mpls_tunnel_add_del( self._sw_if_index, 1, # IPv4 next-hop @@ -28,8 +30,8 @@ class VppMPLSTunnelInterface(VppInterface): path.nh_itf, path.nh_table_id, path.weight, - next_hop_out_label_stack=path.nh_labels, - next_hop_n_out_labels=len(path.nh_labels), + next_hop_out_label_stack=lstack, + next_hop_n_out_labels=len(lstack), is_multicast=self.is_multicast, l2_only=self.is_l2) self._sw_if_index = reply.sw_if_index diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 99e320bfe60..18bb1f60d40 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -1119,7 +1119,6 @@ class VppPapiProvider(object): :param next_hop_weight: (Default value = 1) """ - return self.api( self.papi.mpls_route_add_del, {'mr_label': label, @@ -2875,25 +2874,14 @@ class VppPapiProvider(object): paths, is_add=1): """ BIER Route add/del """ - br_paths = [] - for p in paths: - br_paths.append({'next_hop': p.nh_addr, - 'weight': 1, - 'afi': 0, - 'preference': 0, - 'table_id': p.nh_table_id, - 'next_hop_id': p.next_hop_id, - 'is_udp_encap': p.is_udp_encap, - 'n_labels': len(p.nh_labels), - 'label_stack': p.nh_labels}) return self.api( self.papi.bier_route_add_del, {'br_tbl_id': {"bt_set": bti.set_id, "bt_sub_domain": bti.sub_domain_id, "bt_hdr_len_id": bti.hdr_len_id}, 'br_bp': bp, - 'br_n_paths': len(br_paths), - 'br_paths': br_paths, + 'br_n_paths': len(paths), + 'br_paths': paths, 'br_is_add': is_add}) def bier_route_dump(self, bti): @@ -2950,6 +2938,9 @@ class VppPapiProvider(object): next_hop_is_ip4=1, is_add=1): """ BIER Route add/del """ + lstack = [] + while (len(lstack) < 16): + lstack.append({}) return self.api( self.papi.bier_disp_entry_add_del, {'bde_tbl_id': bdti, @@ -2961,7 +2952,7 @@ class VppPapiProvider(object): 'afi': next_hop_afi, 'rpf_id': next_hop_rpf_id, 'n_labels': 0, - 'label_stack': [0]}], + 'label_stack': lstack}], 'bde_is_add': is_add}) def bier_disp_entry_dump(self, bdti): -- 2.16.6