]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: Add Generic Netlink socket
authorCarmine Scarpitta <carmine.scarpitta@uniroma2.it>
Wed, 16 Nov 2022 23:15:40 +0000 (00:15 +0100)
committerCarmine Scarpitta <cscarpit@cisco.com>
Thu, 14 Dec 2023 13:56:44 +0000 (14:56 +0100)
zebra already supports several Netlink sockets which allow it to
communicate with the kernel. Each Netlink socket has a specific purpose:
we have a socket for incoming events from the kernel, a socket for
programming the dataplane, a socket for the kernel messages, a socket
used as the command channel. All the currently supported sockets are
based on the `NETLINK_ROUTE` protocol.

This commit adds a new Netlink socket that allows zebra to send
commands to the kernel using the `Generic Netlink` protocol.

Signed-off-by: Carmine Scarpitta <carmine.scarpitta@uniroma2.it>
zebra/kernel_netlink.c
zebra/kernel_netlink.h
zebra/zebra_ns.h

index bc284b8b66ec595cf0214762c8160d1523abf1a3..424794135de6e0fcba339ce55163f3cf2b891f3a 100644 (file)
@@ -316,9 +316,6 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups,
        int sock;
        int namelen;
 
-       if (nl_family != NETLINK_ROUTE)
-               return -1;
-
        frr_with_privs(&zserv_privs) {
                sock = ns_socket(AF_NETLINK, SOCK_RAW, nl_family, ns_id);
                if (sock < 0) {
@@ -1230,6 +1227,33 @@ int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
        return netlink_talk_info(filter, n, &dp_info, startup);
 }
 
+/*
+ * Synchronous version of netlink_talk_info. Converts args to suit the
+ * common version, which is suitable for both sync and async use.
+ */
+int ge_netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
+                   struct nlmsghdr *n, struct zebra_ns *zns, bool startup)
+{
+       struct zebra_dplane_info dp_info;
+
+       if (zns->ge_netlink_cmd.sock < 0)
+               return -1;
+
+       /* Increment sequence number before capturing snapshot of ns socket
+        * info.
+        */
+       zns->ge_netlink_cmd.seq = zebra_router_get_next_sequence();
+
+       /* Capture info in intermediate info struct */
+       dp_info.ns_id = zns->ns_id;
+
+       dp_info.is_cmd = true;
+       dp_info.sock = zns->ge_netlink_cmd.sock;
+       dp_info.seq = zns->ge_netlink_cmd.seq;
+
+       return netlink_talk_info(filter, n, &dp_info, startup);
+}
+
 /* Issue request message to kernel via netlink socket. GET messages
  * are issued through this interface.
  */
@@ -1808,6 +1832,19 @@ void kernel_init(struct zebra_ns *zns)
 
        kernel_netlink_nlsock_insert(&zns->netlink_dplane_in);
 
+       /* Generic Netlink socket. */
+       snprintf(zns->ge_netlink_cmd.name, sizeof(zns->ge_netlink_cmd.name),
+                "generic-netlink-cmd (NS %u)", zns->ns_id);
+       zns->ge_netlink_cmd.sock = -1;
+       if (netlink_socket(&zns->ge_netlink_cmd, 0, 0, 0, zns->ns_id,
+                          NETLINK_GENERIC) < 0) {
+               zlog_warn("Failure to create %s socket",
+                         zns->ge_netlink_cmd.name);
+       }
+
+       if (zns->ge_netlink_cmd.sock >= 0)
+               kernel_netlink_nlsock_insert(&zns->ge_netlink_cmd);
+
        /*
         * SOL_NETLINK is not available on all platforms yet
         * apparently.  It's in bits/socket.h which I am not
@@ -1846,6 +1883,15 @@ void kernel_init(struct zebra_ns *zns)
                zlog_notice("Registration for extended dp ACK failed : %d %s",
                            errno, safe_strerror(errno));
 
+       if (zns->ge_netlink_cmd.sock >= 0) {
+               one = 1;
+               ret = setsockopt(zns->ge_netlink_cmd.sock, SOL_NETLINK,
+                                NETLINK_EXT_ACK, &one, sizeof(one));
+               if (ret < 0)
+                       zlog_err("Registration for extended generic netlink cmd ACK failed : %d %s",
+                                errno, safe_strerror(errno));
+       }
+
        /*
         * Trim off the payload of the original netlink message in the
         * acknowledgment. This option is available since Linux 4.2, so if
@@ -1878,12 +1924,22 @@ void kernel_init(struct zebra_ns *zns)
                         zns->netlink_dplane_in.name, safe_strerror(errno),
                         errno);
 
+       if (zns->ge_netlink_cmd.sock >= 0) {
+               if (fcntl(zns->ge_netlink_cmd.sock, F_SETFL, O_NONBLOCK) < 0)
+                       zlog_err("Can't set %s socket error: %s(%d)",
+                                zns->ge_netlink_cmd.name, safe_strerror(errno),
+                                errno);
+       }
+
        /* Set receive buffer size if it's set from command line */
        if (rcvbufsize) {
                netlink_recvbuf(&zns->netlink, rcvbufsize);
                netlink_recvbuf(&zns->netlink_cmd, rcvbufsize);
                netlink_recvbuf(&zns->netlink_dplane_out, rcvbufsize);
                netlink_recvbuf(&zns->netlink_dplane_in, rcvbufsize);
+
+               if (zns->ge_netlink_cmd.sock >= 0)
+                       netlink_recvbuf(&zns->ge_netlink_cmd, rcvbufsize);
        }
 
        /* Set filter for inbound sockets, to exclude events we've generated
@@ -1926,6 +1982,8 @@ void kernel_terminate(struct zebra_ns *zns, bool complete)
 
        kernel_nlsock_fini(&zns->netlink_dplane_in);
 
+       kernel_nlsock_fini(&zns->ge_netlink_cmd);
+
        /* During zebra shutdown, we need to leave the dataplane socket
         * around until all work is done.
         */
index e910f6244484716f17e3810aa1ff8b40ba6fe3a5..e37bba0cf6244fe787798baa0bb155997d374808 100644 (file)
@@ -98,6 +98,9 @@ extern int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns, int startup);
 extern int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
                        struct nlmsghdr *n, struct nlsock *nl,
                        struct zebra_ns *zns, bool startup);
+extern int
+ge_netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
+               struct nlmsghdr *n, struct zebra_ns *zns, bool startup);
 extern int netlink_request(struct nlsock *nl, void *req);
 
 enum netlink_msg_status {
index cda8bada0c3486022be15d7e079382dce6a0db54..55cbb9552817f0004ddd6daa12bd43d0ba1dae74 100644 (file)
@@ -49,6 +49,8 @@ struct zebra_ns {
        struct nlsock netlink_dplane_out;
        struct nlsock netlink_dplane_in;
        struct event *t_netlink;
+
+       struct nlsock ge_netlink_cmd; /* command channel for generic netlink */
 #endif
 
        struct route_table *if_table;