Pim van Pelt
2023-05-31 13:14:18 +02:00
committed by GitHub
14 changed files with 613 additions and 180 deletions

View File

@ -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

12
lcpng.c
View File

@ -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;

10
lcpng.h
View File

@ -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

View File

@ -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);

View File

@ -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";
};
/*

View File

@ -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;

View File

@ -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 <sw_if_index>|<if-name> host-if <host-if-name> "
"netns <namespace> [tun]",
.function = lcp_itf_pair_create_command_fn,
VLIB_CLI_COMMAND (lcp_itf_pair_create_command, static) = {
.path = "lcp create",
.short_help = "lcp create <sw_if_index>|<if-name> host-if <host-if-name> "
"netns <namespace> [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 [<namespace>]",
.function = lcp_default_netns_command_fn,
VLIB_CLI_COMMAND (lcp_default_netns_command, static) = {
.path = "lcp default",
.short_help = "lcp default netns [<namespace>]",
.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 <sw_if_index>|<if-name>",
.function = lcp_itf_pair_delete_command_fn,
VLIB_CLI_COMMAND (lcp_itf_pair_delete_command, static) = {
.path = "lcp delete",
.short_help = "lcp delete <sw_if_index>|<if-name>",
.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 <interface>]",
.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 <interface>]",
.is_mp_safe = 1,
};
clib_error_t *

View File

@ -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,131 @@ 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
{
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
@ -557,14 +654,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 +678,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 +947,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 +1032,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"),
};
/*

View File

@ -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)

View File

@ -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",
@ -278,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.
*/
@ -304,10 +312,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 +351,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 +365,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);
@ -424,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);
@ -432,10 +445,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 +624,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 +783,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 +830,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 +912,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 +937,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 +1212,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);

140
lcpng_mpls_sync.c Normal file
View File

@ -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 <vnet/plugin/plugin.h>
#include <vnet/mpls/mpls.h>
#include <vppinfra/linux/netns.h>
#include <fcntl.h>
#include <plugins/lcpng/lcpng_interface.h>
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:
*/

View File

@ -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 "

View File

@ -22,6 +22,7 @@
#include <netlink/route/link.h>
#include <netlink/route/route.h>
#include <netlink/route/neighbour.h>
#include <netlink/route/nexthop.h>
#include <netlink/route/addr.h>
#include <netlink/route/link/vlan.h>

View File

@ -17,6 +17,7 @@
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/mpls.h>
#include <vnet/vnet.h>
#include <vnet/plugin/plugin.h>
@ -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)
{
@ -461,7 +597,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);
@ -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);