From: Michael Tremer Date: Thu, 9 Feb 2023 21:38:09 +0000 (+0000) Subject: networkd: Create a link object for each interface X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=766f08ca103698e6578228e11f81c1d73d687d65;p=network.git networkd: Create a link object for each interface We are also listening for netlink events that add and delete any interfaces. Signed-off-by: Michael Tremer --- diff --git a/src/networkd/daemon.c b/src/networkd/daemon.c index 88ce8e71..dc2aed6f 100644 --- a/src/networkd/daemon.c +++ b/src/networkd/daemon.c @@ -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 */ diff --git a/src/networkd/daemon.h b/src/networkd/daemon.h index 543685f5..8e534c57 100644 --- a/src/networkd/daemon.h +++ b/src/networkd/daemon.h @@ -23,10 +23,11 @@ #include -#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 */ diff --git a/src/networkd/link.c b/src/networkd/link.c index ec0593b0..b6ece825 100644 --- a/src/networkd/link.c +++ b/src/networkd/link.c @@ -21,8 +21,11 @@ #include #include +#include + #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; } diff --git a/src/networkd/link.h b/src/networkd/link.h index 6003133d..e482d71a 100644 --- a/src/networkd/link.h +++ b/src/networkd/link.h @@ -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 */ diff --git a/src/networkd/links.c b/src/networkd/links.c index 22584f2f..044a27dc 100644 --- a/src/networkd/links.c +++ b/src/networkd/links.c @@ -23,6 +23,7 @@ #include #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); +} diff --git a/src/networkd/links.h b/src/networkd/links.h index b2976e4a..2f2bbeab 100644 --- a/src/networkd/links.h +++ b/src/networkd/links.h @@ -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 */