X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fmpls%2Fmpls_tunnel.c;h=d3faeac6a0d9e9cddfefa4733e644ac5c996f63d;hb=1855b8e4;hp=457d48eb6bf1d030bddd5542f407ab434cf8d061;hpb=227038a444b98f922b4a4f44b85ae60f9ee86e1c;p=vpp.git diff --git a/src/vnet/mpls/mpls_tunnel.c b/src/vnet/mpls/mpls_tunnel.c index 457d48eb6bf..d3faeac6a0d 100644 --- a/src/vnet/mpls/mpls_tunnel.c +++ b/src/vnet/mpls/mpls_tunnel.c @@ -99,14 +99,13 @@ typedef struct mpls_tunnel_collect_forwarding_ctx_t_ fib_forward_chain_type_t fct; } mpls_tunnel_collect_forwarding_ctx_t; -static int +static fib_path_list_walk_rc_t mpls_tunnel_collect_forwarding (fib_node_index_t pl_index, fib_node_index_t path_index, void *arg) { mpls_tunnel_collect_forwarding_ctx_t *ctx; fib_path_ext_t *path_ext; - int have_path_ext; ctx = arg; @@ -115,41 +114,31 @@ mpls_tunnel_collect_forwarding (fib_node_index_t pl_index, */ if (!fib_path_is_resolved(path_index)) { - return (!0); + return (FIB_PATH_LIST_WALK_CONTINUE); } /* * get the matching path-extension for the path being visited. */ - have_path_ext = 0; - vec_foreach(path_ext, ctx->mt->mt_path_exts) - { - if (path_ext->fpe_path_index == path_index) - { - have_path_ext = 1; - break; - } - } + 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 (have_path_ext) - { - /* - * found a matching extension. stack it to obtain the forwarding - * info for this path. - */ - ctx->next_hops = fib_path_ext_stack(path_ext, - ctx->fct, - ctx->fct, - ctx->next_hops); - } - else - ASSERT(0); /* - * else - * There should be a path-extenios associated with each path + * found a matching extension. stack it to obtain the forwarding + * info for this path. */ + ctx->next_hops = fib_path_ext_stack(path_ext, + ctx->fct, + ctx->fct, + ctx->next_hops); - return (!0); + return (FIB_PATH_LIST_WALK_CONTINUE); } static void @@ -179,7 +168,7 @@ mpls_tunnel_mk_lb (mpls_tunnel_t *mt, vec_validate(ctx.next_hops, fib_path_list_get_n_paths(mt->mt_path_list)); vec_reset_length(ctx.next_hops); - lb_proto = vnet_link_to_dpo_proto(linkt); + lb_proto = fib_forw_chain_type_to_dpo_proto(fct); fib_path_list_walk(mt->mt_path_list, mpls_tunnel_collect_forwarding, @@ -281,7 +270,8 @@ mpls_tunnel_stack (adj_index_t ai) mpls_tunnel_mk_lb(mt, adj->ia_link, - 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); @@ -296,7 +286,7 @@ mpls_tunnel_stack (adj_index_t ai) FIB_NODE_TYPE_MPLS_TUNNEL, mt - mpls_tunnel_pool); - fib_path_list_lock(mt->mt_path_list); + fib_path_list_unlock(mt->mt_path_list); } /** @@ -319,12 +309,34 @@ mpls_tunnel_restack (mpls_tunnel_t *mt) /* * walk all the adjacencies on the MPLS interface and restack them */ - FOR_EACH_FIB_PROTOCOL(proto) + if (mt->mt_flags & MPLS_TUNNEL_FLAG_L2) { - adj_nbr_walk(mt->mt_sw_if_index, - proto, - mpls_adj_walk_cb, - NULL); + /* + * Stack a load-balance that drops, whilst we have no paths + */ + vnet_hw_interface_t * hi; + dpo_id_t dpo = DPO_INVALID; + + mpls_tunnel_mk_lb(mt, + VNET_LINK_MPLS, + FIB_FORW_CHAIN_TYPE_ETHERNET, + &dpo); + + hi = vnet_get_hw_interface(vnet_get_main(), mt->mt_hw_if_index); + dpo_stack_from_node(hi->tx_node_index, + &mt->mt_l2_lb, + &dpo); + dpo_reset(&dpo); + } + else + { + FOR_EACH_FIB_PROTOCOL(proto) + { + adj_nbr_walk(mt->mt_sw_if_index, + proto, + mpls_adj_walk_cb, + NULL); + } } } @@ -361,7 +373,8 @@ mpls_tunnel_admin_up_down (vnet_main_t * vnm, static void mpls_tunnel_fixup (vlib_main_t *vm, ip_adjacency_t *adj, - vlib_buffer_t *b0) + vlib_buffer_t *b0, + const void*data) { /* * A no-op w.r.t. the header. but reset the 'have we pushed any @@ -386,7 +399,9 @@ mpls_tunnel_update_adj (vnet_main_t * vnm, { case IP_LOOKUP_NEXT_ARP: case IP_LOOKUP_NEXT_GLEAN: + case IP_LOOKUP_NEXT_BCAST: adj_nbr_midchain_update_rewrite(ai, mpls_tunnel_fixup, + NULL, ADJ_FLAG_NONE, mpls_tunnel_build_rewrite_i()); break; @@ -396,6 +411,7 @@ mpls_tunnel_update_adj (vnet_main_t * vnm, * There's no MAC fixup, so the last 2 parameters are 0 */ adj_mcast_midchain_update_rewrite(ai, mpls_tunnel_fixup, + NULL, ADJ_FLAG_NONE, mpls_tunnel_build_rewrite_i(), 0, 0); @@ -501,7 +517,12 @@ mpls_tunnel_tx (vlib_main_t * vm, b0 = vlib_get_buffer(vm, bi0); - vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mt->mt_l2_adj; + 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)) { @@ -512,7 +533,7 @@ mpls_tunnel_tx (vlib_main_t * vm, vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, - bi0, mt->mt_l2_tx_arc); + bi0, mt->mt_l2_lb.dpoi_next_node); } vlib_put_next_frame (vm, node, next_index, n_left_to_next); @@ -532,8 +553,6 @@ VNET_DEVICE_CLASS (mpls_tunnel_class) = { VNET_HW_INTERFACE_CLASS (mpls_tunnel_hw_interface_class) = { .name = "MPLS-Tunnel", -// .format_header = format_mpls_eth_header_with_length, -// .unformat_header = unformat_mpls_eth_header, .update_adjacency = mpls_tunnel_update_adj, .build_rewrite = mpls_tunnel_build_rewrite, .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P, @@ -573,8 +592,7 @@ vnet_mpls_tunnel_del (u32 sw_if_index) if (FIB_NODE_INDEX_INVALID != mt->mt_path_list) fib_path_list_child_remove(mt->mt_path_list, mt->mt_sibling_index); - if (ADJ_INDEX_INVALID != mt->mt_l2_adj) - adj_unlock(mt->mt_l2_adj); + dpo_reset(&mt->mt_l2_lb); vec_add1 (mpls_tunnel_free_hw_if_indices, mt->mt_hw_if_index); pool_put(mpls_tunnel_pool, mt); @@ -595,12 +613,13 @@ vnet_mpls_tunnel_create (u8 l2_only, memset (mt, 0, sizeof (*mt)); mti = mt - mpls_tunnel_pool; fib_node_init(&mt->mt_node, FIB_NODE_TYPE_MPLS_TUNNEL); - mt->mt_l2_adj = ADJ_INDEX_INVALID; mt->mt_path_list = FIB_NODE_INDEX_INVALID; mt->mt_sibling_index = FIB_NODE_INDEX_INVALID; if (is_multicast) mt->mt_flags |= MPLS_TUNNEL_FLAG_MCAST; + if (l2_only) + mt->mt_flags |= MPLS_TUNNEL_FLAG_L2; /* * Create a new, or re=use and old, tunnel HW interface @@ -622,9 +641,12 @@ vnet_mpls_tunnel_create (u8 l2_only, mti, mpls_tunnel_hw_interface_class.index, mti); - hi = vnet_get_hw_interface(vnm, mt->mt_hw_if_index); + hi = vnet_get_hw_interface (vnm, mt->mt_hw_if_index); } + /* Standard default MPLS tunnel MTU. */ + vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, 9000); + /* * Add the new tunnel to the tunnel DB - key:SW if index */ @@ -632,74 +654,9 @@ vnet_mpls_tunnel_create (u8 l2_only, vec_validate_init_empty(mpls_tunnel_db, mt->mt_sw_if_index, ~0); mpls_tunnel_db[mt->mt_sw_if_index] = mti; - if (l2_only) - { - mt->mt_l2_adj = - adj_nbr_add_or_lock(fib_path_list_get_proto(mt->mt_path_list), - VNET_LINK_ETHERNET, - &zero_addr, - mt->mt_sw_if_index); - - mt->mt_l2_tx_arc = vlib_node_add_named_next(vlib_get_main(), - hi->tx_node_index, - "adj-l2-midchain"); - } - return (mt->mt_sw_if_index); } -/* - * mpls_tunnel_path_ext_add - * - * append a path extension to the entry's list - */ -static void -mpls_tunnel_path_ext_append (mpls_tunnel_t *mt, - const fib_route_path_t *rpath) -{ - if (NULL != rpath->frp_label_stack) - { - fib_path_ext_t *path_ext; - - vec_add2(mt->mt_path_exts, path_ext, 1); - - fib_path_ext_init(path_ext, mt->mt_path_list, rpath); - } -} - -/* - * mpls_tunnel_path_ext_insert - * - * insert, sorted, a path extension to the entry's list. - * It's not strictly necessary in sort the path extensions, since each - * extension has the path index to which it resolves. However, by being - * sorted the load-balance produced has a deterministic order, not an order - * based on the sequence of extension additions. this is a considerable benefit. - */ -static void -mpls_tunnel_path_ext_insert (mpls_tunnel_t *mt, - const fib_route_path_t *rpath) -{ - if (0 == vec_len(mt->mt_path_exts)) - return (mpls_tunnel_path_ext_append(mt, rpath)); - - if (NULL != rpath->frp_label_stack) - { - fib_path_ext_t path_ext; - int i = 0; - - fib_path_ext_init(&path_ext, mt->mt_path_list, rpath); - - while (i < vec_len(mt->mt_path_exts) && - (fib_path_ext_cmp(&mt->mt_path_exts[i], rpath) < 0)) - { - i++; - } - - vec_insert_elts(mt->mt_path_exts, &path_ext, 1, i); - } -} - void vnet_mpls_tunnel_path_add (u32 sw_if_index, fib_route_path_t *rpaths) @@ -727,7 +684,6 @@ vnet_mpls_tunnel_path_add (u32 sw_if_index, else { fib_node_index_t old_pl_index; - fib_path_ext_t *path_ext; old_pl_index = mt->mt_path_list; @@ -744,12 +700,12 @@ vnet_mpls_tunnel_path_add (u32 sw_if_index, /* * re-resolve all the path-extensions with the new path-list */ - vec_foreach(path_ext, mt->mt_path_exts) - { - fib_path_ext_resolve(path_ext, mt->mt_path_list); - } + fib_path_ext_list_resolve(&mt->mt_path_exts, mt->mt_path_list); } - mpls_tunnel_path_ext_insert(mt, rpaths); + fib_path_ext_list_insert(&mt->mt_path_exts, + mt->mt_path_list, + FIB_PATH_EXT_MPLS, + rpaths); mpls_tunnel_restack(mt); } @@ -778,7 +734,6 @@ vnet_mpls_tunnel_path_remove (u32 sw_if_index, else { fib_node_index_t old_pl_index; - fib_path_ext_t *path_ext; old_pl_index = mt->mt_path_list; @@ -805,27 +760,15 @@ vnet_mpls_tunnel_path_remove (u32 sw_if_index, /* * find the matching path extension and remove it */ - vec_foreach(path_ext, mt->mt_path_exts) - { - if (!fib_path_ext_cmp(path_ext, rpaths)) - { - /* - * delete the element moving the remaining elements down 1 position. - * this preserves the sorted order. - */ - vec_free(path_ext->fpe_label_stack); - vec_delete(mt->mt_path_exts, 1, - (path_ext - mt->mt_path_exts)); - break; - } - } - /* + fib_path_ext_list_remove(&mt->mt_path_exts, + FIB_PATH_EXT_MPLS, + rpaths); + + /* * re-resolve all the path-extensions with the new path-list */ - vec_foreach(path_ext, mt->mt_path_exts) - { - fib_path_ext_resolve(path_ext, mt->mt_path_list); - } + fib_path_ext_list_resolve(&mt->mt_path_exts, + mt->mt_path_list); mpls_tunnel_restack(mt); } @@ -843,11 +786,11 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm, vnet_main_t * vnm = vnet_get_main(); u8 is_del = 0, l2_only = 0, is_multicast =0; fib_route_path_t rpath, *rpaths = NULL; - mpls_label_t out_label = MPLS_LABEL_INVALID; - u32 sw_if_index; + u32 sw_if_index = ~0, payload_proto; clib_error_t *error = NULL; memset(&rpath, 0, sizeof(rpath)); + payload_proto = DPO_PROTO_MPLS; /* Get a line of input. */ if (! unformat_user (input, unformat_line_input, line_input)) @@ -859,54 +802,20 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm, unformat_vnet_sw_interface, vnm, &sw_if_index)) is_del = 1; + else if (unformat (line_input, "add %U", + unformat_vnet_sw_interface, vnm, + &sw_if_index)) + is_del = 0; else if (unformat (line_input, "add")) is_del = 0; - else if (unformat (line_input, "out-label %U", - unformat_mpls_unicast_label, &out_label)) - { - vec_add1(rpath.frp_label_stack, out_label); - } - else if (unformat (line_input, "via %U %U", - unformat_ip4_address, - &rpath.frp_addr.ip4, - unformat_vnet_sw_interface, vnm, - &rpath.frp_sw_if_index)) - { - rpath.frp_weight = 1; - rpath.frp_proto = FIB_PROTOCOL_IP4; - } - - else if (unformat (line_input, "via %U %U", - unformat_ip6_address, - &rpath.frp_addr.ip6, - unformat_vnet_sw_interface, vnm, - &rpath.frp_sw_if_index)) - { - rpath.frp_weight = 1; - rpath.frp_proto = FIB_PROTOCOL_IP6; - } - else if (unformat (line_input, "via %U", - unformat_ip6_address, - &rpath.frp_addr.ip6)) - { - rpath.frp_fib_index = 0; - rpath.frp_weight = 1; - rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP6; - } - else if (unformat (line_input, "via %U", - unformat_ip4_address, - &rpath.frp_addr.ip4)) - { - rpath.frp_fib_index = 0; - rpath.frp_weight = 1; - rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP4; - } else if (unformat (line_input, "l2-only")) l2_only = 1; else if (unformat (line_input, "multicast")) is_multicast = 1; + else if (unformat (line_input, "via %U", + unformat_fib_route_path, + &rpath, &payload_proto)) + vec_add1(rpaths, rpath); else { error = clib_error_return (0, "unknown input '%U'", @@ -917,7 +826,10 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm, if (is_del) { - vnet_mpls_tunnel_del(sw_if_index); + if (!vnet_mpls_tunnel_path_remove(sw_if_index, rpaths)) + { + vnet_mpls_tunnel_del(sw_if_index); + } } else { @@ -928,8 +840,10 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm, goto done; } - vec_add1(rpaths, rpath); - sw_if_index = vnet_mpls_tunnel_create(l2_only, is_multicast); + if (~0 == sw_if_index) + { + sw_if_index = vnet_mpls_tunnel_create(l2_only, is_multicast); + } vnet_mpls_tunnel_path_add(sw_if_index, rpaths); } @@ -951,7 +865,7 @@ done: VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = { .path = "mpls tunnel", .short_help = - "mpls tunnel via [addr] [interface] [out-labels]", + "mpls tunnel [multicast] [l2-only] via [next-hop-address] [next-hop-interface] [next-hop-table ] [weight ] [preference ] [udp-encap-id ] [ip4-lookup-in-table ] [ip6-lookup-in-table ] [mpls-lookup-in-table ] [resolve-via-host] [resolve-via-connected] [rx-ip4 ] [out-labels ]", .function = vnet_create_mpls_tunnel_command_fn, }; @@ -960,7 +874,6 @@ format_mpls_tunnel (u8 * s, va_list * args) { mpls_tunnel_t *mt = va_arg (*args, mpls_tunnel_t *); mpls_tunnel_attribute_t attr; - fib_path_ext_t *path_ext; s = format(s, "mpls_tunnel%d: sw_if_index:%d hw_if_index:%d", mt - mpls_tunnel_pool, @@ -976,12 +889,16 @@ format_mpls_tunnel (u8 * s, va_list * args) } s = format(s, "\n via:\n"); s = fib_path_list_format(mt->mt_path_list, s); - s = format(s, " Extensions:"); - vec_foreach(path_ext, mt->mt_path_exts) + s = format(s, "%U", format_fib_path_ext_list, &mt->mt_path_exts); + s = format(s, "\n"); + + if (mt->mt_flags & MPLS_TUNNEL_FLAG_L2) { - s = format(s, "\n %U", format_fib_path_ext, path_ext); + s = format(s, " forwarding: %U\n", + format_fib_forw_chain_type, + FIB_FORW_CHAIN_TYPE_ETHERNET); + s = format(s, " %U\n", format_dpo_id, &mt->mt_l2_lb, 2); } - s = format(s, "\n"); return (s); } @@ -1052,9 +969,7 @@ VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = { static mpls_tunnel_t * mpls_tunnel_from_fib_node (fib_node_t *node) { -#if (CLIB_DEBUG > 0) ASSERT(FIB_NODE_TYPE_MPLS_TUNNEL == node->fn_type); -#endif return ((mpls_tunnel_t*) (((char*)node) - STRUCT_OFFSET_OF(mpls_tunnel_t, mt_node))); }