From: Michael Tremer Date: Mon, 30 Mar 2026 15:37:14 +0000 (+0000) Subject: netlink: Move all netlink stuff away X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=52f5bca05a5ab40abcf2d724fb813ec6e77932d0;p=telemetry.git netlink: Move all netlink stuff away Signed-off-by: Michael Tremer --- diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c index 95d7aae..21eaa2f 100644 --- a/src/daemon/daemon.c +++ b/src/daemon/daemon.c @@ -26,17 +26,6 @@ #include #include -#ifdef HAVE_LIBNL3 -# ifdef HAVE_LIBNL3_GENL -# include -# include -# endif -# ifdef HAVE_LIBNL3_ROUTE -# include -# include -# endif /* HAVE_LIBNL3_ROUTE */ -#endif /* HAVE_LIBNL3 */ - #include "bus.h" #include "ctx.h" #include "daemon.h" @@ -87,27 +76,6 @@ struct td_daemon { // Netlink td_netlink* netlink; - - // Netlink Sockets -#ifdef HAVE_LIBNL3 - struct { - // 802.11 -# ifdef HAVE_LIBNL3_GENL - struct nl_sock* nl80211; -# endif /* HAVE_LIBNL3_GENL */ - - // Route -# ifdef HAVE_LIBNL3_ROUTE - struct nl_sock* route; -# endif /* HAVE_LIBNL3_ROUTE */ - } nl_sockets; -#endif /* HAVE_LIBNL3 */ - -#ifdef HAVE_LIBNL3 -# ifdef HAVE_LIBNL3_GENL - int nl80211id; -# endif /* HAVE_LIBNL3_GENL */ -#endif /* HAVE_LIBNL3 */ }; static int td_daemon_init(sd_event_source* source, void* data) { @@ -310,18 +278,6 @@ static int td_daemon_setup_netlink(td_daemon* self) { } static void td_daemon_free(td_daemon* self) { - // Free Netlink Sockets -#ifdef HAVE_LIBNL3 -# ifdef HAVE_LIBNL3_GENL - if (self->nl_sockets.nl80211) - nl_socket_free(self->nl_sockets.nl80211); -# endif /* HAVE_LIBNL3_GENL */ -# ifdef HAVE_LIBNL3_ROUTE - if (self->nl_sockets.route) - nl_socket_free(self->nl_sockets.route); -# endif /* HAVE_LIBNL3_ROUTE */ -#endif /* HAVE_LIBNL3 */ - if (self->events.memory_pressure) sd_event_source_unref(self->events.memory_pressure); if (self->events.sigchld) @@ -485,82 +441,6 @@ td_netlink* td_daemon_get_netlink(td_daemon* self) { return td_netlink_ref(self->netlink); } -#ifdef HAVE_LIBNL3 -static struct nl_sock* td_daemon_get_nl_socket(td_daemon* self, int protocol) { - struct nl_sock* sock = NULL; - int r; - - // Allocate a new socket - sock = nl_socket_alloc(); - if (!sock) { - ERROR(self->ctx, "Failed to allocate a new Netlink socket: %m\n"); - goto ERROR; - } - - // Connect the protocol - r = nl_connect(sock, protocol); - if (r < 0) { - ERROR(self->ctx, "Failed to select netlink protocol %d: %s\n", - protocol, nl_geterror(r)); - errno = ENOTSUP; - goto ERROR; - } - - // Return the socket - return sock; - -ERROR: - if (sock) - nl_socket_free(sock); - - return NULL; -} - -# ifdef HAVE_LIBNL3_GENL -struct nl_sock* td_daemon_get_nl_80211_socket(td_daemon* self) { - // Create socket if not already done - if (!self->nl_sockets.nl80211) - self->nl_sockets.nl80211 = td_daemon_get_nl_socket(self, NETLINK_GENERIC); - - return self->nl_sockets.nl80211; -} - -int td_daemon_get_nl_80211_id(td_daemon* self) { - struct nl_sock* sock = NULL; - int r; - - if (!self->nl80211id) { - // Fetch the nl80211 socket - sock = td_daemon_get_nl_80211_socket(self); - if (!sock) - return -errno; - - // Retrieve the ID - r = genl_ctrl_resolve(sock, "nl80211"); - if (r < 0) { - ERROR(self->ctx, "Failed to resolve nl80211 family id: %s\n", nl_geterror(r)); - return -ENOTSUP; - } - - // Cache the ID - self->nl80211id = r; - } - - return self->nl80211id; -} -# endif /* HAVE_LIBNL3_GENL */ - -# ifdef HAVE_LIBNL3_ROUTE -struct nl_sock* td_daemon_get_nl_route_socket(td_daemon* self) { - // Create socket if not already done - if (!self->nl_sockets.route) - self->nl_sockets.route = td_daemon_get_nl_socket(self, NETLINK_ROUTE); - - return self->nl_sockets.route; -} -# endif /* HAVE_LIBNL3_ROUTE */ -#endif /* HAVE_LIBNL3 */ - static int td_daemon_bus_version(sd_bus* bus, const char* path, const char* interface, const char* property, sd_bus_message* reply, void* data, sd_bus_error* error) { return sd_bus_message_append(reply, "s", PACKAGE_VERSION); diff --git a/src/daemon/daemon.h b/src/daemon/daemon.h index 5f48ad8..5d8006c 100644 --- a/src/daemon/daemon.h +++ b/src/daemon/daemon.h @@ -24,13 +24,6 @@ #include #include -#ifdef HAVE_LIBNL3 -# ifdef HAVE_LIBNL3_ROUTE -# include -# endif /* HAVE_LIBNL3_ROUTE */ -#endif /* HAVE_LIBNL3 */ - - typedef struct td_daemon td_daemon; #include "bus.h" @@ -61,15 +54,6 @@ int td_daemon_flush_source( #ifdef HAVE_LIBNL3 td_netlink* td_daemon_get_netlink(td_daemon* self); - -# ifdef HAVE_LIBNL3_GENL -struct nl_sock* td_daemon_get_nl_80211_socket(td_daemon* self); -int td_daemon_get_nl_80211_id(td_daemon* self); -# endif /* HAVE_LIBNL3_GENL */ - -# ifdef HAVE_LIBNL3_ROUTE -struct nl_sock* td_daemon_get_nl_route_socket(td_daemon* self); -# endif /* HAVE_LIBNL3_ROUTE */ #endif /* HAVE_LIBNL3 */ // Bus diff --git a/src/daemon/netlink.c b/src/daemon/netlink.c index 90a39c1..2ae14b7 100644 --- a/src/daemon/netlink.c +++ b/src/daemon/netlink.c @@ -21,17 +21,54 @@ #ifdef HAVE_LIBNL3 #include +#include #include +#ifdef HAVE_LIBNL3_GENL +# include +# include +#endif + +#ifdef HAVE_LIBNL3_ROUTE +# include +# include +#endif /* HAVE_LIBNL3_ROUTE */ + #include "ctx.h" #include "netlink.h" struct td_netlink { td_ctx* ctx; int nrefs; + + // Route Stuff +#ifdef HAVE_LIBNL3_ROUTE + struct { + struct nl_sock* sock; + } route; +#endif /* HAVE_LIBNL3_ROUTE */ + + // 802.11 Stuff +#ifdef HAVE_LIBNL3_GENL + struct { + struct nl_sock* sock; + int id; + } nl80211; +#endif /* HAVE_LIBNL3_GENL */ }; static void td_netlink_free(td_netlink* self) { + // Free Netlink Sockets +#ifdef HAVE_LIBNL3_GENL + if (self->nl80211.sock) + nl_socket_free(self->nl80211.sock); +#endif /* HAVE_LIBNL3_GENL */ + +#ifdef HAVE_LIBNL3_ROUTE + if (self->route.sock) + nl_socket_free(self->route.sock); +#endif /* HAVE_LIBNL3_ROUTE */ + if (self->ctx) td_ctx_unref(self->ctx); free(self); @@ -70,4 +107,231 @@ td_netlink* td_netlink_unref(td_netlink* self) { return NULL; } +static struct nl_sock* td_netlink_get_socket(td_netlink* self, int protocol) { + struct nl_sock* sock = NULL; + int r; + + // Allocate a new socket + sock = nl_socket_alloc(); + if (!sock) { + ERROR(self->ctx, "Failed to allocate a new Netlink socket: %m\n"); + goto ERROR; + } + + // Connect the protocol + r = nl_connect(sock, protocol); + if (r < 0) { + ERROR(self->ctx, "Failed to select netlink protocol %d: %s\n", + protocol, nl_geterror(r)); + errno = ENOTSUP; + goto ERROR; + } + + // Return the socket + return sock; + +ERROR: + if (sock) + nl_socket_free(sock); + + return NULL; +} + +/* + Route Stuff +*/ +# ifdef HAVE_LIBNL3_ROUTE +static struct nl_sock* td_netlink_get_route_socket(td_netlink* self) { + // Create socket if not already done + if (!self->route.sock) + self->route.sock = td_netlink_get_socket(self, NETLINK_ROUTE); + + return self->route.sock; +} + +typedef struct td_netlink_enumerte_interfaces_ctx { + // Context + td_ctx* ctx; + + // Callback & Data + td_netlink_interface_callback callback; + void* data; +} td_netlink_enumerate_interfaces_ctx; + +static void enumerate_interface(struct nl_object* object, void* data) { + struct rtnl_link* link = (struct rtnl_link*)object; + td_netlink_enumerate_interfaces_ctx* ctx = data; + const char* name = NULL; + int r; + + // Fetch the link name + name = rtnl_link_get_name(link); + if (!name) + return; + + // Call the callback + r = ctx->callback(ctx->ctx, name, link, ctx->data); + if (r < 0) + ERROR(ctx->ctx, "Netlink: Enumerating interfaces failed: %s\n", strerror(-r)); +} + +int td_netlink_enumerate_interfaces(td_netlink* self, + td_netlink_interface_callback callback, void* data) { + struct nl_sock* sock = NULL; + struct nl_cache* links = NULL; + int r; + + td_netlink_enumerate_interfaces_ctx ctx = { + .ctx = self->ctx, + .callback = callback, + .data = data, + }; + + // Fetch the Netlink socket + sock = td_netlink_get_route_socket(self); + if (!sock) + return -errno; + + // Fetch the links + r = rtnl_link_alloc_cache(sock, AF_UNSPEC, &links); + if (r < 0) { + ERROR(self->ctx, "Failed to fetch the links: %s\n", nl_geterror(r)); + r = -ENOTSUP; + goto ERROR; + } + + // Walk through all interfaces + nl_cache_foreach(links, enumerate_interface, &ctx); + +ERROR: + if (links) + nl_cache_free(links); + + return r; +} + +int td_netlink_get_default_gateway(td_netlink* self, + char* address, size_t length, unsigned int* type) { + struct nl_sock* sock = NULL; + struct nl_cache* routes = NULL; + struct rtnl_route* route = NULL; + struct nl_cache* links = NULL; + struct rtnl_link* link = NULL; + struct rtnl_nexthop* nh = NULL; + struct nl_addr* gw = NULL; + int ifindex = -1; + int r; + + // Fetch the Netlink socket + sock = td_netlink_get_route_socket(self); + if (!sock) + return -errno; + + // Fetch the route cache + r = rtnl_route_alloc_cache(sock, AF_INET, 0, &routes); + if (r < 0) { + ERROR(self->ctx, "Failed to fetch the route cache: %s\n", nl_geterror(r)); + r = -ENOTSUP; + goto ERROR; + } + + // Fetch the links + r = rtnl_link_alloc_cache(sock, AF_UNSPEC, &links); + if (r < 0) { + ERROR(self->ctx, "Failed to fetch the links: %s\n", nl_geterror(r)); + r = -ENOTSUP; + goto ERROR; + } + + // Walk through all routes + for (struct nl_object* o = nl_cache_get_first(routes); o; o = nl_cache_get_next(o)) { + route = (struct rtnl_route*)o; + + // Ignore anything that isn't IPv4 + if (rtnl_route_get_family(route) != AF_INET) + continue; + + // Ignore anything but the main routing table + if (rtnl_route_get_table(route) != RT_TABLE_MAIN) + continue; + + // Ignore anything but the default route + if (!rtnl_route_get_dst(route)) + continue; + + // Fetch the nexthop + nh = rtnl_route_nexthop_n(route, 0); + if (!nh) + continue; + + // Fetch the gateway + gw = rtnl_route_nh_get_gateway(nh); + if (!gw) + continue; + + // Return the gateway address + if (!nl_addr2str(gw, address, length)) + continue; + + // Fetch the interface + ifindex = rtnl_route_nh_get_ifindex(nh); + + // Fetch the link + link = rtnl_link_get(links, ifindex); + if (!link) + continue; + + // Fetch the type of the interface + *type = rtnl_link_get_arptype(link); + } + +ERROR: + if (routes) + nl_cache_free(routes); + if (links) + nl_cache_free(links); + + return r; +} + +# endif /* HAVE_LIBNL3_ROUTE */ + +/* + 802.11 Stuff +*/ +# ifdef HAVE_LIBNL3_GENL + +static struct nl_sock* td_netlink_get_nl80211_socket(td_netlink* self) { + // Create socket if not already done + if (!self->nl80211.sock) + self->nl80211.sock = td_netlink_get_socket(self, NETLINK_GENERIC); + + return self->nl80211.sock; +} + +static int td_netlink_get_nl80211_id(td_netlink* self) { + struct nl_sock* sock = NULL; + int r; + + if (!self->nl80211.id) { + // Fetch the nl80211 socket + sock = td_netlink_get_nl80211_socket(self); + if (!sock) + return -errno; + + // Retrieve the ID + r = genl_ctrl_resolve(sock, "nl80211"); + if (r < 0) { + ERROR(self->ctx, "Failed to resolve nl80211 family id: %s\n", nl_geterror(r)); + return -ENOTSUP; + } + + // Cache the ID + self->nl80211.id = r; + } + + return self->nl80211.id; +} +# endif /* HAVE_LIBNL3_GENL */ + #endif /* HAVE_LIBNL3 */ diff --git a/src/daemon/netlink.h b/src/daemon/netlink.h index a7ef944..39b895d 100644 --- a/src/daemon/netlink.h +++ b/src/daemon/netlink.h @@ -32,6 +32,20 @@ int td_netlink_create(td_netlink** netlink, td_ctx* ctx); td_netlink* td_netlink_ref(td_netlink* self); td_netlink* td_netlink_unref(td_netlink* self); +#ifdef HAVE_LIBNL3_ROUTE +# include + +typedef int (*td_netlink_interface_callback) + (td_ctx* ctx, const char* name, struct rtnl_link* link, void* data); + +int td_netlink_enumerate_interfaces(td_netlink* self, + td_netlink_interface_callback callback, void* data); + +int td_netlink_get_default_gateway(td_netlink* self, + char* address, size_t length, unsigned int* type); + +#endif /* HAVE_LIBNL3_ROUTE */ + #endif /* HAVE_LIBNL3 */ #endif /* TELEMETRY_NETLINK_H */ diff --git a/src/daemon/source.c b/src/daemon/source.c index 6206be4..0a02bb0 100644 --- a/src/daemon/source.c +++ b/src/daemon/source.c @@ -35,6 +35,7 @@ #include "ctx.h" #include "daemon.h" #include "metrics.h" +#include "netlink.h" #include "source.h" #include "string.h" #include "time.h" @@ -547,8 +548,8 @@ struct udev* td_source_get_udev(td_source* self) { return td_daemon_get_udev(self->daemon); } -struct nl_sock* td_source_get_nl_route_socket(td_source* self) { - return td_daemon_get_nl_route_socket(self->daemon); +td_netlink* td_source_get_netlink(td_source* self) { + return td_daemon_get_netlink(self->daemon); } unsigned int td_source_num_data_sources(td_source* self) { diff --git a/src/daemon/source.h b/src/daemon/source.h index 5f9d352..fefed4e 100644 --- a/src/daemon/source.h +++ b/src/daemon/source.h @@ -25,12 +25,6 @@ #include -#ifdef HAVE_LIBNL3 -# ifdef HAVE_LIBNL3_ROUTE -# include -# endif /* HAVE_LIBNL3_ROUTE */ -#endif /* HAVE_LIBNL3 */ - typedef struct td_source td_source; #include "args.h" @@ -38,6 +32,7 @@ typedef struct td_source td_source; #include "ctx.h" #include "daemon.h" #include "metrics.h" +#include "netlink.h" #define MAX_DS 64 #define MAX_RRA 8 @@ -92,6 +87,7 @@ const char* td_source_name(td_source* self); int td_source_disable(td_source* self); struct udev* td_source_get_udev(td_source* self); +td_netlink* td_source_get_netlink(td_source* self); #ifdef HAVE_LIBNL3 # ifdef HAVE_LIBNL3_ROUTE diff --git a/src/daemon/sources/interface.c b/src/daemon/sources/interface.c index cc8515c..1aa2fe6 100644 --- a/src/daemon/sources/interface.c +++ b/src/daemon/sources/interface.c @@ -101,18 +101,13 @@ static const interface_stats stats[] = { { NULL }, }; -static void interface_link_callback(struct nl_object* object, void* data) { - struct rtnl_link* link = (struct rtnl_link*)object; +static int interface_link_callback(td_ctx* ctx, const char* name, + struct rtnl_link* link, void* data) { td_metrics* metrics = NULL; td_source* source = data; uint64_t value = 0; int r; - // Fetch the link name - const char *name = rtnl_link_get_name(link); - if (!name) - goto ERROR; - // Create a new metrics object r = td_source_create_metrics(source, &metrics, name); if (r < 0) @@ -137,31 +132,27 @@ static void interface_link_callback(struct nl_object* object, void* data) { ERROR: if (metrics) td_metrics_unref(metrics); + + return r; } static int interface_heartbeat(td_ctx* ctx, td_source* source) { - struct nl_cache* links = NULL; + td_netlink* netlink = NULL; int r; - // Fetch the Netlink socket - struct nl_sock* sock = td_source_get_nl_route_socket(source); - if (!sock) + // Fetch the netlink interface + netlink = td_source_get_netlink(source); + if (!netlink) return -errno; - // Fetch the links - r = rtnl_link_alloc_cache(sock, AF_UNSPEC, &links); - if (r < 0) { - ERROR(ctx, "Failed to fetch the links: %s\n", nl_geterror(r)); - r = -ENOTSUP; + // Enumerate all interfaces + r = td_netlink_enumerate_interfaces(netlink, interface_link_callback, source); + if (r < 0) goto ERROR; - } - - // Walk through all interfaces - nl_cache_foreach(links, interface_link_callback, source); ERROR: - if (links) - nl_cache_free(links); + if (netlink) + td_netlink_unref(netlink); return r; } diff --git a/src/daemon/sources/legacy-gateway-latency4.c b/src/daemon/sources/legacy-gateway-latency4.c index 0850c8d..947242d 100644 --- a/src/daemon/sources/legacy-gateway-latency4.c +++ b/src/daemon/sources/legacy-gateway-latency4.c @@ -36,89 +36,6 @@ #include "../time.h" #include "legacy-gateway-latency4.h" -static int fetch_default_gateway(td_ctx* ctx, td_source* source, - char* address, size_t length, unsigned int* type) { - struct nl_cache* routes = NULL; - struct rtnl_route* route = NULL; - struct nl_cache* links = NULL; - struct rtnl_link* link = NULL; - struct rtnl_nexthop* nh = NULL; - struct nl_addr* gw = NULL; - int ifindex = -1; - int r; - - // Fetch the Netlink socket - struct nl_sock* sock = td_source_get_nl_route_socket(source); - if (!sock) - return -errno; - - // Fetch the route cache - r = rtnl_route_alloc_cache(sock, AF_INET, 0, &routes); - if (r < 0) { - ERROR(ctx, "Failed to fetch the route cache: %s\n", nl_geterror(r)); - r = -ENOTSUP; - goto ERROR; - } - - // Fetch the links - r = rtnl_link_alloc_cache(sock, AF_UNSPEC, &links); - if (r < 0) { - ERROR(ctx, "Failed to fetch the links: %s\n", nl_geterror(r)); - r = -ENOTSUP; - goto ERROR; - } - - // Walk through all routes - for (struct nl_object* o = nl_cache_get_first(routes); o; o = nl_cache_get_next(o)) { - route = (struct rtnl_route*)o; - - // Ignore anything that isn't IPv4 - if (rtnl_route_get_family(route) != AF_INET) - continue; - - // Ignore anything but the main routing table - if (rtnl_route_get_table(route) != RT_TABLE_MAIN) - continue; - - // Ignore anything but the default route - if (!rtnl_route_get_dst(route)) - continue; - - // Fetch the nexthop - nh = rtnl_route_nexthop_n(route, 0); - if (!nh) - continue; - - // Fetch the gateway - gw = rtnl_route_nh_get_gateway(nh); - if (!gw) - continue; - - // Return the gateway address - if (!nl_addr2str(gw, address, length)) - continue; - - // Fetch the interface - ifindex = rtnl_route_nh_get_ifindex(nh); - - // Fetch the link - link = rtnl_link_get(links, ifindex); - if (!link) - continue; - - // Fetch the type of the interface - *type = rtnl_link_get_arptype(link); - } - -ERROR: - if (routes) - nl_cache_free(routes); - if (links) - nl_cache_free(links); - - return r; -} - static int legacy_gateway_latency_on_success(td_ctx* ctx, int rc, td_file* stdout, void* data) { td_source* source = data; @@ -199,29 +116,44 @@ static int do_ping(td_ctx* ctx, td_source* source, const char* address) { } static int legacy_gateway_latency4_heartbeat(td_ctx* ctx, td_source* source) { + td_netlink* netlink = NULL; char address[NAME_MAX] = ""; unsigned int type = 0; int r; + // Fetch netlink + netlink = td_source_get_netlink(source); + if (!netlink) + return -errno; + // Fetch the IP address of the default gateway - r = fetch_default_gateway(ctx, source, address, sizeof(address), &type); + r = td_netlink_get_default_gateway(netlink, address, sizeof(address), &type); if (r < 0) - return r; + goto ERROR; // Bail if we don't have a gateway address if (!*address) { DEBUG(ctx, "Failed to fetch the gateway address\n"); - return 0; + r = 0; + goto ERROR; } // Use ARP ping for Ethernet interfaces and otherwise fall back on ICMP ping switch (type) { case ARPHRD_ETHER: - return do_arping(ctx, source, address); + r = do_arping(ctx, source, address); + break; default: - return do_ping(ctx, source, address); + r = do_ping(ctx, source, address); + break; } + +ERROR: + if (netlink) + td_netlink_unref(netlink); + + return r; } const td_source_impl legacy_gateway_latency4_source = {