Merge pull request #7 from vifino/mpls
Basic MPLS support! See the following references: https://ipng.ch/s/articles/2023/05/07/vpp-mpls-1.html https://ipng.ch/s/articles/2023/05/17/vpp-mpls-2.html https://ipng.ch/s/articles/2023/05/21/vpp-mpls-3.html https://ipng.ch/s/articles/2023/05/28/vpp-mpls-4.html And contact vpp-dev@lists.fd.io for support.
This commit is contained in:
@ -29,6 +29,7 @@ add_vpp_library(lcpng
|
|||||||
lcpng_interface.c
|
lcpng_interface.c
|
||||||
lcpng_adj.c
|
lcpng_adj.c
|
||||||
lcpng_if_sync.c
|
lcpng_if_sync.c
|
||||||
|
lcpng_mpls_sync.c
|
||||||
lcpng.c
|
lcpng.c
|
||||||
|
|
||||||
LINK_LIBRARIES
|
LINK_LIBRARIES
|
||||||
|
12
lcpng.c
12
lcpng.c
@ -23,7 +23,9 @@
|
|||||||
|
|
||||||
lcp_main_t lcp_main;
|
lcp_main_t lcp_main;
|
||||||
|
|
||||||
u8 *lcp_get_default_ns(void) {
|
u8 *
|
||||||
|
lcp_get_default_ns (void)
|
||||||
|
{
|
||||||
lcp_main_t *lcpm = &lcp_main;
|
lcp_main_t *lcpm = &lcp_main;
|
||||||
|
|
||||||
if (!lcpm->default_namespace || lcpm->default_namespace[0] == 0)
|
if (!lcpm->default_namespace || lcpm->default_namespace[0] == 0)
|
||||||
@ -31,7 +33,9 @@ u8 *lcp_get_default_ns(void) {
|
|||||||
return lcpm->default_namespace;
|
return lcpm->default_namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lcp_get_default_ns_fd(void) {
|
int
|
||||||
|
lcp_get_default_ns_fd (void)
|
||||||
|
{
|
||||||
lcp_main_t *lcpm = &lcp_main;
|
lcp_main_t *lcpm = &lcp_main;
|
||||||
|
|
||||||
return lcpm->default_ns_fd;
|
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.
|
* 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;
|
lcp_main_t *lcpm = &lcp_main;
|
||||||
char *p;
|
char *p;
|
||||||
int len;
|
int len;
|
||||||
|
25
lcpng_if.api
25
lcpng_if.api
@ -134,9 +134,10 @@ autoendian define lcp_itf_pair_details
|
|||||||
string netns[32]; /* LCP_NS_LEN */
|
string netns[32]; /* LCP_NS_LEN */
|
||||||
};
|
};
|
||||||
|
|
||||||
service {
|
service
|
||||||
rpc lcp_itf_pair_get returns lcp_itf_pair_get_reply
|
{
|
||||||
stream lcp_itf_pair_details;
|
rpc lcp_itf_pair_get returns lcp_itf_pair_get_reply stream
|
||||||
|
lcp_itf_pair_details;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Replace end/begin
|
/** \brief Replace end/begin
|
||||||
@ -155,14 +156,17 @@ autoreply define lcp_itf_pair_replace_end
|
|||||||
/*
|
/*
|
||||||
* Linux-CP Error counters/messages
|
* Linux-CP Error counters/messages
|
||||||
*/
|
*/
|
||||||
counters linuxcp {
|
counters linuxcp
|
||||||
packets {
|
{
|
||||||
|
packets
|
||||||
|
{
|
||||||
severity info;
|
severity info;
|
||||||
type counter64;
|
type counter64;
|
||||||
units "packets";
|
units "packets";
|
||||||
description "ARP packets processed";
|
description "ARP packets processed";
|
||||||
};
|
};
|
||||||
copies {
|
copies
|
||||||
|
{
|
||||||
severity info;
|
severity info;
|
||||||
type counter64;
|
type counter64;
|
||||||
units "packets";
|
units "packets";
|
||||||
@ -170,9 +174,12 @@ counters linuxcp {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
paths {
|
paths
|
||||||
"/err/linux-cp-arp-phy" "linuxcp";
|
{
|
||||||
"/err/linux-cp-arp-host" "linuxcp";
|
"/err/linux-cp-arp-phy"
|
||||||
|
"linuxcp";
|
||||||
|
"/err/linux-cp-arp-host"
|
||||||
|
"linuxcp";
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -162,7 +162,8 @@ vl_api_lcp_itf_pair_get_t_handler (vl_api_lcp_itf_pair_get_t *mp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
vl_api_lcp_default_ns_set_reply_t *rmp;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
@ -173,7 +174,8 @@ vl_api_lcp_default_ns_set_t_handler(vl_api_lcp_default_ns_set_t *mp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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_lcp_default_ns_get_reply_t *rmp;
|
||||||
vl_api_registration_t *reg;
|
vl_api_registration_t *reg;
|
||||||
char *ns;
|
char *ns;
|
||||||
|
@ -173,9 +173,10 @@ VLIB_CLI_COMMAND (lcp_auto_subint_command, static) = {
|
|||||||
.function = lcp_auto_subint_command_fn,
|
.function = lcp_auto_subint_command_fn,
|
||||||
};
|
};
|
||||||
|
|
||||||
static clib_error_t *lcp_default_netns_command_fn(vlib_main_t *vm,
|
static clib_error_t *
|
||||||
unformat_input_t *input,
|
lcp_default_netns_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||||
vlib_cli_command_t *cmd) {
|
vlib_cli_command_t *cmd)
|
||||||
|
{
|
||||||
unformat_input_t _line_input, *line_input = &_line_input;
|
unformat_input_t _line_input, *line_input = &_line_input;
|
||||||
u8 *ns;
|
u8 *ns;
|
||||||
int r;
|
int r;
|
||||||
@ -186,7 +187,8 @@ static clib_error_t *lcp_default_netns_command_fn(vlib_main_t *vm,
|
|||||||
|
|
||||||
ns = 0;
|
ns = 0;
|
||||||
|
|
||||||
while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) {
|
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
|
||||||
|
{
|
||||||
if (unformat (line_input, "netns %s", &ns))
|
if (unformat (line_input, "netns %s", &ns))
|
||||||
;
|
;
|
||||||
else if (unformat (line_input, "clear netns"))
|
else if (unformat (line_input, "clear netns"))
|
||||||
|
@ -438,6 +438,103 @@ VNET_FEATURE_INIT(lcp_xc_ip6_mcast_node, static) = {
|
|||||||
.node_name = "linux-cp-xc-ip6",
|
.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
|
typedef enum
|
||||||
{
|
{
|
||||||
LCP_XC_L3_NEXT_XC,
|
LCP_XC_L3_NEXT_XC,
|
||||||
|
@ -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
|
// Sync interface state changes into host
|
||||||
lip = lcp_itf_pair_get (lcp_itf_pair_find_by_phy (sw_if_index));
|
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,
|
LCP_IF_INFO ("admin_state_change: %U flags %u", format_lcp_itf_pair, lip,
|
||||||
flags);
|
flags);
|
||||||
|
|
||||||
|
@ -149,8 +149,10 @@ lcp_itf_pair_show (u32 phy_sw_if_index)
|
|||||||
lcp_itf_pair_t *
|
lcp_itf_pair_t *
|
||||||
lcp_itf_pair_get (u32 index)
|
lcp_itf_pair_get (u32 index)
|
||||||
{
|
{
|
||||||
if (!lcp_itf_pair_pool) return NULL;
|
if (!lcp_itf_pair_pool)
|
||||||
if (index == INDEX_INVALID) return NULL;
|
return NULL;
|
||||||
|
if (index == INDEX_INVALID)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return pool_elt_at_index (lcp_itf_pair_pool, index);
|
return pool_elt_at_index (lcp_itf_pair_pool, index);
|
||||||
}
|
}
|
||||||
@ -230,12 +232,14 @@ lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name,
|
|||||||
if (lipi != INDEX_INVALID)
|
if (lipi != INDEX_INVALID)
|
||||||
return VNET_API_ERROR_VALUE_EXIST;
|
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");
|
LCP_IF_ERROR ("pair_add: Cannot add LIP - invalid host");
|
||||||
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
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");
|
LCP_IF_ERROR ("pair_add: Cannot add LIP - invalid phy");
|
||||||
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
||||||
}
|
}
|
||||||
@ -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],
|
lcp_itf_l3_feat_names[lip->lip_host_type][af],
|
||||||
lip->lip_host_sw_if_index, 1, NULL, 0);
|
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.
|
* Configure passive punt to the host interface.
|
||||||
*/
|
*/
|
||||||
@ -343,7 +351,8 @@ lcp_netlink_add_link_vlan (int parent, u32 vlan, u16 proto, const char *name)
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
sk = nl_socket_alloc ();
|
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",
|
LCP_IF_ERROR ("netlink_add_link_vlan: Netlink connect error: %s",
|
||||||
nl_geterror (err));
|
nl_geterror (err));
|
||||||
return clib_error_return (NULL, "Unable to connect socket: %d", err);
|
return clib_error_return (NULL, "Unable to connect socket: %d", err);
|
||||||
@ -356,7 +365,8 @@ 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_id (link, vlan);
|
||||||
rtnl_link_vlan_set_protocol (link, htons (proto));
|
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",
|
LCP_IF_ERROR ("netlink_add_link_vlan: Netlink link add error: %s",
|
||||||
nl_geterror (err));
|
nl_geterror (err));
|
||||||
return clib_error_return (NULL, "Unable to add link %s: %d", name, err);
|
return clib_error_return (NULL, "Unable to add link %s: %d", name, err);
|
||||||
@ -424,6 +434,9 @@ lcp_itf_pair_del (u32 phy_sw_if_index)
|
|||||||
lcp_itf_l3_feat_names[lip->lip_host_type][af],
|
lcp_itf_l3_feat_names[lip->lip_host_type][af],
|
||||||
lip->lip_host_sw_if_index, 0, NULL, 0);
|
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);
|
lcp_itf_unset_adjs (lip);
|
||||||
|
|
||||||
ip4_punt_redirect_del (lip->lip_phy_sw_if_index);
|
ip4_punt_redirect_del (lip->lip_phy_sw_if_index);
|
||||||
@ -611,7 +624,8 @@ lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state)
|
|||||||
vnet_main_t *vnm = vnet_get_main ();
|
vnet_main_t *vnm = vnet_get_main ();
|
||||||
int curr_ns_fd, vif_ns_fd;
|
int curr_ns_fd, vif_ns_fd;
|
||||||
|
|
||||||
if (!lip) return;
|
if (!lip)
|
||||||
|
return;
|
||||||
|
|
||||||
curr_ns_fd = vif_ns_fd = -1;
|
curr_ns_fd = vif_ns_fd = -1;
|
||||||
|
|
||||||
@ -769,12 +783,14 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
|
|||||||
const vnet_hw_interface_t *hw;
|
const vnet_hw_interface_t *hw;
|
||||||
lcp_itf_pair_t *lip;
|
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);
|
LCP_IF_ERROR ("pair_create: Invalid phy index %u", phy_sw_if_index);
|
||||||
return VNET_API_ERROR_INVALID_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);
|
LCP_IF_ERROR ("pair_create: Invalid host-if-name '%s'", host_if_name);
|
||||||
return VNET_API_ERROR_INVALID_ARGUMENT;
|
return VNET_API_ERROR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
@ -782,13 +798,15 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
|
|||||||
vnm = vnet_get_main ();
|
vnm = vnet_get_main ();
|
||||||
sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
|
sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
|
||||||
hw = vnet_get_sup_hw_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");
|
LCP_IF_ERROR ("pair_create: Invalid interface");
|
||||||
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hw->hw_class_index != ethernet_hw_interface_class.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 (
|
LCP_IF_ERROR (
|
||||||
"pair_create: don't create TAP for non-eth interface; use tun");
|
"pair_create: don't create TAP for non-eth interface; use tun");
|
||||||
return VNET_API_ERROR_INVALID_ARGUMENT;
|
return VNET_API_ERROR_INVALID_ARGUMENT;
|
||||||
@ -812,7 +830,9 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
|
|||||||
u16 vlan, proto;
|
u16 vlan, proto;
|
||||||
u32 parent_vif_index;
|
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 "
|
LCP_IF_ERROR ("pair_create: Cannot create LIP for a "
|
||||||
"sub-interface without exact-match set");
|
"sub-interface without exact-match set");
|
||||||
return VNET_API_ERROR_INVALID_ARGUMENT;
|
return VNET_API_ERROR_INVALID_ARGUMENT;
|
||||||
@ -821,7 +841,8 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
|
|||||||
outer_vlan = sw->sub.eth.outer_vlan_id;
|
outer_vlan = sw->sub.eth.outer_vlan_id;
|
||||||
inner_vlan = sw->sub.eth.inner_vlan_id;
|
inner_vlan = sw->sub.eth.inner_vlan_id;
|
||||||
outer_proto = inner_proto = ETH_P_8021Q;
|
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",
|
LCP_IF_INFO ("pair_create: creating dot1%s %d inner-dot1q %d on %U",
|
||||||
sw->sub.eth.flags.dot1ad ? "ad" : "q", outer_vlan,
|
sw->sub.eth.flags.dot1ad ? "ad" : "q", outer_vlan,
|
||||||
@ -916,7 +937,8 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
|
|||||||
|
|
||||||
err = lcp_netlink_add_link_vlan (parent_vif_index, vlan, proto,
|
err = lcp_netlink_add_link_vlan (parent_vif_index, vlan, proto,
|
||||||
(const char *) host_if_name);
|
(const char *) host_if_name);
|
||||||
if (err != 0) {
|
if (err != 0)
|
||||||
|
{
|
||||||
LCP_IF_ERROR ("pair_create: Cannot create link "
|
LCP_IF_ERROR ("pair_create: Cannot create link "
|
||||||
"outer(proto:0x%04x,vlan:%u).inner(proto:0x%"
|
"outer(proto:0x%04x,vlan:%u).inner(proto:0x%"
|
||||||
"04x,vlan:%u) name:'%s'",
|
"04x,vlan:%u) name:'%s'",
|
||||||
|
140
lcpng_mpls_sync.c
Normal file
140
lcpng_mpls_sync.c
Normal 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:
|
||||||
|
*/
|
@ -22,6 +22,7 @@
|
|||||||
#include <netlink/route/link.h>
|
#include <netlink/route/link.h>
|
||||||
#include <netlink/route/route.h>
|
#include <netlink/route/route.h>
|
||||||
#include <netlink/route/neighbour.h>
|
#include <netlink/route/neighbour.h>
|
||||||
|
#include <netlink/route/nexthop.h>
|
||||||
#include <netlink/route/addr.h>
|
#include <netlink/route/addr.h>
|
||||||
#include <netlink/route/link/vlan.h>
|
#include <netlink/route/link/vlan.h>
|
||||||
|
|
||||||
|
166
lcpng_nl_sync.c
166
lcpng_nl_sync.c
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
|
#include <linux/mpls.h>
|
||||||
|
|
||||||
#include <vnet/vnet.h>
|
#include <vnet/vnet.h>
|
||||||
#include <vnet/plugin/plugin.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;
|
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
|
static fib_protocol_t
|
||||||
lcp_nl_mk_addr46 (const struct nl_addr *rna, ip46_address_t *ia)
|
lcp_nl_mk_addr46 (const struct nl_addr *rna, ip46_address_t *ia)
|
||||||
{
|
{
|
||||||
fib_protocol_t fproto;
|
fib_protocol_t fproto;
|
||||||
|
|
||||||
fproto =
|
fproto = lcp_nl_proto_k2f (nl_addr_get_family (rna));
|
||||||
nl_addr_get_family (rna) == AF_INET6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4;
|
ASSERT (FIB_PROTOCOL_MPLS != fproto);
|
||||||
|
|
||||||
ip46_address_reset (ia);
|
ip46_address_reset (ia);
|
||||||
if (FIB_PROTOCOL_IP4 == fproto)
|
if (FIB_PROTOCOL_IP4 == fproto)
|
||||||
memcpy (&ia->ip4, nl_addr_get_binary_addr (rna), nl_addr_get_len (rna));
|
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)
|
lcp_nl_mk_route_prefix (struct rtnl_route *r, fib_prefix_t *p)
|
||||||
{
|
{
|
||||||
const struct nl_addr *addr = rtnl_route_get_dst (r);
|
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_len = nl_addr_get_prefixlen (addr);
|
||||||
p->fp_proto = lcp_nl_mk_addr46 (addr, &p->fp_addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -208,6 +249,37 @@ lcp_nl_mk_route_entry_flags (uint8_t rtype, int table_id, uint8_t rproto)
|
|||||||
return (fef);
|
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
|
static void
|
||||||
lcp_nl_route_path_parse (struct rtnl_nexthop *rnh, void *arg)
|
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;
|
lcp_itf_pair_t *lip;
|
||||||
fib_protocol_t fproto;
|
fib_protocol_t fproto;
|
||||||
struct nl_addr *addr;
|
struct nl_addr *addr;
|
||||||
|
int label_count = 0;
|
||||||
|
|
||||||
/* We do not log a warning/error here, because some routes (like
|
/* We do not log a warning/error here, because some routes (like
|
||||||
* blackhole/unreach) don't have an interface associated with them.
|
* 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_flags = FIB_ROUTE_PATH_FLAG_NONE | ctx->type_flags;
|
||||||
path->frp_sw_if_index = lip->lip_phy_sw_if_index;
|
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;
|
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);
|
addr = rtnl_route_nh_get_gateway (rnh);
|
||||||
if (!addr)
|
if (!addr)
|
||||||
addr = rtnl_route_nh_get_via (rnh);
|
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);
|
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)
|
if (ctx->is_mcast)
|
||||||
path->frp_mitf_flags = MFIB_ITF_FLAG_FORWARD;
|
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",
|
LCP_NL_DBG ("route_del: table %d prefix %U flags %U",
|
||||||
rtnl_route_get_table (rr), format_fib_prefix, &pfx,
|
rtnl_route_get_table (rr), format_fib_prefix, &pfx,
|
||||||
format_fib_entry_flags, entry_flags);
|
format_fib_entry_flags, entry_flags);
|
||||||
if (pfx.fp_proto == FIB_PROTOCOL_IP6)
|
|
||||||
|
switch (pfx.fp_proto)
|
||||||
|
{
|
||||||
|
case FIB_PROTOCOL_IP6:
|
||||||
fib_table_entry_delete (nlt->nlt_fib_index, &pfx, fib_src);
|
fib_table_entry_delete (nlt->nlt_fib_index, &pfx, fib_src);
|
||||||
else
|
break;
|
||||||
|
case FIB_PROTOCOL_MPLS:
|
||||||
fib_table_entry_path_remove2 (nlt->nlt_fib_index, &pfx, fib_src,
|
fib_table_entry_path_remove2 (nlt->nlt_fib_index, &pfx, fib_src,
|
||||||
np.paths);
|
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);
|
vec_free (np.paths);
|
||||||
@ -451,6 +567,26 @@ lcp_nl_route_del (struct rtnl_route *rr)
|
|||||||
lcp_nl_table_unlock (nlt);
|
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
|
void
|
||||||
lcp_nl_route_add (struct rtnl_route *rr, int is_replace)
|
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,
|
rtnl_route_get_table (rr), format_fib_prefix, &pfx,
|
||||||
format_fib_entry_flags, entry_flags);
|
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)
|
if (is_replace)
|
||||||
fib_table_entry_update (nlt->nlt_fib_index, &pfx, fib_src,
|
fib_table_entry_update (nlt->nlt_fib_index, &pfx, fib_src,
|
||||||
entry_flags, np.paths);
|
entry_flags, np.paths);
|
||||||
|
Reference in New Issue
Block a user