]> git.ipfire.org Git - network.git/commitdiff
networkd: Create a link object for each interface
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 9 Feb 2023 21:38:09 +0000 (21:38 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 9 Feb 2023 21:38:09 +0000 (21:38 +0000)
We are also listening for netlink events that add and delete any
interfaces.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/networkd/daemon.c
src/networkd/daemon.h
src/networkd/link.c
src/networkd/link.h
src/networkd/links.c
src/networkd/links.h

index 88ce8e71929c2f6aefdea09071c95bf10f51594d..dc2aed6ff7bbed7c7559b5861d800f2f4e83aea9 100644 (file)
@@ -226,6 +226,14 @@ static int nw_daemon_connect_rtnl(struct nw_daemon* daemon, int fd) {
                return 1;
        }
 
+       // Register callback for deleted interfaces
+       r = sd_netlink_add_match(daemon->rtnl, NULL, RTM_DELLINK, nw_link_process, NULL,
+                       daemon, "networkd-RTM_DELLINK");
+       if (r < 0) {
+               ERROR("Could not register RTM_DELLINK: %m\n");
+               return 1;
+       }
+
        return 0;
 }
 
@@ -396,6 +404,27 @@ sd_netlink* nw_daemon_get_rtnl(struct nw_daemon* daemon) {
        return daemon->rtnl;
 }
 
+/*
+       Links
+*/
+struct nw_links* nw_daemon_links(struct nw_daemon* daemon) {
+       return nw_links_ref(daemon->links);
+}
+
+void nw_daemon_drop_link(struct nw_daemon* daemon, struct nw_link* link) {
+       if (!daemon->links)
+               return;
+
+       nw_links_drop_link(daemon->links, link);
+}
+
+struct nw_link* nw_daemon_get_link_by_ifindex(struct nw_daemon* daemon, int ifindex) {
+       if (!daemon->links)
+               return NULL;
+
+       return nw_links_get_by_ifindex(daemon->links, ifindex);
+}
+
 /*
        Zones
 */
index 543685f5b7c40d337aff80aa461bf0254d4c2c11..8e534c57715cb128317b1a72aafe0184e2425ac6 100644 (file)
 
 #include <systemd/sd-netlink.h>
 
-#include "zone.h"
-
 struct nw_daemon;
 
+#include "link.h"
+#include "zone.h"
+
 int nw_daemon_create(struct nw_daemon** daemon);
 
 struct nw_daemon* nw_daemon_ref(struct nw_daemon* daemon);
@@ -41,6 +42,13 @@ int nw_daemon_reload(struct nw_daemon* daemon);
 */
 sd_netlink* nw_daemon_get_rtnl(struct nw_daemon* daemon);
 
+/*
+       Links
+*/
+struct nw_links* nw_daemon_links(struct nw_daemon* daemon);
+void nw_daemon_drop_link(struct nw_daemon* daemon, struct nw_link* link);
+struct nw_link* nw_daemon_get_link_by_ifindex(struct nw_daemon* daemon, int ifindex);
+
 /*
        Zones
 */
index ec0593b0ba766b364800c9c5785e99bc96b7566a..b6ece825929b9cd90db683693b886255ebd4b12a 100644 (file)
 #include <stddef.h>
 #include <stdlib.h>
 
+#include <systemd/sd-netlink.h>
+
 #include "daemon.h"
 #include "link.h"
+#include "links.h"
 #include "logging.h"
 
 struct nw_link {
@@ -48,12 +51,16 @@ int nw_link_create(struct nw_link** link, struct nw_daemon* daemon, int ifindex)
        // Store the ifindex
        l->ifindex = ifindex;
 
+       DEBUG("New link allocated (ifindex = %d)\n", l->ifindex);
+
        *link = l;
 
        return 0;
 }
 
 static void nw_link_free(struct nw_link* link) {
+       DEBUG("Freeing link (ifindex = %d)\n", link->ifindex);
+
        if (link->daemon)
                nw_daemon_unref(link->daemon);
 }
@@ -72,8 +79,112 @@ struct nw_link* nw_link_unref(struct nw_link* link) {
        return NULL;
 }
 
-int nw_link_process(sd_netlink* rtnl, sd_netlink_message* message, void* data) {
-       DEBUG("nw_link_process called\n");
+int nw_link_ifindex(struct nw_link* link) {
+       return link->ifindex;
+}
 
-       return 0;
+int nw_link_process(sd_netlink* rtnl, sd_netlink_message* message, void* data) {
+       struct nw_links* links = NULL;
+       struct nw_link* link = NULL;
+       const char* ifname = NULL;
+       int ifindex;
+       uint16_t type;
+       int r;
+
+       struct nw_daemon* daemon = (struct nw_daemon*)data;
+
+       // Fetch links
+       links = nw_daemon_links(daemon);
+       if (!links) {
+               r = 1;
+               goto ERROR;
+       }
+
+       // Check if this message could be received
+       if (sd_netlink_message_is_error(message)) {
+               r = sd_netlink_message_get_errno(message);
+               if (r < 0)
+                       ERROR("Could not receive link message: %m\n");
+
+               goto IGNORE;
+       }
+
+       // Fetch the message type
+       r = sd_netlink_message_get_type(message, &type);
+       if (r < 0) {
+               ERROR("Could not fetch message type: %m\n");
+               goto IGNORE;
+       }
+
+       // Check type
+       switch (type) {
+               case RTM_NEWLINK:
+               case RTM_DELLINK:
+                       break;
+
+               default:
+                       ERROR("Received an unexpected message (type %u)\n", type);
+                       goto IGNORE;
+       }
+
+       // Fetch the interface index
+       r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
+       if (r < 0) {
+               ERROR("Could not fetch ifindex: %m\n");
+               goto IGNORE;
+       }
+
+       // Check interface index
+       if (ifindex <= 0) {
+               ERROR("Received an invalid ifindex\n");
+               goto IGNORE;
+       }
+
+       // Fetch the interface name
+       r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
+       if (r < 0) {
+               ERROR("Received a netlink message without interface name: %m\n");
+               goto IGNORE;
+       }
+
+       // Try finding an existing link
+       link = nw_daemon_get_link_by_ifindex(daemon, ifindex);
+
+       switch (type) {
+               case RTM_NEWLINK:
+                       // If the link doesn't exist, create it
+                       if (!link) {
+                               r = nw_link_create(&link, daemon, ifindex);
+                               if (r) {
+                                       ERROR("Could not create link: %m\n");
+                                       goto ERROR;
+                               }
+                       }
+
+                       // TODO Import any data from the netlink message
+
+                       // Add it to the list
+                       r = nw_links_add_link(links, link);
+                       if (r)
+                               goto ERROR;
+
+                       break;
+
+               case RTM_DELLINK:
+                       if (link)
+                               nw_links_drop_link(links, link);
+
+                       break;
+       }
+
+IGNORE:
+       r = 0;
+
+ERROR:
+       if (links)
+               nw_links_unref(links);
+       if (link)
+               nw_link_unref(link);
+
+       return r;
 }
index 6003133d5119b610dc29d428e8352c657c7c6317..e482d71ac67df4ccb58011654445222cfe45901e 100644 (file)
@@ -30,6 +30,8 @@ int nw_link_create(struct nw_link** link, struct nw_daemon* daemon, int ifindex)
 struct nw_link* nw_link_ref(struct nw_link* link);
 struct nw_link* nw_link_unref(struct nw_link* link);
 
+int nw_link_ifindex(struct nw_link* link);
+
 int nw_link_process(sd_netlink* rtnl, sd_netlink_message* message, void* data);
 
 #endif /* NETWORKD_LINK_H */
index 22584f2f632c3dfe4fcf328da6db4b17a406b930..044a27dc85909ef2d43f982ea4616fe19781bfd9 100644 (file)
@@ -23,6 +23,7 @@
 #include <sys/queue.h>
 
 #include "daemon.h"
+#include "logging.h"
 #include "link.h"
 #include "links.h"
 
@@ -98,6 +99,49 @@ struct nw_links* nw_links_unref(struct nw_links* links) {
        return NULL;
 }
 
+static struct nw_links_entry* nw_links_find_link(struct nw_links* links, const int ifindex) {
+       struct nw_links_entry* entry = NULL;
+
+       STAILQ_FOREACH(entry, &links->entries, nodes) {
+               if (nw_link_ifindex(entry->link) == ifindex)
+                       return entry;
+       }
+
+       // No match found
+       return NULL;
+}
+
+int nw_links_add_link(struct nw_links* links, struct nw_link* link) {
+       // Allocate a new entry
+       struct nw_links_entry* entry = calloc(1, sizeof(*entry));
+       if (!entry)
+               return 1;
+
+       // Reference the link
+       entry->link = nw_link_ref(link);
+
+       // Add it to the list
+       STAILQ_INSERT_TAIL(&links->entries, entry, nodes);
+
+       // Increment the counter
+       links->num++;
+
+       return 0;
+}
+
+void nw_links_drop_link(struct nw_links* links, struct nw_link* link) {
+       struct nw_links_entry* entry = NULL;
+
+       entry = nw_links_find_link(links, nw_link_ifindex(link));
+       if (!entry)
+               return;
+
+       DEBUG("Dropping link %d\n", nw_link_ifindex(entry->link));
+
+       STAILQ_REMOVE(&links->entries, entry, nw_links_entry, nodes);
+       links->num--;
+}
+
 int nw_links_enumerate(struct nw_links* links) {
        sd_netlink_message* req = NULL;
        sd_netlink_message* res = NULL;
@@ -138,3 +182,13 @@ ERROR:
 
        return r;
 }
+
+struct nw_link* nw_links_get_by_ifindex(struct nw_links* links, int ifindex) {
+       struct nw_links_entry* entry = NULL;
+
+       entry = nw_links_find_link(links, ifindex);
+       if (!entry)
+               return NULL;
+
+       return nw_link_ref(entry->link);
+}
index b2976e4af8b3884604ce29ba824a86e373475061..2f2bbeab044a4584f8d663f46bb97a81547cb8e4 100644 (file)
@@ -22,6 +22,7 @@
 #define NETWORKD_LINKS_H
 
 #include "daemon.h"
+#include "link.h"
 
 struct nw_links;
 
@@ -30,6 +31,11 @@ int nw_links_create(struct nw_links** links, struct nw_daemon* daemon);
 struct nw_links* nw_links_ref(struct nw_links* links);
 struct nw_links* nw_links_unref(struct nw_links* links);
 
+int nw_links_add_link(struct nw_links* links, struct nw_link* link);
+void nw_links_drop_link(struct nw_links* links, struct nw_link* link);
+
 int nw_links_enumerate(struct nw_links* links);
 
+struct nw_link* nw_links_get_by_ifindex(struct nw_links* links, int ifindex);
+
 #endif /* NETWORKD_LINKS_H */