summaryrefslogtreecommitdiffstats
path: root/src/network/networkctl-dump-util.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2024-08-21 08:31:57 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2024-08-21 18:12:39 +0200
commit1bf49198b5ce8c5a68d32b722497bf22be2b1f8b (patch)
treec34c857c27c7025d18426cbeb5d34db5c6c91512 /src/network/networkctl-dump-util.c
parentMerge pull request #33498 from DaanDeMeyer/btrfs (diff)
downloadsystemd-1bf49198b5ce8c5a68d32b722497bf22be2b1f8b.tar.xz
systemd-1bf49198b5ce8c5a68d32b722497bf22be2b1f8b.zip
networkctl: split networkctl.c into small pieces
No functional change, just refactoring.
Diffstat (limited to 'src/network/networkctl-dump-util.c')
-rw-r--r--src/network/networkctl-dump-util.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/src/network/networkctl-dump-util.c b/src/network/networkctl-dump-util.c
new file mode 100644
index 0000000000..d8022eb3f0
--- /dev/null
+++ b/src/network/networkctl-dump-util.c
@@ -0,0 +1,242 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "format-util.h"
+#include "in-addr-util.h"
+#include "local-addresses.h"
+#include "networkctl-dump-util.h"
+#include "stdio-util.h"
+#include "strv.h"
+
+int dump_list(Table *table, const char *key, char * const *l) {
+ int r;
+
+ assert(table);
+ assert(key);
+
+ if (strv_isempty(l))
+ return 0;
+
+ r = table_add_many(table,
+ TABLE_FIELD, key,
+ TABLE_STRV, l);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ return 0;
+}
+
+/* IEEE Organizationally Unique Identifier vendor string */
+int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) {
+ _cleanup_free_ char *desc = NULL;
+ const char *description;
+ char modalias[STRLEN("OUI:XXYYXXYYXXYY") + 1];
+ int r;
+
+ assert(ret);
+
+ if (!hwdb || !mac)
+ return -EINVAL;
+
+ /* skip commonly misused 00:00:00 (Xerox) prefix */
+ if (memcmp(mac, "\0\0\0", 3) == 0)
+ return -EINVAL;
+
+ xsprintf(modalias, "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
+
+ r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
+ if (r < 0)
+ return r;
+
+ desc = strdup(description);
+ if (!desc)
+ return -ENOMEM;
+
+ *ret = TAKE_PTR(desc);
+
+ return 0;
+}
+
+static int get_gateway_description(
+ sd_netlink *rtnl,
+ sd_hwdb *hwdb,
+ int ifindex,
+ int family,
+ union in_addr_union *gateway,
+ char **ret) {
+
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+ int r;
+
+ assert(rtnl);
+ assert(ifindex >= 0);
+ assert(IN_SET(family, AF_INET, AF_INET6));
+ assert(gateway);
+ assert(ret);
+
+ r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_set_request_dump(req, true);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(rtnl, req, 0, &reply);
+ if (r < 0)
+ return r;
+
+ for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
+ union in_addr_union gw = IN_ADDR_NULL;
+ struct ether_addr mac = ETHER_ADDR_NULL;
+ uint16_t type;
+ int ifi, fam;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get netlink message, ignoring: %m");
+ continue;
+ }
+
+ r = sd_netlink_message_get_type(m, &type);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get netlink message type, ignoring: %m");
+ continue;
+ }
+
+ if (type != RTM_NEWNEIGH) {
+ log_error("Got unexpected netlink message type %u, ignoring.", type);
+ continue;
+ }
+
+ r = sd_rtnl_message_neigh_get_family(m, &fam);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get rtnl family, ignoring: %m");
+ continue;
+ }
+
+ if (fam != family) {
+ log_error("Got invalid rtnl family %d, ignoring.", fam);
+ continue;
+ }
+
+ r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get rtnl ifindex, ignoring: %m");
+ continue;
+ }
+
+ if (ifindex > 0 && ifi != ifindex)
+ continue;
+
+ switch (fam) {
+
+ case AF_INET:
+ r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in);
+ if (r < 0)
+ continue;
+
+ break;
+
+ case AF_INET6:
+ r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6);
+ if (r < 0)
+ continue;
+
+ break;
+
+ default:
+ assert_not_reached();
+ }
+
+ if (!in_addr_equal(fam, &gw, gateway))
+ continue;
+
+ r = sd_netlink_message_read(m, NDA_LLADDR, sizeof(mac), &mac);
+ if (r < 0)
+ continue;
+
+ r = ieee_oui(hwdb, &mac, ret);
+ if (r < 0)
+ continue;
+
+ return 0;
+ }
+
+ return -ENODATA;
+}
+
+int dump_gateways(sd_netlink *rtnl, sd_hwdb *hwdb, Table *table, int ifindex) {
+ _cleanup_free_ struct local_address *local_addrs = NULL;
+ _cleanup_strv_free_ char **buf = NULL;
+ int r, n;
+
+ assert(rtnl);
+ assert(table);
+
+ n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local_addrs);
+ if (n <= 0)
+ return n;
+
+ FOREACH_ARRAY(local, local_addrs, n) {
+ _cleanup_free_ char *description = NULL;
+
+ r = get_gateway_description(rtnl, hwdb, local->ifindex, local->family, &local->address, &description);
+ if (r < 0)
+ log_debug_errno(r, "Could not get description of gateway, ignoring: %m");
+
+ /* Show interface name for the entry if we show entries for all interfaces */
+ r = strv_extendf(&buf, "%s%s%s%s%s%s",
+ IN_ADDR_TO_STRING(local->family, &local->address),
+ description ? " (" : "",
+ strempty(description),
+ description ? ")" : "",
+ ifindex <= 0 ? " on " : "",
+ ifindex <= 0 ? FORMAT_IFNAME_FULL(local->ifindex, FORMAT_IFNAME_IFINDEX_WITH_PERCENT) : "");
+ if (r < 0)
+ return log_oom();
+ }
+
+ return dump_list(table, "Gateway", buf);
+}
+
+int dump_addresses(
+ sd_netlink *rtnl,
+ sd_dhcp_lease *lease,
+ Table *table,
+ int ifindex) {
+
+ _cleanup_free_ struct local_address *local_addrs = NULL;
+ _cleanup_strv_free_ char **buf = NULL;
+ struct in_addr dhcp4_address = {};
+ int r, n;
+
+ assert(rtnl);
+ assert(table);
+
+ n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local_addrs);
+ if (n <= 0)
+ return n;
+
+ if (lease)
+ (void) sd_dhcp_lease_get_address(lease, &dhcp4_address);
+
+ FOREACH_ARRAY(local, local_addrs, n) {
+ struct in_addr server_address;
+ bool dhcp4 = false;
+
+ if (local->family == AF_INET && in4_addr_equal(&local->address.in, &dhcp4_address))
+ dhcp4 = sd_dhcp_lease_get_server_identifier(lease, &server_address) >= 0;
+
+ r = strv_extendf(&buf, "%s%s%s%s%s%s",
+ IN_ADDR_TO_STRING(local->family, &local->address),
+ dhcp4 ? " (DHCPv4 via " : "",
+ dhcp4 ? IN4_ADDR_TO_STRING(&server_address) : "",
+ dhcp4 ? ")" : "",
+ ifindex <= 0 ? " on " : "",
+ ifindex <= 0 ? FORMAT_IFNAME_FULL(local->ifindex, FORMAT_IFNAME_IFINDEX_WITH_PERCENT) : "");
+ if (r < 0)
+ return log_oom();
+ }
+
+ return dump_list(table, "Address", buf);
+}