diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-08-21 08:31:57 +0200 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-08-21 18:12:39 +0200 |
commit | 1bf49198b5ce8c5a68d32b722497bf22be2b1f8b (patch) | |
tree | c34c857c27c7025d18426cbeb5d34db5c6c91512 /src/network/networkctl-dump-util.c | |
parent | Merge pull request #33498 from DaanDeMeyer/btrfs (diff) | |
download | systemd-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.c | 242 |
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); +} |