]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: Add a `mpls enable` interface node command
authorDonald Sharp <sharpd@nvidia.com>
Wed, 29 Jun 2022 11:43:50 +0000 (07:43 -0400)
committerDonald Sharp <sharpd@nvidia.com>
Mon, 8 Aug 2022 13:15:22 +0000 (09:15 -0400)
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>
doc/user/zebra.rst
zebra/if_socket.c
zebra/interface.c
zebra/kernel_netlink.c
zebra/kernel_socket.c
zebra/netconf_netlink.c
zebra/netconf_netlink.h
zebra/rt.h
zebra/zebra_dplane.c
zebra/zebra_dplane.h

index d96df0ce522901215687cb4cd4b66ff751419617..05990e2523d1f3be77c0414d5460ea2110d07ce3 100644 (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
 
 
index 309d5a3f3e2091198401b0a2357a07c5c2c753d9..da9fadf7c7e3665dbfdbdccddad668ce7f9d0180 100644 (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
index b1f59a4e4f9a79f4ef30420c9d307d1ca683931a..b7a984e44dc003308d6a69d33302c769ea02a6e4 100644 (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);
index 5c8aca96917274bcf068fc720b73ad10cf02a143..396ccb34bdbbcd3a1b0cc626d14206a4a3719e72 100644 (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:
index 2741a2324230057ce072fe1a253157c7dc85b7f5..076e9c4dfab1204571d6bab6db32bc0f23a8ec66 100644 (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:
index f9cb37a3cf7dd691b2a73f8d8c872b26a95c9b60..56f56bfe669d2df7d89855fe56ec5a5acf463021 100644 (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 */
index 3f2e7af7685326271dd5c3688e13cbcfc400129e..1b3450bcb5f774a80ca89571cec54955eeacd426 100644 (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
 }
index 4952c3eb1a21dae117a991898a9715ebc416f222..0a86a2897cb8086e3c0e28b3ffba7cbc206e2dcc 100644 (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,
index a4330a3200cb93c7330039240c79d85750128327..4c7838198e3764b87348a91ebe323223e4244077 100644 (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,
index d940bd9568e38f3481fe43125f75cf29ee059e7b..c96ea400946aa7889121a714abace8f877e60cc1 100644 (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.
  */