]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/netconf_netlink.c
zebra: evpn mh sync mac install as inactive
[mirror_frr.git] / zebra / netconf_netlink.c
index cc6a1201a5a4e4b4b9b921f9a24ba7d266d466f2..7352dfb2eec5f456f3bd2b3afcc7332a436d075d 100644 (file)
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * netconf_netlink.c - netconf interaction with the kernel using
  * netlink
  * Copyright (C) 2021  Nvidia, Inc.
  *                     Donald Sharp
- *
- * This file is part of FRR.
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING.  If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
  */
 #include <zebra.h>
 
@@ -29,6 +13,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"
@@ -46,7 +31,7 @@ static struct rtattr *netconf_rta(struct netconfmsg *ncm)
  * context, and enqueue for processing in the main zebra pthread.
  */
 static int
-netlink_netconf_dplane_update(ns_id_t ns_id, ifindex_t ifindex,
+netlink_netconf_dplane_update(ns_id_t ns_id, afi_t afi, ifindex_t ifindex,
                              enum dplane_netconf_status_e mpls_on,
                              enum dplane_netconf_status_e mcast_on,
                              enum dplane_netconf_status_e linkdown_on)
@@ -56,6 +41,7 @@ netlink_netconf_dplane_update(ns_id_t ns_id, ifindex_t ifindex,
        ctx = dplane_ctx_alloc();
        dplane_ctx_set_op(ctx, DPLANE_OP_INTF_NETCONFIG);
        dplane_ctx_set_ns_id(ctx, ns_id);
+       dplane_ctx_set_afi(ctx, afi);
        dplane_ctx_set_ifindex(ctx, ifindex);
 
        dplane_ctx_set_netconf_mpls(ctx, mpls_on);
@@ -78,6 +64,7 @@ int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        int len;
        ifindex_t ifindex;
        uint32_t ival;
+       afi_t afi;
        enum dplane_netconf_status_e mpls_on = DPLANE_NETCONF_STATUS_UNKNOWN;
        enum dplane_netconf_status_e mcast_on = DPLANE_NETCONF_STATUS_UNKNOWN;
        enum dplane_netconf_status_e linkdown_on =
@@ -96,6 +83,20 @@ int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 
        ncm = NLMSG_DATA(h);
 
+       /*
+        * FRR does not have an internal representation of afi_t for
+        * the MPLS Address Family that the kernel has.  So let's
+        * just call it v4.  This is ok because the kernel appears
+        * to do a good job of not sending data that is mixed/matched
+        * across families
+        */
+#ifdef AF_MPLS
+       if (ncm->ncm_family == AF_MPLS)
+               afi = AFI_IP;
+       else
+#endif /* AF_MPLS */
+               afi = family2afi(ncm->ncm_family);
+
        netlink_parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), len);
 
        if (!tb[NETCONFA_IFINDEX]) {
@@ -105,23 +106,6 @@ int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 
        ifindex = *(ifindex_t *)RTA_DATA(tb[NETCONFA_IFINDEX]);
 
-       switch (ifindex) {
-       case NETCONFA_IFINDEX_ALL:
-       case NETCONFA_IFINDEX_DEFAULT:
-               /*
-                * We need the ability to handle netlink messages intended
-                * for all and default interfaces.  I am not 100% sure
-                * what that is yet, or where we would store it.
-                */
-               if (IS_ZEBRA_DEBUG_KERNEL)
-                       zlog_debug("%s: Ignoring global ifindex %d",
-                                  __func__, ifindex);
-
-               return 0;
-       default:
-               break;
-       }
-
        if (tb[NETCONFA_INPUT]) {
                ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_INPUT]);
                if (ival != 0)
@@ -153,7 +137,7 @@ int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        __func__, ifindex, mpls_on, mcast_on, linkdown_on);
 
        /* Create a dplane context and pass it along for processing */
-       netlink_netconf_dplane_update(ns_id, ifindex, mpls_on, mcast_on,
+       netlink_netconf_dplane_update(ns_id, afi, ifindex, mpls_on, mcast_on,
                                      linkdown_on);
 
        return 0;
@@ -188,4 +172,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 */