]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: Show network and link file dropins in networkctl status
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 30 Nov 2022 15:13:23 +0000 (16:13 +0100)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 12 Jan 2023 04:44:52 +0000 (13:44 +0900)
Fixes #24428

src/libsystemd/sd-network/sd-network.c
src/network/networkctl.c
src/network/networkd-json.c
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-state-file.c
src/systemd/sd-network.h
src/udev/net/link-config.c
src/udev/net/link-config.h
src/udev/udev-builtin-net_setup_link.c
test/networkd-test.py

index 56de3f965c4a05e0a1513cd193f9485137623f86..dd440a5d17d924feaa9e0db4753988ebafe542cf 100644 (file)
@@ -159,6 +159,25 @@ int sd_network_link_get_network_file(int ifindex, char **ret) {
         return network_link_get_string(ifindex, "NETWORK_FILE", ret);
 }
 
+int sd_network_link_get_network_file_dropins(int ifindex, char ***ret) {
+        _cleanup_free_ char **sv = NULL, *joined = NULL;
+        int r;
+
+        assert_return(ifindex > 0, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = network_link_get_string(ifindex, "NETWORK_FILE_DROPINS", &joined);
+        if (r < 0)
+                return r;
+
+        r = strv_split_full(&sv, joined, ":", EXTRACT_CUNESCAPE);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(sv);
+        return 0;
+}
+
 int sd_network_link_get_operational_state(int ifindex, char **ret) {
         return network_link_get_string(ifindex, "OPER_STATE", ret);
 }
index 357d38f5ea64518765aed3d93fd4b8987859fe8b..65015b132f0322f61c7082af26ffcd4407a9588d 100644 (file)
@@ -1536,13 +1536,29 @@ static int table_add_string_line(Table *table, const char *key, const char *valu
         return 0;
 }
 
+static int format_dropins(char **dropins) {
+        STRV_FOREACH(d, dropins) {
+                _cleanup_free_ char *s = NULL;
+                int glyph = *(d + 1) == NULL ? SPECIAL_GLYPH_TREE_RIGHT : SPECIAL_GLYPH_TREE_BRANCH;
+
+                s = strjoin(special_glyph(glyph), *d);
+                if (!s)
+                        return log_oom();
+
+                free_and_replace(*d, s);
+        }
+
+        return 0;
+}
+
 static int link_status_one(
                 sd_bus *bus,
                 sd_netlink *rtnl,
                 sd_hwdb *hwdb,
                 const LinkInfo *info) {
 
-        _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL;
+        _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL,
+                **route_domains = NULL, **link_dropins = NULL, **network_dropins = NULL;
         _cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL,
                 *setup_state = NULL, *operational_state = NULL, *online_state = NULL, *activation_policy = NULL;
         const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL,
@@ -1571,12 +1587,22 @@ static int link_status_one(
         (void) sd_network_link_get_ntp(info->ifindex, &ntp);
         (void) sd_network_link_get_sip(info->ifindex, &sip);
         (void) sd_network_link_get_network_file(info->ifindex, &network);
+        (void) sd_network_link_get_network_file_dropins(info->ifindex, &network_dropins);
         (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
         (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
         (void) sd_network_link_get_activation_policy(info->ifindex, &activation_policy);
 
         if (info->sd_device) {
+                const char *joined;
+
                 (void) sd_device_get_property_value(info->sd_device, "ID_NET_LINK_FILE", &link);
+
+                if (sd_device_get_property_value(info->sd_device, "ID_NET_LINK_FILE_DROPINS", &joined) >= 0) {
+                        r = strv_split_full(&link_dropins, joined, ":", EXTRACT_CUNESCAPE);
+                        if (r < 0)
+                                return r;
+                }
+
                 (void) sd_device_get_property_value(info->sd_device, "ID_NET_DRIVER", &driver);
                 (void) sd_device_get_property_value(info->sd_device, "ID_PATH", &path);
 
@@ -1596,6 +1622,20 @@ static int link_status_one(
 
         (void) dhcp_lease_load(&lease, lease_file);
 
+        r = format_dropins(network_dropins);
+        if (r < 0)
+                return r;
+
+        if (strv_prepend(&network_dropins, network) < 0)
+                return log_oom();
+
+        r = format_dropins(link_dropins);
+        if (r < 0)
+                return r;
+
+        if (strv_prepend(&link_dropins, link) < 0)
+                return log_oom();
+
         table = table_new("dot", "key", "value");
         if (!table)
                 return log_oom();
@@ -1631,10 +1671,10 @@ static int link_status_one(
                            TABLE_EMPTY,
                            TABLE_STRING, "Link File:",
                            TABLE_SET_ALIGN_PERCENT, 100,
-                           TABLE_STRING, strna(link),
+                           TABLE_STRV, link_dropins ?: STRV_MAKE("n/a"),
                            TABLE_EMPTY,
                            TABLE_STRING, "Network File:",
-                           TABLE_STRING, strna(network),
+                           TABLE_STRV, network_dropins ?: STRV_MAKE("n/a"),
                            TABLE_EMPTY,
                            TABLE_STRING, "State:");
         if (r < 0)
index 9e2ff33d970ce2560f136fc2ebbd556d248778b4..c37f734d619428abcf3257dc7c178284874b2e95 100644 (file)
@@ -464,6 +464,7 @@ static int network_build_json(Network *network, JsonVariant **ret) {
 
         return json_build(ret, JSON_BUILD_OBJECT(
                                 JSON_BUILD_PAIR_STRING("NetworkFile", network->filename),
+                                JSON_BUILD_PAIR_STRV("NetworkFileDropins", network->dropins),
                                 JSON_BUILD_PAIR_BOOLEAN("RequiredForOnline", network->required_for_online),
                                 JSON_BUILD_PAIR("RequiredOperationalStateForOnline",
                                                 JSON_BUILD_ARRAY(JSON_BUILD_STRING(link_operstate_to_string(network->required_operstate_for_online.min)),
@@ -475,7 +476,9 @@ static int network_build_json(Network *network, JsonVariant **ret) {
 }
 
 static int device_build_json(sd_device *device, JsonVariant **ret) {
-        const char *link = NULL, *path = NULL, *vendor = NULL, *model = NULL;
+        _cleanup_strv_free_ char **link_dropins = NULL;
+        const char *link = NULL, *path = NULL, *vendor = NULL, *model = NULL, *joined;
+        int r;
 
         assert(ret);
 
@@ -485,6 +488,13 @@ static int device_build_json(sd_device *device, JsonVariant **ret) {
         }
 
         (void) sd_device_get_property_value(device, "ID_NET_LINK_FILE", &link);
+
+        if (sd_device_get_property_value(device, "ID_NET_LINK_FILE_DROPINS", &joined) >= 0) {
+                 r = strv_split_full(&link_dropins, joined, ":", EXTRACT_CUNESCAPE);
+                 if (r < 0)
+                        return r;
+        }
+
         (void) sd_device_get_property_value(device, "ID_PATH", &path);
 
         if (sd_device_get_property_value(device, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
@@ -495,6 +505,7 @@ static int device_build_json(sd_device *device, JsonVariant **ret) {
 
         return json_build(ret, JSON_BUILD_OBJECT(
                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("LinkFile", link),
+                                JSON_BUILD_PAIR_STRV_NON_EMPTY("LinkFileDropins", link_dropins),
                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("Path", path),
                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("Vendor", vendor),
                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("Model", model)));
index d516918c786e6e2b3ec5a6b805447df36c007dfb..d881889316868f8fa7d8a1e6b0c2bc5dcc6fc633 100644 (file)
@@ -552,7 +552,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                         CONFIG_PARSE_WARN,
                         network,
                         &network->stats_by_path,
-                        NULL);
+                        &network->dropins);
         if (r < 0)
                 return r; /* config_parse_many() logs internally. */
 
@@ -670,6 +670,7 @@ static Network *network_free(Network *network) {
         free(network->name);
         free(network->filename);
         free(network->description);
+        strv_free(network->dropins);
         hashmap_free(network->stats_by_path);
 
         /* conditions */
index 09f0e9beea007341766751cfcfc413018de03964..fbeec6072ef0abe900b37e1186db036c05b1df8e 100644 (file)
@@ -65,6 +65,7 @@ struct Network {
 
         char *name;
         char *filename;
+        char **dropins;
         Hashmap *stats_by_path;
         char *description;
 
index 0800e91202b4d23f058f88c4ca04d92da8d5817e..6e962c03f64eb8d045a252b38957ba806437c129 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "alloc-util.h"
 #include "dns-domain.h"
+#include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
@@ -515,7 +516,7 @@ int link_save(Link *link) {
 
         if (link->network) {
                 const char *online_state;
-                bool space;
+                bool space = false;
 
                 online_state = link_online_state_to_string(link->online_state);
                 if (online_state)
@@ -538,6 +539,18 @@ int link_save(Link *link) {
 
                 fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
 
+                fputs("NETWORK_FILE_DROPINS=\"", f);
+                STRV_FOREACH(d, link->network->dropins) {
+                        _cleanup_free_ char *escaped = NULL;
+
+                        escaped = xescape(*d, ":");
+                        if (!escaped)
+                                return -ENOMEM;
+
+                        fputs_with_space(f, escaped, ":", &space);
+                }
+                fputs("\"\n", f);
+
                 /************************************************************/
 
                 fputs("DNS=", f);
index b89e035fd64779d4a9be8743947425f11c62a238..9cc2cbaa6ec0ba125f52eeeabc43dcfd6fd82696 100644 (file)
@@ -119,6 +119,9 @@ int sd_network_link_get_activation_policy(int ifindex, char **ret);
 /* Get path to .network file applied to link */
 int sd_network_link_get_network_file(int ifindex, char **ret);
 
+/* Get paths to .network file dropins applied to link */
+int sd_network_link_get_network_file_dropins(int ifindex, char ***ret);
+
 /* Get DNS entries for a given link. These are string representations of
  * IP addresses */
 int sd_network_link_get_dns(int ifindex, char ***ret);
index 5f18ba35fc38b4ae9ea9564e9e8b17b96a6e4b3b..9efdb6000accc6383834f4eab2052f34a9d719df 100644 (file)
@@ -47,6 +47,7 @@ static LinkConfig* link_config_free(LinkConfig *config) {
                 return NULL;
 
         free(config->filename);
+        strv_free(config->dropins);
 
         net_match_clear(&config->match);
         condition_free_list(config->conditions);
@@ -264,7 +265,7 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
                         "SR-IOV\0",
                         config_item_perf_lookup, link_config_gperf_lookup,
                         CONFIG_PARSE_WARN, config, &stats_by_path,
-                        NULL);
+                        &config->dropins);
         if (r < 0)
                 return r; /* config_parse_many() logs internally. */
 
index ea9f560f45ee6c3bbb0a772d7eb9701a7e635f92..ed0896e9dee83b4b8ea085b9de0326a492ca82c4 100644 (file)
@@ -44,6 +44,7 @@ typedef struct Link {
 
 struct LinkConfig {
         char *filename;
+        char **dropins;
 
         NetMatch match;
         LIST_HEAD(Condition, conditions);
index ea7b1c5f602260a22c1cc67c6d93a19df0adfc5e..18450536b5caefb3d0c39460d88efcc6b652978b 100644 (file)
@@ -2,16 +2,19 @@
 
 #include "alloc-util.h"
 #include "device-util.h"
+#include "escape.h"
 #include "errno-util.h"
 #include "link-config.h"
 #include "log.h"
 #include "string-util.h"
+#include "strv.h"
 #include "udev-builtin.h"
 
 static LinkConfigContext *ctx = NULL;
 
 static int builtin_net_setup_link(sd_device *dev, sd_netlink **rtnl, int argc, char **argv, bool test) {
         _cleanup_(link_freep) Link *link = NULL;
+        _cleanup_free_ char *joined = NULL;
         int r;
 
         if (argc > 1)
@@ -48,6 +51,19 @@ static int builtin_net_setup_link(sd_device *dev, sd_netlink **rtnl, int argc, c
         if (link->new_name)
                 udev_builtin_add_property(dev, test, "ID_NET_NAME", link->new_name);
 
+        STRV_FOREACH(d, link->config->dropins) {
+                _cleanup_free_ char *escaped = NULL;
+
+                escaped = xescape(*d, ":");
+                if (!escaped)
+                        return log_oom();
+
+                if (!strextend_with_separator(&joined, ":", escaped))
+                        return log_oom();
+        }
+
+        udev_builtin_add_property(dev, test, "ID_NET_LINK_FILE_DROPINS", joined);
+
         return 0;
 }
 
index 0a5ba11f89e08e6a4439306a518236d370102288..9e7233d39bb16888f8a5e07d73ead2ef300e5f7a 100755 (executable)
@@ -992,6 +992,9 @@ DNS=127.0.0.1
         self.assertIn('nameserver 192.168.42.1\n', contents)
         self.assertIn('nameserver 127.0.0.1\n', contents)
 
+        out = subprocess.check_output(['networkctl', 'status', 'dummy0'])
+        self.assertIn(b'test.network.d/dns.conf', out)
+
     def test_dhcp_timezone(self):
         '''networkd sets time zone from DHCP'''