zebra: Add a mpls enable interface node command

Allow individual interfaces to turn on/off the mpls subsystem
for it in linux.

sharpd@eva:~/frr9$ sudo sysctl -a | grep enp39s0 | grep mpls
net.mpls.conf.enp39s0.input = 0
sharpd@eva:~/frr9$ vtysh -c "conf" -c "int enp39s0" -c "mpls enable"
sharpd@eva:~/frr9$ sudo sysctl -a | grep enp39s0 | grep mpls
net.mpls.conf.enp39s0.input = 1
sharpd@eva:~/frr9$ vtysh -c "conf" -c "int enp39s0" -c "no mpls enable"
sharpd@eva:~/frr9$ sudo sysctl -a | grep enp39s0 | grep mpls
net.mpls.conf.enp39s0.input = 0
sharpd@eva:~/frr9$

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
This commit is contained in:
Donald Sharp 2022-06-29 07:43:50 -04:00
parent c87f5c2392
commit 39ffa8e8e8
10 changed files with 178 additions and 4 deletions

View file

@ -155,6 +155,13 @@ Standard Commands
Set description for the interface.
.. clicmd:: mpls enable
Enable or disable mpls kernel processing on the interface, for linux. Interfaces
configured with mpls will not automatically turn on if mpls kernel modules do not
happen to be loaded. This command will fail on 3.X linux kernels and does not
work on non-linux systems at all.
.. clicmd:: multicast

View file

@ -38,4 +38,15 @@ enum zebra_dplane_result kernel_intf_update(struct zebra_dplane_ctx *ctx)
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
enum zebra_dplane_result
kernel_intf_netconf_update(struct zebra_dplane_ctx *ctx)
{
const char *ifname = dplane_ctx_get_ifname(ctx);
enum dplane_netconf_status_e mpls_on = dplane_ctx_get_netconf_mpls(ctx);
zlog_warn("%s: Unable to set kernel mpls state for interface %s(%d)",
__func__, ifname, mpls_on);
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
#endif

View file

@ -2937,6 +2937,27 @@ DEFUN (multicast,
return CMD_SUCCESS;
}
DEFPY (mpls,
mpls_cmd,
"[no] mpls enable",
NO_STR
MPLS_STR
"Set mpls to be on for the interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct zebra_if *if_data = ifp->info;
if (no) {
dplane_intf_mpls_modify_state(ifp, false);
if_data->mpls = IF_ZEBRA_DATA_UNSPEC;
} else {
dplane_intf_mpls_modify_state(ifp, true);
if_data->mpls = IF_ZEBRA_DATA_ON;
}
return CMD_SUCCESS;
}
int if_multicast_unset(struct interface *ifp)
{
struct zebra_if *if_data;
@ -4581,6 +4602,8 @@ static int if_config_write(struct vty *vty)
IF_ZEBRA_DATA_ON
? ""
: "no ");
if (if_data->mpls == IF_ZEBRA_DATA_ON)
vty_out(vty, " mpls\n");
}
hook_call(zebra_if_config_wr, vty, ifp);
@ -4617,6 +4640,7 @@ void zebra_if_init(void)
install_element(ENABLE_NODE, &show_interface_desc_vrf_all_cmd);
install_element(INTERFACE_NODE, &multicast_cmd);
install_element(INTERFACE_NODE, &no_multicast_cmd);
install_element(INTERFACE_NODE, &mpls_cmd);
install_element(INTERFACE_NODE, &linkdetect_cmd);
install_element(INTERFACE_NODE, &no_linkdetect_cmd);
install_element(INTERFACE_NODE, &shutdown_if_cmd);

View file

@ -1613,10 +1613,12 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth,
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
case DPLANE_OP_INTF_NETCONFIG:
case DPLANE_OP_NONE:
return FRR_NETLINK_ERROR;
case DPLANE_OP_INTF_NETCONFIG:
return netlink_put_intf_netconfig(bth, ctx);
case DPLANE_OP_INTF_INSTALL:
case DPLANE_OP_INTF_UPDATE:
case DPLANE_OP_INTF_DELETE:

View file

@ -1529,7 +1529,7 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list)
{
struct zebra_dplane_ctx *ctx;
struct dplane_ctx_q handled_list;
enum zebra_dplane_result res;
enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS;
TAILQ_INIT(&handled_list);
@ -1611,9 +1611,27 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list)
res = ZEBRA_DPLANE_REQUEST_SUCCESS;
break;
default:
res = ZEBRA_DPLANE_REQUEST_FAILURE;
case DPLANE_OP_INTF_NETCONFIG:
res = kernel_intf_netconf_update(ctx);
break;
case DPLANE_OP_NONE:
case DPLANE_OP_BR_PORT_UPDATE:
case DPLANE_OP_IPTABLE_ADD:
case DPLANE_OP_IPTABLE_DELETE:
case DPLANE_OP_IPSET_ADD:
case DPLANE_OP_IPSET_DELETE:
case DPLANE_OP_IPSET_ENTRY_ADD:
case DPLANE_OP_IPSET_ENTRY_DELETE:
case DPLANE_OP_NEIGH_IP_INSTALL:
case DPLANE_OP_NEIGH_IP_DELETE:
case DPLANE_OP_NEIGH_TABLE_UPDATE:
case DPLANE_OP_GRE_SET:
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
zlog_err("Unhandled dplane data for %s",
dplane_op2str(dplane_ctx_get_op(ctx)));
res = ZEBRA_DPLANE_REQUEST_FAILURE;
}
skip_one:

View file

@ -29,6 +29,7 @@
#include "linux/netconf.h"
#include "lib/lib_errors.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_dplane.h"
#include "zebra/kernel_netlink.h"
@ -185,4 +186,56 @@ int netlink_request_netconf(int sockfd)
return netlink_request(nls, &req);
}
extern struct zebra_privs_t zserv_privs;
/*
* Currently netconf has no ability to set from netlink.
* So we've received a request to do this work in the data plane.
* as such we need to set the value via the /proc system
*/
enum netlink_msg_status netlink_put_intf_netconfig(struct nl_batch *bth,
struct zebra_dplane_ctx *ctx)
{
const char *ifname = dplane_ctx_get_ifname(ctx);
enum dplane_netconf_status_e mpls_on = dplane_ctx_get_netconf_mpls(ctx);
char set[64];
char mpls_proc[PATH_MAX];
int fd, ret = FRR_NETLINK_ERROR;
snprintf(mpls_proc, sizeof(mpls_proc),
"/proc/sys/net/mpls/conf/%s/input", ifname);
if (mpls_on == DPLANE_NETCONF_STATUS_ENABLED)
snprintf(set, sizeof(set), "1\n");
else if (mpls_on == DPLANE_NETCONF_STATUS_DISABLED)
snprintf(set, sizeof(set), "0\n");
else {
flog_err_sys(
EC_LIB_DEVELOPMENT,
"%s: Expected interface %s to be set to ENABLED or DISABLED was %d",
__func__, ifname, mpls_on);
return ret;
}
frr_with_privs (&zserv_privs) {
fd = open(mpls_proc, O_WRONLY);
if (fd < 0) {
flog_err_sys(
EC_LIB_SOCKET,
"%s: Unable to open %s for writing: %s(%d)",
__func__, mpls_proc, safe_strerror(errno),
errno);
return ret;
}
if (write(fd, set, 2) == 2)
ret = FRR_NETLINK_SUCCESS;
else
flog_err_sys(EC_LIB_SOCKET,
"%s: Unsuccessful write to %s: %s(%d)",
__func__, mpls_proc, safe_strerror(errno),
errno);
close(fd);
}
return ret;
}
#endif /* HAVE_NETLINK */

View file

@ -38,6 +38,10 @@ extern int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id,
/* Request info from the host OS. */
int netlink_request_netconf(int sockfd);
struct nl_batch;
extern enum netlink_msg_status
netlink_put_intf_netconfig(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
#ifdef __cplusplus
}

View file

@ -69,6 +69,9 @@ kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx);
extern enum zebra_dplane_result
kernel_intf_update(struct zebra_dplane_ctx *ctx);
extern enum zebra_dplane_result
kernel_intf_netconf_update(struct zebra_dplane_ctx *ctx);
#endif /* !HAVE_NETLINK */
extern int kernel_neigh_update(int cmd, int ifindex, void *addr, char *lla,

View file

@ -509,6 +509,8 @@ static struct zebra_dplane_globals {
_Atomic uint32_t dg_intf_addrs_in;
_Atomic uint32_t dg_intf_addr_errors;
_Atomic uint32_t dg_intf_changes;
_Atomic uint32_t dg_intf_changes_errors;
_Atomic uint32_t dg_macs_in;
_Atomic uint32_t dg_mac_errors;
@ -3913,6 +3915,47 @@ dplane_br_port_update(const struct interface *ifp, bool non_df,
return result;
}
enum zebra_dplane_result
dplane_intf_mpls_modify_state(const struct interface *ifp, bool set)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
struct zebra_dplane_ctx *ctx;
struct zebra_ns *zns;
int ret = EINVAL;
ctx = dplane_ctx_alloc();
ctx->zd_op = DPLANE_OP_INTF_NETCONFIG;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
ctx->zd_vrf_id = ifp->vrf->vrf_id;
strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
zns = zebra_ns_lookup(ifp->vrf->vrf_id);
dplane_ctx_ns_init(ctx, zns, false);
ctx->zd_ifindex = ifp->ifindex;
if (set)
dplane_ctx_set_netconf_mpls(ctx, DPLANE_NETCONF_STATUS_ENABLED);
else
dplane_ctx_set_netconf_mpls(ctx,
DPLANE_NETCONF_STATUS_DISABLED);
/* Increment counter */
atomic_fetch_add_explicit(&zdplane_info.dg_intf_changes, 1,
memory_order_relaxed);
ret = dplane_update_enqueue(ctx);
if (ret == AOK)
result = ZEBRA_DPLANE_REQUEST_QUEUED;
else {
/* Error counter */
atomic_fetch_add_explicit(&zdplane_info.dg_intf_changes_errors,
1, memory_order_relaxed);
dplane_ctx_free(&ctx);
}
return result;
}
/*
* Enqueue interface address add for the dataplane.
*/
@ -4900,6 +4943,13 @@ int dplane_show_helper(struct vty *vty, bool detailed)
vty_out(vty, "Intf addr updates: %"PRIu64"\n", incoming);
vty_out(vty, "Intf addr errors: %"PRIu64"\n", errs);
incoming = atomic_load_explicit(&zdplane_info.dg_intf_changes,
memory_order_relaxed);
errs = atomic_load_explicit(&zdplane_info.dg_intf_changes_errors,
memory_order_relaxed);
vty_out(vty, "Intf change updates: %" PRIu64 "\n", incoming);
vty_out(vty, "Intf change errors: %" PRIu64 "\n", errs);
incoming = atomic_load_explicit(&zdplane_info.dg_macs_in,
memory_order_relaxed);
errs = atomic_load_explicit(&zdplane_info.dg_mac_errors,

View file

@ -690,6 +690,8 @@ enum zebra_dplane_result dplane_lsp_notif_update(struct zebra_lsp *lsp,
enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw);
enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw);
enum zebra_dplane_result
dplane_intf_mpls_modify_state(const struct interface *ifp, const bool set);
/*
* Enqueue interface address changes for the dataplane.
*/