From 8fc5631ef6d9cec462904203a5bb27cf5f1f7328 Mon Sep 17 00:00:00 2001 From: Adrian Pistol Date: Tue, 30 May 2023 21:27:49 +0200 Subject: [PATCH 1/2] Run clang-format on all files. --- lcpng.c | 12 ++++-- lcpng.h | 10 ++--- lcpng_adj.c | 16 ++++---- lcpng_if.api | 41 +++++++++++-------- lcpng_if_api.c | 8 ++-- lcpng_if_cli.c | 82 +++++++++++++++++++------------------ lcpng_if_node.c | 102 +++++++++++++++++++++++----------------------- lcpng_if_sync.c | 9 ++-- lcpng_interface.c | 91 ++++++++++++++++++++++++----------------- lcpng_netlink.c | 2 +- lcpng_nl_sync.c | 2 +- 11 files changed, 204 insertions(+), 171 deletions(-) diff --git a/lcpng.c b/lcpng.c index 6432dd0..3b102b5 100644 --- a/lcpng.c +++ b/lcpng.c @@ -23,7 +23,9 @@ lcp_main_t lcp_main; -u8 *lcp_get_default_ns(void) { +u8 * +lcp_get_default_ns (void) +{ lcp_main_t *lcpm = &lcp_main; if (!lcpm->default_namespace || lcpm->default_namespace[0] == 0) @@ -31,7 +33,9 @@ u8 *lcp_get_default_ns(void) { return lcpm->default_namespace; } -int lcp_get_default_ns_fd(void) { +int +lcp_get_default_ns_fd (void) +{ lcp_main_t *lcpm = &lcp_main; return lcpm->default_ns_fd; @@ -40,7 +44,9 @@ int lcp_get_default_ns_fd(void) { /* * ns is expected to be or look like a NUL-terminated C string. */ -int lcp_set_default_ns(u8 *ns) { +int +lcp_set_default_ns (u8 *ns) +{ lcp_main_t *lcpm = &lcp_main; char *p; int len; diff --git a/lcpng.h b/lcpng.h index 8917db3..cf51411 100644 --- a/lcpng.h +++ b/lcpng.h @@ -21,8 +21,8 @@ typedef struct lcp_main_s { - u16 msg_id_base; /* API message ID base */ - u8 *default_namespace; /* default namespace if set */ + u16 msg_id_base; /* API message ID base */ + u8 *default_namespace; /* default namespace if set */ int default_ns_fd; u8 lcp_auto_subint; /* Automatically create/delete LCP sub-interfaces */ u8 lcp_sync; /* Automatically sync VPP changes to LCP */ @@ -35,9 +35,9 @@ extern lcp_main_t lcp_main; /** * Get/Set the default namespace for LCP host taps. */ -int lcp_set_default_ns(u8 *ns); -u8 *lcp_get_default_ns(void); /* Returns NULL or shared string */ -int lcp_get_default_ns_fd(void); +int lcp_set_default_ns (u8 *ns); +u8 *lcp_get_default_ns (void); /* Returns NULL or shared string */ +int lcp_get_default_ns_fd (void); /* * Sync state from VPP into all LCP devices diff --git a/lcpng_adj.c b/lcpng_adj.c index 0b8aa77..2d7bf6c 100644 --- a/lcpng_adj.c +++ b/lcpng_adj.c @@ -185,17 +185,17 @@ lcp_adj_show_cmd (vlib_main_t *vm, unformat_input_t *input, if (unformat (input, "verbose")) verbose = 1; - vlib_cli_output(vm, "lcp Adjs:\n%U", BV(format_bihash), &lcp_adj_tbl, - verbose); + vlib_cli_output (vm, "lcp Adjs:\n%U", BV (format_bihash), &lcp_adj_tbl, + verbose); return 0; } -VLIB_CLI_COMMAND(lcp_itf_pair_show_cmd_node, static) = { - .path = "show lcp adj", - .function = lcp_adj_show_cmd, - .short_help = "show lcp adj", - .is_mp_safe = 1, +VLIB_CLI_COMMAND (lcp_itf_pair_show_cmd_node, static) = { + .path = "show lcp adj", + .function = lcp_adj_show_cmd, + .short_help = "show lcp adj", + .is_mp_safe = 1, }; const adj_delegate_vft_t lcp_adj_vft = { @@ -210,7 +210,7 @@ lcp_adj_init (vlib_main_t *vm) { adj_type = adj_delegate_register_new_type (&lcp_adj_vft); - BV(clib_bihash_init)(&lcp_adj_tbl, "lcp ADJ table", 1024, 1 << 24); + BV (clib_bihash_init) (&lcp_adj_tbl, "lcp ADJ table", 1024, 1 << 24); BV (clib_bihash_set_kvp_format_fn) (&lcp_adj_tbl, format_lcp_adj_kvp); return (NULL); diff --git a/lcpng_if.api b/lcpng_if.api index 059ce64..ddd299b 100644 --- a/lcpng_if.api +++ b/lcpng_if.api @@ -30,7 +30,7 @@ autoreply define lcp_default_ns_set { u32 client_index; u32 context; - string netns[32]; /* LCP_NS_LEN */ + string netns[32]; /* LCP_NS_LEN */ }; /** \brief get the default Linux Control Plane netns @@ -51,7 +51,7 @@ define lcp_default_ns_get define lcp_default_ns_get_reply { u32 context; - string netns[32]; /* LCP_NS_LEN */ + string netns[32]; /* LCP_NS_LEN */ }; enum lcp_itf_host_type : u8 @@ -75,9 +75,9 @@ autoreply autoendian define lcp_itf_pair_add_del u32 context; bool is_add; vl_api_interface_index_t sw_if_index; - string host_if_name[16]; /* IFNAMSIZ */ + string host_if_name[16]; /* IFNAMSIZ */ vl_api_lcp_itf_host_type_t host_if_type; - string netns[32]; /* LCP_NS_LEN */ + string netns[32]; /* LCP_NS_LEN */ }; autoendian define lcp_itf_pair_add_del_v2 { @@ -85,9 +85,9 @@ autoendian define lcp_itf_pair_add_del_v2 u32 context; bool is_add; vl_api_interface_index_t sw_if_index; - string host_if_name[16]; /* IFNAMSIZ */ + string host_if_name[16]; /* IFNAMSIZ */ vl_api_lcp_itf_host_type_t host_if_type; - string netns[32]; /* LCP_NS_LEN */ + string netns[32]; /* LCP_NS_LEN */ }; define lcp_itf_pair_add_del_v2_reply { @@ -129,14 +129,15 @@ autoendian define lcp_itf_pair_details vl_api_interface_index_t phy_sw_if_index; vl_api_interface_index_t host_sw_if_index; u32 vif_index; - string host_if_name[16]; /* IFNAMSIZ */ + string host_if_name[16]; /* IFNAMSIZ */ vl_api_lcp_itf_host_type_t host_if_type; - string netns[32]; /* LCP_NS_LEN */ + string netns[32]; /* LCP_NS_LEN */ }; -service { - rpc lcp_itf_pair_get returns lcp_itf_pair_get_reply - stream lcp_itf_pair_details; +service +{ + rpc lcp_itf_pair_get returns lcp_itf_pair_get_reply stream + lcp_itf_pair_details; }; /** \brief Replace end/begin @@ -155,14 +156,17 @@ autoreply define lcp_itf_pair_replace_end /* * Linux-CP Error counters/messages */ -counters linuxcp { - packets { +counters linuxcp +{ + packets + { severity info; type counter64; units "packets"; description "ARP packets processed"; }; - copies { + copies + { severity info; type counter64; units "packets"; @@ -170,9 +174,12 @@ counters linuxcp { }; }; -paths { - "/err/linux-cp-arp-phy" "linuxcp"; - "/err/linux-cp-arp-host" "linuxcp"; +paths +{ + "/err/linux-cp-arp-phy" + "linuxcp"; + "/err/linux-cp-arp-host" + "linuxcp"; }; /* diff --git a/lcpng_if_api.c b/lcpng_if_api.c index 747cbee..58c46f6 100644 --- a/lcpng_if_api.c +++ b/lcpng_if_api.c @@ -162,18 +162,20 @@ vl_api_lcp_itf_pair_get_t_handler (vl_api_lcp_itf_pair_get_t *mp) } static void -vl_api_lcp_default_ns_set_t_handler(vl_api_lcp_default_ns_set_t *mp) { +vl_api_lcp_default_ns_set_t_handler (vl_api_lcp_default_ns_set_t *mp) +{ vl_api_lcp_default_ns_set_reply_t *rmp; int rv; mp->netns[LCP_NS_LEN - 1] = 0; rv = lcp_set_default_ns (mp->netns); - REPLY_MACRO(VL_API_LCP_DEFAULT_NS_SET_REPLY); + REPLY_MACRO (VL_API_LCP_DEFAULT_NS_SET_REPLY); } static void -vl_api_lcp_default_ns_get_t_handler(vl_api_lcp_default_ns_get_t *mp) { +vl_api_lcp_default_ns_get_t_handler (vl_api_lcp_default_ns_get_t *mp) +{ vl_api_lcp_default_ns_get_reply_t *rmp; vl_api_registration_t *reg; char *ns; diff --git a/lcpng_if_cli.c b/lcpng_if_cli.c index d237092..beab982 100644 --- a/lcpng_if_cli.c +++ b/lcpng_if_cli.c @@ -99,16 +99,16 @@ lcp_itf_pair_create_command_fn (vlib_main_t *vm, unformat_input_t *input, vec_free (ns); if (r) - return clib_error_return(0, "lcp pair creation failed (%d)", r); + return clib_error_return (0, "lcp pair creation failed (%d)", r); return 0; } -VLIB_CLI_COMMAND(lcp_itf_pair_create_command, static) = { - .path = "lcp create", - .short_help = "lcp create | host-if " - "netns [tun]", - .function = lcp_itf_pair_create_command_fn, +VLIB_CLI_COMMAND (lcp_itf_pair_create_command, static) = { + .path = "lcp create", + .short_help = "lcp create | host-if " + "netns [tun]", + .function = lcp_itf_pair_create_command_fn, }; static clib_error_t * @@ -173,39 +173,41 @@ VLIB_CLI_COMMAND (lcp_auto_subint_command, static) = { .function = lcp_auto_subint_command_fn, }; -static clib_error_t *lcp_default_netns_command_fn(vlib_main_t *vm, - unformat_input_t *input, - vlib_cli_command_t *cmd) { +static clib_error_t * +lcp_default_netns_command_fn (vlib_main_t *vm, unformat_input_t *input, + vlib_cli_command_t *cmd) +{ unformat_input_t _line_input, *line_input = &_line_input; u8 *ns; int r; clib_error_t *error = NULL; - if (!unformat_user(input, unformat_line_input, line_input)) + if (!unformat_user (input, unformat_line_input, line_input)) return 0; ns = 0; - while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) { - if (unformat(line_input, "netns %s", &ns)) - ; - else if (unformat(line_input, "clear netns")) - ; - else - { - vec_free (ns); - error = clib_error_return (0, "unknown input `%U'", - format_unformat_error, line_input); - goto done; - } - } + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "netns %s", &ns)) + ; + else if (unformat (line_input, "clear netns")) + ; + else + { + vec_free (ns); + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } + } - vlib_cli_output(vm, "lcp set default netns %v\n", ns); + vlib_cli_output (vm, "lcp set default netns %v\n", ns); - r = lcp_set_default_ns(ns); + r = lcp_set_default_ns (ns); if (r) - return clib_error_return(0, "linux-cp set default netns failed (%d)", r); + return clib_error_return (0, "linux-cp set default netns failed (%d)", r); done: unformat_free (line_input); @@ -213,10 +215,10 @@ done: return error; } -VLIB_CLI_COMMAND(lcp_default_netns_command, static) = { - .path = "lcp default", - .short_help = "lcp default netns []", - .function = lcp_default_netns_command_fn, +VLIB_CLI_COMMAND (lcp_default_netns_command, static) = { + .path = "lcp default", + .short_help = "lcp default netns []", + .function = lcp_default_netns_command_fn, }; static clib_error_t * @@ -253,14 +255,14 @@ lcp_itf_pair_delete_command_fn (vlib_main_t *vm, unformat_input_t *input, r = lcp_itf_pair_delete (sw_if_index); if (r) - return clib_error_return(0, "lcp pair deletion failed (%d)", r); + return clib_error_return (0, "lcp pair deletion failed (%d)", r); return 0; } -VLIB_CLI_COMMAND(lcp_itf_pair_delete_command, static) = { - .path = "lcp delete", - .short_help = "lcp delete |", - .function = lcp_itf_pair_delete_command_fn, +VLIB_CLI_COMMAND (lcp_itf_pair_delete_command, static) = { + .path = "lcp delete", + .short_help = "lcp delete |", + .function = lcp_itf_pair_delete_command_fn, }; static clib_error_t * @@ -287,11 +289,11 @@ lcp_itf_pair_show_cmd (vlib_main_t *vm, unformat_input_t *input, return 0; } -VLIB_CLI_COMMAND(lcp_itf_pair_show_cmd_node, static) = { - .path = "show lcp", - .function = lcp_itf_pair_show_cmd, - .short_help = "show lcp [phy ]", - .is_mp_safe = 1, +VLIB_CLI_COMMAND (lcp_itf_pair_show_cmd_node, static) = { + .path = "show lcp", + .function = lcp_itf_pair_show_cmd, + .short_help = "show lcp [phy ]", + .is_mp_safe = 1, }; clib_error_t * diff --git a/lcpng_if_node.c b/lcpng_if_node.c index 1095576..80417e6 100644 --- a/lcpng_if_node.c +++ b/lcpng_if_node.c @@ -181,7 +181,7 @@ format_lcp_punt_l3_trace (u8 *s, va_list *args) CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); lcp_punt_l3_trace_t *t = va_arg (*args, lcp_punt_l3_trace_t *); - s = format(s, "linux-cp-punt-l3: %u", t->phy_sw_if_index); + s = format (s, "linux-cp-punt-l3: %u", t->phy_sw_if_index); return s; } @@ -261,16 +261,16 @@ VLIB_REGISTER_NODE(lcp_punt_l3_node) = { }, }; -VNET_FEATURE_INIT(lcp_punt_l3_ip4, static) = { - .arc_name = "ip4-punt", - .node_name = "linux-cp-punt-l3", - .runs_before = VNET_FEATURES("ip4-punt-redirect"), +VNET_FEATURE_INIT (lcp_punt_l3_ip4, static) = { + .arc_name = "ip4-punt", + .node_name = "linux-cp-punt-l3", + .runs_before = VNET_FEATURES ("ip4-punt-redirect"), }; -VNET_FEATURE_INIT(lip_punt_l3_ip6, static) = { - .arc_name = "ip6-punt", - .node_name = "linux-cp-punt-l3", - .runs_before = VNET_FEATURES("ip6-punt-redirect"), +VNET_FEATURE_INIT (lip_punt_l3_ip6, static) = { + .arc_name = "ip6-punt", + .node_name = "linux-cp-punt-l3", + .runs_before = VNET_FEATURES ("ip6-punt-redirect"), }; #define foreach_lcp_xc \ @@ -408,34 +408,34 @@ VLIB_NODE_FN (lcp_xc_ip6) return (lcp_xc_inline (vm, node, frame, AF_IP6)); } -VLIB_REGISTER_NODE(lcp_xc_ip4) = {.name = "linux-cp-xc-ip4", - .vector_size = sizeof(u32), - .format_trace = format_lcp_xc_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .sibling_of = "ip4-rewrite"}; +VLIB_REGISTER_NODE (lcp_xc_ip4) = { .name = "linux-cp-xc-ip4", + .vector_size = sizeof (u32), + .format_trace = format_lcp_xc_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .sibling_of = "ip4-rewrite" }; -VNET_FEATURE_INIT(lcp_xc_ip4_ucast_node, static) = { - .arc_name = "ip4-unicast", - .node_name = "linux-cp-xc-ip4", +VNET_FEATURE_INIT (lcp_xc_ip4_ucast_node, static) = { + .arc_name = "ip4-unicast", + .node_name = "linux-cp-xc-ip4", }; -VNET_FEATURE_INIT(lcp_xc_ip4_mcast_node, static) = { - .arc_name = "ip4-multicast", - .node_name = "linux-cp-xc-ip4", +VNET_FEATURE_INIT (lcp_xc_ip4_mcast_node, static) = { + .arc_name = "ip4-multicast", + .node_name = "linux-cp-xc-ip4", }; -VLIB_REGISTER_NODE(lcp_xc_ip6) = {.name = "linux-cp-xc-ip6", - .vector_size = sizeof(u32), - .format_trace = format_lcp_xc_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .sibling_of = "ip6-rewrite"}; +VLIB_REGISTER_NODE (lcp_xc_ip6) = { .name = "linux-cp-xc-ip6", + .vector_size = sizeof (u32), + .format_trace = format_lcp_xc_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .sibling_of = "ip6-rewrite" }; -VNET_FEATURE_INIT(lcp_xc_ip6_ucast_node, static) = { - .arc_name = "ip6-unicast", - .node_name = "linux-cp-xc-ip6", +VNET_FEATURE_INIT (lcp_xc_ip6_ucast_node, static) = { + .arc_name = "ip6-unicast", + .node_name = "linux-cp-xc-ip6", }; -VNET_FEATURE_INIT(lcp_xc_ip6_mcast_node, static) = { - .arc_name = "ip6-multicast", - .node_name = "linux-cp-xc-ip6", +VNET_FEATURE_INIT (lcp_xc_ip6_mcast_node, static) = { + .arc_name = "ip6-multicast", + .node_name = "linux-cp-xc-ip6", }; typedef enum @@ -557,14 +557,14 @@ VLIB_REGISTER_NODE(lcp_xc_l3_ip4_node) = { }, }; -VNET_FEATURE_INIT(lcp_xc_node_l3_ip4_unicast, static) = { - .arc_name = "ip4-unicast", - .node_name = "linux-cp-xc-l3-ip4", +VNET_FEATURE_INIT (lcp_xc_node_l3_ip4_unicast, static) = { + .arc_name = "ip4-unicast", + .node_name = "linux-cp-xc-l3-ip4", }; -VNET_FEATURE_INIT(lcp_xc_node_l3_ip4_multicaast, static) = { - .arc_name = "ip4-multicast", - .node_name = "linux-cp-xc-l3-ip4", +VNET_FEATURE_INIT (lcp_xc_node_l3_ip4_multicaast, static) = { + .arc_name = "ip4-multicast", + .node_name = "linux-cp-xc-l3-ip4", }; VLIB_REGISTER_NODE(lcp_xc_l3_ip6_node) = { @@ -581,14 +581,14 @@ VLIB_REGISTER_NODE(lcp_xc_l3_ip6_node) = { }, }; -VNET_FEATURE_INIT(lcp_xc_node_l3_ip6_unicast, static) = { - .arc_name = "ip6-unicast", - .node_name = "linux-cp-xc-l3-ip6", +VNET_FEATURE_INIT (lcp_xc_node_l3_ip6_unicast, static) = { + .arc_name = "ip6-unicast", + .node_name = "linux-cp-xc-l3-ip6", }; -VNET_FEATURE_INIT(lcp_xc_node_l3_ip6_multicast, static) = { - .arc_name = "ip6-multicast", - .node_name = "linux-cp-xc-l3-ip6", +VNET_FEATURE_INIT (lcp_xc_node_l3_ip6_multicast, static) = { + .arc_name = "ip6-multicast", + .node_name = "linux-cp-xc-l3-ip6", }; #define foreach_lcp_arp \ @@ -850,10 +850,10 @@ VLIB_REGISTER_NODE(lcp_arp_phy_node) = { }, }; -VNET_FEATURE_INIT(lcp_arp_phy_arp_feat, static) = { - .arc_name = "arp", - .node_name = "linux-cp-arp-phy", - .runs_before = VNET_FEATURES("arp-reply"), +VNET_FEATURE_INIT (lcp_arp_phy_arp_feat, static) = { + .arc_name = "arp", + .node_name = "linux-cp-arp-phy", + .runs_before = VNET_FEATURES ("arp-reply"), }; /** @@ -935,10 +935,10 @@ VLIB_REGISTER_NODE(lcp_arp_host_node) = { }, }; -VNET_FEATURE_INIT(lcp_arp_host_arp_feat, static) = { - .arc_name = "arp", - .node_name = "linux-cp-arp-host", - .runs_before = VNET_FEATURES("arp-reply"), +VNET_FEATURE_INIT (lcp_arp_host_arp_feat, static) = { + .arc_name = "arp", + .node_name = "linux-cp-arp-host", + .runs_before = VNET_FEATURES ("arp-reply"), }; /* diff --git a/lcpng_if_sync.c b/lcpng_if_sync.c index 4d84570..43bbb0a 100644 --- a/lcpng_if_sync.c +++ b/lcpng_if_sync.c @@ -170,7 +170,7 @@ lcp_itf_pair_sync_state_hw (vnet_hw_interface_t *hi) } static clib_error_t * -lcp_itf_admin_state_change (vnet_main_t * vnm, u32 sw_if_index, u32 flags) +lcp_itf_admin_state_change (vnet_main_t *vnm, u32 sw_if_index, u32 flags) { lcp_itf_pair_t *lip; vnet_hw_interface_t *hi; @@ -184,7 +184,8 @@ lcp_itf_admin_state_change (vnet_main_t * vnm, u32 sw_if_index, u32 flags) // Sync interface state changes into host lip = lcp_itf_pair_get (lcp_itf_pair_find_by_phy (sw_if_index)); - if (!lip) return NULL; + if (!lip) + return NULL; LCP_IF_INFO ("admin_state_change: %U flags %u", format_lcp_itf_pair, lip, flags); @@ -213,9 +214,9 @@ lcp_itf_admin_state_change (vnet_main_t * vnm, u32 sw_if_index, u32 flags) lcp_itf_pair_sync_state_hw (hi); return NULL; -} +} -VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(lcp_itf_admin_state_change); +VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (lcp_itf_admin_state_change); static clib_error_t * lcp_itf_mtu_change (vnet_main_t *vnm, u32 sw_if_index, u32 flags) diff --git a/lcpng_interface.c b/lcpng_interface.c index c910743..dd9cba6 100644 --- a/lcpng_interface.c +++ b/lcpng_interface.c @@ -128,7 +128,7 @@ lcp_itf_pair_show (u32 phy_sw_if_index) index_t api; vm = vlib_get_main (); - ns = lcp_get_default_ns(); + ns = lcp_get_default_ns (); vlib_cli_output (vm, "lcp default netns %v\n", ns); vlib_cli_output (vm, "lcp lcp-auto-subint %s\n", lcp_auto_subint () ? "on" : "off"); @@ -149,8 +149,10 @@ lcp_itf_pair_show (u32 phy_sw_if_index) lcp_itf_pair_t * lcp_itf_pair_get (u32 index) { - if (!lcp_itf_pair_pool) return NULL; - if (index == INDEX_INVALID) return NULL; + if (!lcp_itf_pair_pool) + return NULL; + if (index == INDEX_INVALID) + return NULL; return pool_elt_at_index (lcp_itf_pair_pool, index); } @@ -230,15 +232,17 @@ lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name, if (lipi != INDEX_INVALID) return VNET_API_ERROR_VALUE_EXIST; - if (host_sw_if_index == ~0) { + if (host_sw_if_index == ~0) + { LCP_IF_ERROR ("pair_add: Cannot add LIP - invalid host"); return VNET_API_ERROR_INVALID_SW_IF_INDEX; - } + } - if (phy_sw_if_index == ~0) { + if (phy_sw_if_index == ~0) + { LCP_IF_ERROR ("pair_add: Cannot add LIP - invalid phy"); return VNET_API_ERROR_INVALID_SW_IF_INDEX; - } + } LCP_IF_NOTICE ( "pair_add: Adding LIP for host:%U phy:%U host_if:%v vif:%d netns:%v", @@ -304,10 +308,10 @@ lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name, /* enable ARP feature node for broadcast interfaces */ if (lip->lip_host_type != LCP_ITF_HOST_TUN) { - vnet_feature_enable_disable("arp", "linux-cp-arp-phy", - lip->lip_phy_sw_if_index, 1, NULL, 0); - vnet_feature_enable_disable("arp", "linux-cp-arp-host", - lip->lip_host_sw_if_index, 1, NULL, 0); + vnet_feature_enable_disable ("arp", "linux-cp-arp-phy", + lip->lip_phy_sw_if_index, 1, NULL, 0); + vnet_feature_enable_disable ("arp", "linux-cp-arp-host", + lip->lip_host_sw_if_index, 1, NULL, 0); } else { @@ -343,11 +347,12 @@ lcp_netlink_add_link_vlan (int parent, u32 vlan, u16 proto, const char *name) int err; sk = nl_socket_alloc (); - if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0) { + if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0) + { LCP_IF_ERROR ("netlink_add_link_vlan: Netlink connect error: %s", nl_geterror (err)); return clib_error_return (NULL, "Unable to connect socket: %d", err); - } + } link = rtnl_link_vlan_alloc (); @@ -356,11 +361,12 @@ lcp_netlink_add_link_vlan (int parent, u32 vlan, u16 proto, const char *name) rtnl_link_vlan_set_id (link, vlan); rtnl_link_vlan_set_protocol (link, htons (proto)); - if ((err = rtnl_link_add (sk, link, NLM_F_CREATE)) < 0) { + if ((err = rtnl_link_add (sk, link, NLM_F_CREATE)) < 0) + { LCP_IF_ERROR ("netlink_add_link_vlan: Netlink link add error: %s", nl_geterror (err)); return clib_error_return (NULL, "Unable to add link %s: %d", name, err); - } + } rtnl_link_put (link); nl_close (sk); @@ -432,10 +438,10 @@ lcp_itf_pair_del (u32 phy_sw_if_index) /* disable ARP feature node for broadcast interfaces */ if (lip->lip_host_type != LCP_ITF_HOST_TUN) { - vnet_feature_enable_disable("arp", "linux-cp-arp-phy", - lip->lip_phy_sw_if_index, 0, NULL, 0); - vnet_feature_enable_disable("arp", "linux-cp-arp-host", - lip->lip_host_sw_if_index, 0, NULL, 0); + vnet_feature_enable_disable ("arp", "linux-cp-arp-phy", + lip->lip_phy_sw_if_index, 0, NULL, 0); + vnet_feature_enable_disable ("arp", "linux-cp-arp-host", + lip->lip_host_sw_if_index, 0, NULL, 0); } else { @@ -611,7 +617,8 @@ lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state) vnet_main_t *vnm = vnet_get_main (); int curr_ns_fd, vif_ns_fd; - if (!lip) return; + if (!lip) + return; curr_ns_fd = vif_ns_fd = -1; @@ -769,37 +776,41 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name, const vnet_hw_interface_t *hw; lcp_itf_pair_t *lip; - if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index)) { + if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index)) + { LCP_IF_ERROR ("pair_create: Invalid phy index %u", phy_sw_if_index); return VNET_API_ERROR_INVALID_SW_IF_INDEX; - } + } - if (!lcp_validate_if_name (host_if_name)) { + if (!lcp_validate_if_name (host_if_name)) + { LCP_IF_ERROR ("pair_create: Invalid host-if-name '%s'", host_if_name); return VNET_API_ERROR_INVALID_ARGUMENT; - } + } vnm = vnet_get_main (); sw = vnet_get_sw_interface (vnm, phy_sw_if_index); hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index); - if (!sw && !hw) { + if (!sw && !hw) + { LCP_IF_ERROR ("pair_create: Invalid interface"); return VNET_API_ERROR_INVALID_SW_IF_INDEX; - } + } if (hw->hw_class_index != ethernet_hw_interface_class.index && - host_if_type == LCP_ITF_HOST_TAP) { + host_if_type == LCP_ITF_HOST_TAP) + { LCP_IF_ERROR ( "pair_create: don't create TAP for non-eth interface; use tun"); return VNET_API_ERROR_INVALID_ARGUMENT; - } + } /* * Use interface-specific netns if supplied. * Otherwise, use netns if defined, otherwise use the OS default. */ if (ns == 0 || ns[0] == 0) - ns = lcp_get_default_ns(); + ns = lcp_get_default_ns (); /* sub interfaces do not need a tap created */ if (vnet_sw_interface_is_sub (vnm, phy_sw_if_index)) @@ -812,16 +823,19 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name, u16 vlan, proto; u32 parent_vif_index; - if (sw->type == VNET_SW_INTERFACE_TYPE_SUB && sw->sub.eth.flags.exact_match == 0) { + if (sw->type == VNET_SW_INTERFACE_TYPE_SUB && + sw->sub.eth.flags.exact_match == 0) + { LCP_IF_ERROR ("pair_create: Cannot create LIP for a " "sub-interface without exact-match set"); return VNET_API_ERROR_INVALID_ARGUMENT; - } + } outer_vlan = sw->sub.eth.outer_vlan_id; inner_vlan = sw->sub.eth.inner_vlan_id; outer_proto = inner_proto = ETH_P_8021Q; - if (1 == sw->sub.eth.flags.dot1ad) outer_proto = ETH_P_8021AD; + if (1 == sw->sub.eth.flags.dot1ad) + outer_proto = ETH_P_8021AD; LCP_IF_INFO ("pair_create: creating dot1%s %d inner-dot1q %d on %U", sw->sub.eth.flags.dot1ad ? "ad" : "q", outer_vlan, @@ -891,7 +905,7 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name, "vlan %d proto %s on %U", outer_vlan, outer_proto == ETH_P_8021AD ? "dot1ad" : - "dot1q", + "dot1q", format_vnet_sw_if_index_name, vnet_get_main (), hw->sw_if_index); return VNET_API_ERROR_INVALID_SW_IF_INDEX; @@ -916,13 +930,14 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name, err = lcp_netlink_add_link_vlan (parent_vif_index, vlan, proto, (const char *) host_if_name); - if (err != 0) { + if (err != 0) + { LCP_IF_ERROR ("pair_create: Cannot create link " "outer(proto:0x%04x,vlan:%u).inner(proto:0x%" "04x,vlan:%u) name:'%s'", outer_proto, outer_vlan, inner_proto, inner_vlan, host_if_name); - } + } if (!err) vif_index = if_nametoindex ((char *) host_if_name); @@ -1190,12 +1205,12 @@ VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down); static clib_error_t * lcp_itf_pair_init (vlib_main_t *vm) { - vlib_punt_hdl_t punt_hdl = vlib_punt_client_register("linux-cp"); + vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("linux-cp"); lcp_itf_pair_logger = vlib_log_register_class ("linux-cp", "if"); /* punt IKE */ - vlib_punt_register(punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0], - "linux-cp-punt"); + vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0], + "linux-cp-punt"); /* punt all unknown ports */ udp_punt_unknown (vm, 0, 1); diff --git a/lcpng_netlink.c b/lcpng_netlink.c index 00fc86b..bd4ec1f 100644 --- a/lcpng_netlink.c +++ b/lcpng_netlink.c @@ -408,7 +408,7 @@ lcp_nl_pair_add_cb (lcp_itf_pair_t *lip) nm->nl_ns.clib_file_lcp_refcnt); if ((nm->nl_ns.clib_file_lcp_refcnt > 0) && - vec_cmp(nm->nl_ns.netns_name, lip->lip_namespace)) + vec_cmp (nm->nl_ns.netns_name, lip->lip_namespace)) { LCP_NL_WARN ( "pair_add_cb: Existing netlink listener for netns %v -- this " diff --git a/lcpng_nl_sync.c b/lcpng_nl_sync.c index 52d532d..6496e24 100644 --- a/lcpng_nl_sync.c +++ b/lcpng_nl_sync.c @@ -461,7 +461,7 @@ lcp_nl_route_add (struct rtnl_route *rr, int is_replace) uint8_t rtype, rproto; LCP_NL_DBG ("route_add: netlink %U %s", format_nl_object, rr, - is_replace?"replace":""); + is_replace ? "replace" : ""); rtype = rtnl_route_get_type (rr); table_id = rtnl_route_get_table (rr); From 153628a3dede6814b79452cea05ecb3351a1f3b1 Mon Sep 17 00:00:00 2001 From: Adrian Pistol Date: Tue, 30 May 2023 21:25:26 +0200 Subject: [PATCH 2/2] Basic MPLS support. 1) Imports ENCAP_MPLS labels from IPv4/IPv6 routes. Note that this requires libnl 3.6.0 or newer. In previous patches, the fib_path_ext_t had a path ID of -1. After a long investigation, it turned out to be caused by route weight being set to 0. There is a comment explaining more details. 2) Handles MPLS routes. MPLS routes were wrongly added as IPv4 routes before. POP and SWAP are now both supported. All the routes are installed as NON-EOS and EOS routes, as the Linux kernel does not differentiate. EOS POP used in PHP uses the next-hop address family to determine the resulting address family. This patch is sufficient for P setups. PE setups with implicit null should also function okay, as long as a seperate label gets programmed per address family. PE setups with explicit null will also forward packets, but punting is a bit odd and needs MPLS input enabled on the LCP host device. Make sure to enable MPLS in VPP first. 3) Propagate MPLS input state to LCP Pair and Linux. Since the Linux kernel uses the MPLS routes itself, the LCP pair tap needs MPLS enabled to allow host originated packets. This also syncs the Linux `net.mpls.conf..input` sysctl to allow punted packets to have MPLS labels, mostly explicit nulls. For that to work, load the mpls kernel modules. 4) Cross connect MPLS packets from Linux directly to interface-output This is a port of https://gerrit.fd.io/r/c/vpp/+/38702 --- CMakeLists.txt | 1 + lcpng_if_node.c | 97 ++++++++++++++++++++++++++ lcpng_interface.c | 7 ++ lcpng_mpls_sync.c | 140 +++++++++++++++++++++++++++++++++++++ lcpng_netlink.h | 1 + lcpng_nl_sync.c | 172 +++++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 409 insertions(+), 9 deletions(-) create mode 100644 lcpng_mpls_sync.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f2149a..4e47d1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ add_vpp_library(lcpng lcpng_interface.c lcpng_adj.c lcpng_if_sync.c + lcpng_mpls_sync.c lcpng.c LINK_LIBRARIES diff --git a/lcpng_if_node.c b/lcpng_if_node.c index 80417e6..e1d674b 100644 --- a/lcpng_if_node.c +++ b/lcpng_if_node.c @@ -438,6 +438,103 @@ VNET_FEATURE_INIT (lcp_xc_ip6_mcast_node, static) = { .node_name = "linux-cp-xc-ip6", }; +typedef enum +{ + LCP_XC_MPLS_NEXT_DROP, + LCP_XC_MPLS_NEXT_IO, + LCP_XC_MPLS_N_NEXT, +} lcp_xc_mpls_next_t; + +static_always_inline uword +lcp_xc_mpls_inline (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + u32 n_left_from, *from, *to_next, n_left_to_next; + lcp_xc_next_t next_index; + + next_index = 0; + n_left_from = frame->n_vectors; + from = vlib_frame_vector_args (frame); + + while (n_left_from > 0) + { + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + const ethernet_header_t *eth; + const lcp_itf_pair_t *lip; + u32 next0, bi0, lipi, ai; + vlib_buffer_t *b0; + // const ip_adjacency_t *adj; + + bi0 = to_next[0] = from[0]; + + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + lipi = + lcp_itf_pair_find_by_host (vnet_buffer (b0)->sw_if_index[VLIB_RX]); + lip = lcp_itf_pair_get (lipi); + + vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip->lip_phy_sw_if_index; + vlib_buffer_advance (b0, -lip->lip_rewrite_len); + eth = vlib_buffer_get_current (b0); + + ai = ADJ_INDEX_INVALID; + next0 = LCP_XC_MPLS_NEXT_DROP; + if (!ethernet_address_cast (eth->dst_address)) + ai = lcp_adj_lkup ((u8 *) eth, lip->lip_rewrite_len, + vnet_buffer (b0)->sw_if_index[VLIB_TX]); + if (ai != ADJ_INDEX_INVALID) + { + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ai; + next0 = LCP_XC_MPLS_NEXT_IO; + } + + if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED))) + { + lcp_xc_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->phy_sw_if_index = lip->lip_phy_sw_if_index; + t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX]; + } + + 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); + } + + return frame->n_vectors; +} + +VLIB_NODE_FN (lcp_xc_mpls) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return (lcp_xc_mpls_inline (vm, node, frame)); +} + +VLIB_REGISTER_NODE ( + lcp_xc_mpls) = { .name = "linux-cp-xc-mpls", + .vector_size = sizeof (u32), + .format_trace = format_lcp_xc_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_next_nodes = LCP_XC_MPLS_N_NEXT, + .next_nodes = { + [LCP_XC_MPLS_NEXT_DROP] = "error-drop", + [LCP_XC_MPLS_NEXT_IO] = "interface-output", + } }; + +VNET_FEATURE_INIT (lcp_xc_mpls_node, static) = { + .arc_name = "mpls-input", + .node_name = "linux-cp-xc-mpls", +}; + typedef enum { LCP_XC_L3_NEXT_XC, diff --git a/lcpng_interface.c b/lcpng_interface.c index dd9cba6..a93d770 100644 --- a/lcpng_interface.c +++ b/lcpng_interface.c @@ -282,6 +282,10 @@ lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name, lcp_itf_l3_feat_names[lip->lip_host_type][af], lip->lip_host_sw_if_index, 1, NULL, 0); + /* Enable MPLS */ + vnet_feature_enable_disable ("mpls-input", "linux-cp-xc-mpls", + lip->lip_host_sw_if_index, 1, NULL, 0); + /* * Configure passive punt to the host interface. */ @@ -430,6 +434,9 @@ lcp_itf_pair_del (u32 phy_sw_if_index) lcp_itf_l3_feat_names[lip->lip_host_type][af], lip->lip_host_sw_if_index, 0, NULL, 0); + vnet_feature_enable_disable ("mpls-input", "linux-cp-xc-mpls", + lip->lip_host_sw_if_index, 0, NULL, 0); + lcp_itf_unset_adjs (lip); ip4_punt_redirect_del (lip->lip_phy_sw_if_index); diff --git a/lcpng_mpls_sync.c b/lcpng_mpls_sync.c new file mode 100644 index 0000000..47fed5e --- /dev/null +++ b/lcpng_mpls_sync.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2023 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include +#include +#include + +#include + +#include + +void +lcp_mpls_sync_pair_add_cb (lcp_itf_pair_t *lip) +{ + u8 phy_is_enabled = mpls_sw_interface_is_enabled (lip->lip_phy_sw_if_index); + LCP_IF_DBG ("mpls_pair_add_cb: mpls enabled %u, parent %U", phy_is_enabled, + format_lcp_itf_pair, lip); + if (phy_is_enabled) + mpls_sw_interface_enable_disable (&mpls_main, lip->lip_host_sw_if_index, + 1); +} + +void +lcp_mpls_sync_state_cb (struct mpls_main_t *mm, uword opaque, u32 sw_if_index, + u32 is_enable) +{ + lcp_itf_pair_t *lip; + index_t lipi; + int curr_ns_fd = -1; + int vif_ns_fd = -1; + int ctl_fd = -1; + u8 *ctl_path = NULL; + + LCP_IF_DBG ("mpls_sync_state_cb: called for sw_if_index %u", sw_if_index); + + // If device is LCP PHY, sync state to host tap. + lipi = lcp_itf_pair_find_by_phy (sw_if_index); + if (INDEX_INVALID != lipi) + { + lip = lcp_itf_pair_get (lipi); + LCP_IF_DBG ("mpls_sync_state_cb: mpls enabled %u parent %U", is_enable, + format_lcp_itf_pair, lip); + mpls_sw_interface_enable_disable (&mpls_main, lip->lip_host_sw_if_index, + is_enable); + return; + } + + // If device is LCP host, sync state to linux. + lipi = lcp_itf_pair_find_by_host (sw_if_index); + if (INDEX_INVALID == lipi) + return; + + lip = lcp_itf_pair_get (lipi); + if (lip->lip_namespace) + { + curr_ns_fd = clib_netns_open (NULL /* self */); + vif_ns_fd = clib_netns_open (lip->lip_namespace); + if (vif_ns_fd != -1) + clib_setns (vif_ns_fd); + } + + ctl_path = format (NULL, "/proc/sys/net/mpls/conf/%s/input%c", + lip->lip_host_name, NULL); + if (NULL == ctl_path) + { + LCP_IF_DBG ("mpls_sync_state_cb: failed to format sysctl"); + goto SYNC_CLEANUP; + } + + ctl_fd = open ((char *) ctl_path, O_WRONLY); + if (ctl_fd < 0) + { + LCP_IF_DBG ("mpls_sync_state_cb: failed to open %s for writing", + ctl_path); + goto SYNC_CLEANUP; + } + + if (fdformat (ctl_fd, "%u", is_enable) < 1) + { + LCP_IF_DBG ("mpls_sync_state_cb: failed to write to %s", ctl_path); + goto SYNC_CLEANUP; + } + + LCP_IF_DBG ("mpls_sync_state_cb: set mpls input for %s", lip->lip_host_name); + +SYNC_CLEANUP: + if (ctl_fd < 0) + close (ctl_fd); + + if (NULL != ctl_path) + vec_free (ctl_path); + + if (vif_ns_fd != -1) + close (vif_ns_fd); + + if (curr_ns_fd != -1) + { + clib_setns (curr_ns_fd); + close (curr_ns_fd); + } +} + +static clib_error_t * +lcp_mpls_sync_init (vlib_main_t *vm) +{ + lcp_itf_pair_vft_t mpls_sync_itf_pair_vft = { + .pair_add_fn = lcp_mpls_sync_pair_add_cb, + }; + lcp_itf_pair_register_vft (&mpls_sync_itf_pair_vft); + + mpls_interface_state_change_add_callback (lcp_mpls_sync_state_cb, 0); + + return NULL; +} + +VLIB_INIT_FUNCTION (lcp_mpls_sync_init) = { + .runs_after = VLIB_INITS ("lcp_itf_pair_init", "mpls_init"), +}; + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lcpng_netlink.h b/lcpng_netlink.h index c0efc2d..ab368af 100644 --- a/lcpng_netlink.h +++ b/lcpng_netlink.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/lcpng_nl_sync.c b/lcpng_nl_sync.c index 6496e24..0dcbfa1 100644 --- a/lcpng_nl_sync.c +++ b/lcpng_nl_sync.c @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -146,13 +147,31 @@ vnet_sw_interface_get_available_subid (vnet_main_t *vnm, u32 sw_if_index, return 1; } +static fib_protocol_t +lcp_nl_proto_k2f (uint32_t k) +{ + switch (k) + { + case AF_INET6: + return FIB_PROTOCOL_IP6; + case AF_INET: + return FIB_PROTOCOL_IP4; + case AF_MPLS: + return FIB_PROTOCOL_MPLS; + default: + ASSERT (0); + return FIB_PROTOCOL_NONE; + } +} + static fib_protocol_t lcp_nl_mk_addr46 (const struct nl_addr *rna, ip46_address_t *ia) { fib_protocol_t fproto; - fproto = - nl_addr_get_family (rna) == AF_INET6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4; + fproto = lcp_nl_proto_k2f (nl_addr_get_family (rna)); + ASSERT (FIB_PROTOCOL_MPLS != fproto); + ip46_address_reset (ia); if (FIB_PROTOCOL_IP4 == fproto) memcpy (&ia->ip4, nl_addr_get_binary_addr (rna), nl_addr_get_len (rna)); @@ -166,9 +185,31 @@ static void lcp_nl_mk_route_prefix (struct rtnl_route *r, fib_prefix_t *p) { const struct nl_addr *addr = rtnl_route_get_dst (r); + u32 *baddr = nl_addr_get_binary_addr (addr); + u32 blen = nl_addr_get_len (addr); + ip46_address_t *paddr = &p->fp_addr; + u32 entry; + + p->fp_proto = lcp_nl_proto_k2f (nl_addr_get_family (addr)); + + switch (p->fp_proto) + { + case FIB_PROTOCOL_MPLS: + entry = ntohl (*baddr); + p->fp_label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT; + p->fp_len = 21; + p->fp_eos = MPLS_NON_EOS; + return; + case FIB_PROTOCOL_IP4: + ip46_address_reset (paddr); + memcpy (&paddr->ip4, baddr, blen); + break; + case FIB_PROTOCOL_IP6: + memcpy (&paddr->ip6, baddr, blen); + break; + } p->fp_len = nl_addr_get_prefixlen (addr); - p->fp_proto = lcp_nl_mk_addr46 (addr, &p->fp_addr); } static void @@ -208,6 +249,37 @@ lcp_nl_mk_route_entry_flags (uint8_t rtype, int table_id, uint8_t rproto) return (fef); } +static int +lcp_router_mpls_nladdr_to_path (fib_route_path_t *path, struct nl_addr *addr) +{ + if (!addr) + return 0; + + struct mpls_label *stack = nl_addr_get_binary_addr (addr); + u32 entry, label; + u8 exp, ttl; + int label_count = 0; + + while (1) + { + entry = ntohl (stack[label_count++].entry); + label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT; + exp = (entry & MPLS_LS_TC_MASK) >> MPLS_LS_TC_SHIFT; + ttl = (entry & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT; + + fib_mpls_label_t fml = { + .fml_value = label, + .fml_exp = exp, + .fml_ttl = ttl, + }; + vec_add1 (path->frp_label_stack, fml); + + if (entry & MPLS_LS_S_MASK) + break; + } + return label_count; +} + static void lcp_nl_route_path_parse (struct rtnl_nexthop *rnh, void *arg) { @@ -216,6 +288,7 @@ lcp_nl_route_path_parse (struct rtnl_nexthop *rnh, void *arg) lcp_itf_pair_t *lip; fib_protocol_t fproto; struct nl_addr *addr; + int label_count = 0; /* We do not log a warning/error here, because some routes (like * blackhole/unreach) don't have an interface associated with them. @@ -230,9 +303,16 @@ lcp_nl_route_path_parse (struct rtnl_nexthop *rnh, void *arg) path->frp_flags = FIB_ROUTE_PATH_FLAG_NONE | ctx->type_flags; path->frp_sw_if_index = lip->lip_phy_sw_if_index; - path->frp_weight = rtnl_route_nh_get_weight (rnh); path->frp_preference = ctx->preference; + /* + * FIB Path Weight of 0 is meaningless and replaced with 1 further along. + * See fib_path_create. fib_path_cmp_w_route_path would fail to match + * such a fib_route_path_t with any fib_path_t, because a fib_path_t's + * fp_weight can never be 0. + */ + path->frp_weight = clib_max (1, rtnl_route_nh_get_weight (rnh)); + addr = rtnl_route_nh_get_gateway (rnh); if (!addr) addr = rtnl_route_nh_get_via (rnh); @@ -244,6 +324,32 @@ lcp_nl_route_path_parse (struct rtnl_nexthop *rnh, void *arg) path->frp_proto = fib_proto_to_dpo (fproto); + if (ctx->route_proto == FIB_PROTOCOL_MPLS) + { + addr = rtnl_route_nh_get_newdst (rnh); + label_count = lcp_router_mpls_nladdr_to_path (path, addr); + if (label_count) + { + LCP_NL_DBG ("router_path_parse: is label swap to %u", + path->frp_label_stack[0].fml_value); + } + else + { + fib_mpls_label_t fml = { + .fml_value = MPLS_LABEL_POP, + }; + vec_add1 (path->frp_label_stack, fml); + LCP_NL_DBG ("router_path_parse: is label pop"); + } + } + +#ifdef NL_CAPABILITY_VERSION_3_6_0 + addr = rtnl_route_nh_get_encap_mpls_dst (rnh); + label_count = lcp_router_mpls_nladdr_to_path (path, addr); + if (label_count) + LCP_NL_DBG ("router_path_parse: has encap mpls, %d labels", label_count); +#endif + if (ctx->is_mcast) path->frp_mitf_flags = MFIB_ITF_FLAG_FORWARD; @@ -439,11 +545,21 @@ lcp_nl_route_del (struct rtnl_route *rr) LCP_NL_DBG ("route_del: table %d prefix %U flags %U", rtnl_route_get_table (rr), format_fib_prefix, &pfx, format_fib_entry_flags, entry_flags); - if (pfx.fp_proto == FIB_PROTOCOL_IP6) - fib_table_entry_delete (nlt->nlt_fib_index, &pfx, fib_src); - else - fib_table_entry_path_remove2 (nlt->nlt_fib_index, &pfx, fib_src, - np.paths); + + switch (pfx.fp_proto) + { + case FIB_PROTOCOL_IP6: + fib_table_entry_delete (nlt->nlt_fib_index, &pfx, fib_src); + break; + case FIB_PROTOCOL_MPLS: + fib_table_entry_path_remove2 (nlt->nlt_fib_index, &pfx, fib_src, + np.paths); + /* delete the EOS route in addition to NEOS - fallthrough */ + pfx.fp_eos = MPLS_EOS; + default: + fib_table_entry_path_remove2 (nlt->nlt_fib_index, &pfx, fib_src, + np.paths); + } } vec_free (np.paths); @@ -451,6 +567,26 @@ lcp_nl_route_del (struct rtnl_route *rr) lcp_nl_table_unlock (nlt); } +static fib_route_path_t * +lcp_router_fib_route_path_dup (fib_route_path_t *old) +{ + int idx; + fib_route_path_t *p; + + fib_route_path_t *new = vec_dup (old); + if (!new) + return NULL; + + for (idx = 0; idx < vec_len (new); idx++) + { + p = &new[idx]; + if (p->frp_label_stack) + p->frp_label_stack = vec_dup (p->frp_label_stack); + } + + return new; +} + void lcp_nl_route_add (struct rtnl_route *rr, int is_replace) { @@ -536,6 +672,24 @@ lcp_nl_route_add (struct rtnl_route *rr, int is_replace) rtnl_route_get_table (rr), format_fib_prefix, &pfx, format_fib_entry_flags, entry_flags); + if (pfx.fp_proto == FIB_PROTOCOL_MPLS) + { + /* in order to avoid double-frees, we duplicate the paths. */ + fib_route_path_t *pathdup = + lcp_router_fib_route_path_dup (np.paths); + if (is_replace) + fib_table_entry_update (nlt->nlt_fib_index, &pfx, fib_src, + entry_flags, pathdup); + else + fib_table_entry_path_add2 (nlt->nlt_fib_index, &pfx, fib_src, + entry_flags, pathdup); + vec_free (pathdup); + + /* install EOS route in addition to NEOS */ + pfx.fp_eos = MPLS_EOS; + pfx.fp_payload_proto = np.paths[0].frp_proto; + } + if (is_replace) fib_table_entry_update (nlt->nlt_fib_index, &pfx, fib_src, entry_flags, np.paths);