]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/generator/network-generator.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / network / generator / network-generator.c
index 60e074e99bfe13bc8c3cbcd837494025ccbe947a..1090934bfc15e03d00e2503b4b62a1429d7f8bf8 100644 (file)
@@ -1,11 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
-#include "ether-addr-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "hostname-util.h"
 #include "log.h"
 #include "macro.h"
+#include "netif-naming-scheme.h"
 #include "network-generator.h"
 #include "parse-util.h"
 #include "proc-cmdline.h"
 
 /*
   # .network
-  ip={dhcp|on|any|dhcp6|auto6|either6}
-  ip=<interface>:{dhcp|on|any|dhcp6|auto6}[:[<mtu>][:<macaddr>]]
-  ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}[:[<mtu>][:<macaddr>]]
-  ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}[:[<dns1>][:<dns2>]]
+  ip={dhcp|on|any|dhcp6|auto6|either6|link6}
+  ip=<interface>:{dhcp|on|any|dhcp6|auto6|link6}[:[<mtu>][:<macaddr>]]
+  ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|link6|ibft}[:[<mtu>][:<macaddr>]]
+  ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|link6|ibft}[:[<dns1>][:<dns2>]]
   rd.route=<net>/<netmask>:<gateway>[:<interface>]
   nameserver=<IP> [nameserver=<IP> ...]
   rd.peerdns=0
 
   # .link
   ifname=<interface>:<MAC>
+  net.ifname-policy=policy1[,policy2,...][,<MAC>] # This is an original rule, not supported by other tools.
 
   # .netdev
   vlan=<vlanname>:<phydevice>
@@ -46,11 +47,12 @@ static const char * const dracut_dhcp_type_table[_DHCP_TYPE_MAX] = {
         [DHCP_TYPE_OFF]     = "off",
         [DHCP_TYPE_ON]      = "on",
         [DHCP_TYPE_ANY]     = "any",
-        [DHCP_TYPE_DHCP   = "dhcp",
+        [DHCP_TYPE_DHCP4]   = "dhcp",
         [DHCP_TYPE_DHCP6]   = "dhcp6",
         [DHCP_TYPE_AUTO6]   = "auto6",
         [DHCP_TYPE_EITHER6] = "either6",
         [DHCP_TYPE_IBFT]    = "ibft",
+        [DHCP_TYPE_LINK6]   = "link6",
 };
 
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dracut_dhcp_type, DHCPType);
@@ -60,11 +62,12 @@ static const char * const networkd_dhcp_type_table[_DHCP_TYPE_MAX] = {
         [DHCP_TYPE_OFF]     = "no",
         [DHCP_TYPE_ON]      = "yes",
         [DHCP_TYPE_ANY]     = "yes",
-        [DHCP_TYPE_DHCP   = "ipv4",
+        [DHCP_TYPE_DHCP4]   = "ipv4",
         [DHCP_TYPE_DHCP6]   = "ipv6",
         [DHCP_TYPE_AUTO6]   = "no",   /* TODO: enable other setting? */
         [DHCP_TYPE_EITHER6] = "ipv6", /* TODO: enable other setting? */
         [DHCP_TYPE_IBFT]    = "no",
+        [DHCP_TYPE_LINK6]   = "no",
 };
 
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(networkd_dhcp_type, DHCPType);
@@ -262,36 +265,59 @@ static Link *link_free(Link *link) {
         if (!link)
                 return NULL;
 
+        free(link->filename);
         free(link->ifname);
+        strv_free(link->policies);
+        strv_free(link->alt_policies);
         return mfree(link);
 }
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free);
 
-static int link_new(Context *context, const char *name, struct ether_addr *mac, Link **ret) {
+static int link_new(
+                Context *context,
+                const char *name,
+                const struct hw_addr_data *mac,
+                Link **ret) {
+
         _cleanup_(link_freep) Link *link = NULL;
-        _cleanup_free_ char *ifname = NULL;
+        _cleanup_free_ char *ifname = NULL, *filename = NULL;
         int r;
 
         assert(context);
+        assert(mac);
 
-        if (!ifname_valid(name))
-                return -EINVAL;
+        if (name) {
+                if (!ifname_valid(name))
+                        return -EINVAL;
 
-        ifname = strdup(name);
-        if (!ifname)
-                return -ENOMEM;
+                ifname = strdup(name);
+                if (!ifname)
+                        return -ENOMEM;
+
+                filename = strdup(name);
+                if (!filename)
+                        return -ENOMEM;
+        }
+
+        if (!filename) {
+                filename = strdup(hw_addr_is_null(mac) ? "default" :
+                                  HW_ADDR_TO_STR_FULL(mac, HW_ADDR_TO_STRING_NO_COLON));
+                if (!filename)
+                        return -ENOMEM;
+        }
 
         link = new(Link, 1);
         if (!link)
                 return -ENOMEM;
 
         *link = (Link) {
+                .filename = TAKE_PTR(filename),
                 .ifname = TAKE_PTR(ifname),
                 .mac = *mac,
         };
 
-        r = hashmap_ensure_put(&context->links_by_name, &string_hash_ops, link->ifname, link);
+        r = hashmap_ensure_put(&context->links_by_filename, &string_hash_ops, link->filename, link);
         if (r < 0)
                 return r;
 
@@ -302,8 +328,10 @@ static int link_new(Context *context, const char *name, struct ether_addr *mac,
         return 0;
 }
 
-Link *link_get(Context *context, const char *ifname) {
-        return hashmap_get(context->links_by_name, ifname);
+Link *link_get(Context *context, const char *filename) {
+        assert(context);
+        assert(filename);
+        return hashmap_get(context->links_by_filename, filename);
 }
 
 static int network_set_dhcp_type(Context *context, const char *ifname, const char *dhcp_type) {
@@ -353,7 +381,7 @@ static int network_set_mac_address(Context *context, const char *ifname, const c
         if (!network)
                 return -ENODEV;
 
-        return ether_addr_from_string(mac, &network->mac);
+        return parse_ether_addr(mac, &network->mac);
 }
 
 static int network_set_address(Context *context, const char *ifname, int family, unsigned char prefixlen,
@@ -475,7 +503,7 @@ static int parse_cmdline_ip_mtu_mac(Context *context, const char *ifname, int fa
         if (!p)
                 mtu = value;
         else
-                mtu = strndupa(value, p - value);
+                mtu = strndupa_safe(value, p - value);
 
         r = network_set_mtu(context, ifname, family, mtu);
         if (r < 0)
@@ -511,14 +539,14 @@ static int parse_ip_address_one(int family, const char **value, union in_addr_un
                 if (q[1] != ':')
                         return -EINVAL;
 
-                buf = strndupa(p + 1, q - p - 1);
+                buf = strndupa_safe(p + 1, q - p - 1);
                 p = q + 2;
         } else {
                 q = strchr(p, ':');
                 if (!q)
                         return -EINVAL;
 
-                buf = strndupa(p, q - p);
+                buf = strndupa_safe(p, q - p);
                 p = q + 1;
         }
 
@@ -549,7 +577,7 @@ static int parse_netmask_or_prefixlen(int family, const char **value, unsigned c
                 if (!p)
                         return -EINVAL;
 
-                q = strndupa(*value, p - *value);
+                q = strndupa_safe(*value, p - *value);
                 r = safe_atou8(q, ret);
                 if (r < 0)
                         return r;
@@ -566,8 +594,8 @@ static int parse_cmdline_ip_address(Context *context, int family, const char *va
         unsigned char prefixlen;
         int r;
 
-        /* ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}[:[<mtu>][:<macaddr>]]
-         * ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}[:[<dns1>][:<dns2>]] */
+        /* ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft|link6}[:[<mtu>][:<macaddr>]]
+         * ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft|link6}[:[<dns1>][:<dns2>]] */
 
         r = parse_ip_address_one(family, &value, &addr);
         if (r < 0)
@@ -588,7 +616,7 @@ static int parse_cmdline_ip_address(Context *context, int family, const char *va
                 return -EINVAL;
 
         if (p != value) {
-                hostname = strndupa(value, p - value);
+                hostname = strndupa_safe(value, p - value);
                 if (!hostname_is_valid(hostname, 0))
                         return -EINVAL;
         }
@@ -600,7 +628,7 @@ static int parse_cmdline_ip_address(Context *context, int family, const char *va
         if (!p)
                 return -EINVAL;
 
-        ifname = strndupa(value, p - value);
+        ifname = strndupa_safe(value, p - value);
 
         value = p + 1;
 
@@ -609,7 +637,7 @@ static int parse_cmdline_ip_address(Context *context, int family, const char *va
         if (!p)
                 dhcp_type = value;
         else
-                dhcp_type = strndupa(value, p - value);
+                dhcp_type = strndupa_safe(value, p - value);
 
         r = network_set_dhcp_type(context, ifname, dhcp_type);
         if (r < 0)
@@ -644,7 +672,7 @@ static int parse_cmdline_ip_address(Context *context, int family, const char *va
                 if (r < 0)
                         return r;
         } else {
-                dns = strndupa(value, p - value);
+                dns = strndupa_safe(value, p - value);
                 r = network_set_dns(context, ifname, dns);
                 if (r < 0)
                         return r;
@@ -660,20 +688,20 @@ static int parse_cmdline_ip_interface(Context *context, const char *value) {
         const char *ifname, *dhcp_type, *p;
         int r;
 
-        /* ip=<interface>:{dhcp|on|any|dhcp6|auto6}[:[<mtu>][:<macaddr>]] */
+        /* ip=<interface>:{dhcp|on|any|dhcp6|auto6|link6}[:[<mtu>][:<macaddr>]] */
 
         p = strchr(value, ':');
         if (!p)
                 return -EINVAL;
 
-        ifname = strndupa(value, p - value);
+        ifname = strndupa_safe(value, p - value);
 
         value = p + 1;
         p = strchr(value, ':');
         if (!p)
                 dhcp_type = value;
         else
-                dhcp_type = strndupa(value, p - value);
+                dhcp_type = strndupa_safe(value, p - value);
 
         r = network_set_dhcp_type(context, ifname, dhcp_type);
         if (r < 0)
@@ -694,7 +722,7 @@ static int parse_cmdline_ip(Context *context, const char *key, const char *value
 
         p = strchr(value, ':');
         if (!p)
-                /* ip={dhcp|on|any|dhcp6|auto6|either6} */
+                /* ip={dhcp|on|any|dhcp6|auto6|either6|link6} */
                 return network_set_dhcp_type(context, "", value);
 
         if (value[0] == '[')
@@ -726,7 +754,7 @@ static int parse_cmdline_rd_route(Context *context, const char *key, const char
                 if (p[1] != ':')
                         return -EINVAL;
 
-                buf = strndupa(value + 1, p - value - 1);
+                buf = strndupa_safe(value + 1, p - value - 1);
                 value = p + 2;
                 family = AF_INET6;
         } else {
@@ -734,7 +762,7 @@ static int parse_cmdline_rd_route(Context *context, const char *key, const char
                 if (!p)
                         return -EINVAL;
 
-                buf = strndupa(value, p - value);
+                buf = strndupa_safe(value, p - value);
                 value = p + 1;
                 family = AF_INET;
         }
@@ -786,7 +814,7 @@ static int parse_cmdline_vlan(Context *context, const char *key, const char *val
         if (!p)
                 return -EINVAL;
 
-        name = strndupa(value, p - value);
+        name = strndupa_safe(value, p - value);
 
         netdev = netdev_get(context, name);
         if (!netdev) {
@@ -810,7 +838,7 @@ static int parse_cmdline_bridge(Context *context, const char *key, const char *v
         if (!p)
                 return -EINVAL;
 
-        name = strndupa(value, p - value);
+        name = strndupa_safe(value, p - value);
 
         netdev = netdev_get(context, name);
         if (!netdev) {
@@ -848,7 +876,7 @@ static int parse_cmdline_bond(Context *context, const char *key, const char *val
         if (!p)
                 return -EINVAL;
 
-        name = strndupa(value, p - value);
+        name = strndupa_safe(value, p - value);
 
         netdev = netdev_get(context, name);
         if (!netdev) {
@@ -862,7 +890,7 @@ static int parse_cmdline_bond(Context *context, const char *key, const char *val
         if (!p)
                 slaves = value;
         else
-                slaves = strndupa(value, p - value);
+                slaves = strndupa_safe(value, p - value);
 
         if (isempty(slaves))
                 return -EINVAL;
@@ -894,7 +922,7 @@ static int parse_cmdline_bond(Context *context, const char *key, const char *val
 }
 
 static int parse_cmdline_ifname(Context *context, const char *key, const char *value) {
-        struct ether_addr mac;
+        struct hw_addr_data mac;
         const char *name, *p;
         int r;
 
@@ -907,20 +935,78 @@ static int parse_cmdline_ifname(Context *context, const char *key, const char *v
         if (!p)
                 return -EINVAL;
 
-        name = strndupa(value, p - value);
+        name = strndupa_safe(value, p - value);
 
-        r = ether_addr_from_string(p + 1, &mac);
+        r = parse_hw_addr(p + 1, &mac);
         if (r < 0)
                 return r;
 
         return link_new(context, name, &mac, NULL);
 }
 
+static int parse_cmdline_ifname_policy(Context *context, const char *key, const char *value) {
+        _cleanup_strv_free_ char **policies = NULL, **alt_policies = NULL;
+        struct hw_addr_data mac = HW_ADDR_NULL;
+        Link *link;
+        int r;
+
+        /* net.ifname-policy=policy1[,policy2,...][,<MAC>] */
+
+        if (proc_cmdline_value_missing(key, value))
+                return -EINVAL;
+
+        for (const char *q = value; ; ) {
+                _cleanup_free_ char *word = NULL;
+                NamePolicy p;
+
+                r = extract_first_word(&q, &word, ",", 0);
+                if (r == 0)
+                        break;
+                if (r < 0)
+                        return r;
+
+                p = name_policy_from_string(word);
+                if (p < 0) {
+                        r = parse_hw_addr(word, &mac);
+                        if (r < 0)
+                                return r;
+
+                        if (hw_addr_is_null(&mac))
+                                return -EINVAL;
+
+                        if (!isempty(q))
+                                return -EINVAL;
+
+                        break;
+                }
+
+                if (alternative_names_policy_from_string(word) >= 0) {
+                        r = strv_extend(&alt_policies, word);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = strv_consume(&policies, TAKE_PTR(word));
+                if (r < 0)
+                        return r;
+        }
+
+        if (strv_isempty(policies))
+                return -EINVAL;
+
+        r = link_new(context, NULL, &mac, &link);
+        if (r < 0)
+                return r;
+
+        link->policies = TAKE_PTR(policies);
+        link->alt_policies = TAKE_PTR(alt_policies);
+        return 0;
+}
+
 int parse_cmdline_item(const char *key, const char *value, void *data) {
-        Context *context = data;
+        Context *context = ASSERT_PTR(data);
 
         assert(key);
-        assert(data);
 
         if (streq(key, "ip"))
                 return parse_cmdline_ip(context, key, value);
@@ -938,13 +1024,14 @@ int parse_cmdline_item(const char *key, const char *value, void *data) {
                 return parse_cmdline_bond(context, key, value);
         if (streq(key, "ifname"))
                 return parse_cmdline_ifname(context, key, value);
+        if (streq(key, "net.ifname-policy"))
+                return parse_cmdline_ifname_policy(context, key, value);
 
         return 0;
 }
 
 int context_merge_networks(Context *context) {
         Network *all, *network;
-        Route *route;
         int r;
 
         assert(context);
@@ -989,61 +1076,33 @@ void context_clear(Context *context) {
 
         hashmap_free_with_destructor(context->networks_by_name, network_free);
         hashmap_free_with_destructor(context->netdevs_by_name, netdev_free);
-        hashmap_free_with_destructor(context->links_by_name, link_free);
+        hashmap_free_with_destructor(context->links_by_filename, link_free);
 }
 
 static int address_dump(Address *address, FILE *f) {
-        _cleanup_free_ char *addr = NULL, *peer = NULL;
-        int r;
-
-        r = in_addr_prefix_to_string(address->family, &address->address, address->prefixlen, &addr);
-        if (r < 0)
-                return r;
-
-        if (in_addr_is_set(address->family, &address->peer)) {
-                r = in_addr_to_string(address->family, &address->peer, &peer);
-                if (r < 0)
-                        return r;
-        }
-
         fprintf(f,
                 "\n[Address]\n"
                 "Address=%s\n",
-                addr);
-
-        if (peer)
-                fprintf(f, "Peer=%s\n", peer);
-
+                IN_ADDR_PREFIX_TO_STRING(address->family, &address->address, address->prefixlen));
+        if (in_addr_is_set(address->family, &address->peer))
+                fprintf(f, "Peer=%s\n",
+                        IN_ADDR_TO_STRING(address->family, &address->peer));
         return 0;
 }
 
 static int route_dump(Route *route, FILE *f) {
-        _cleanup_free_ char *dest = NULL, *gateway = NULL;
-        int r;
-
-        if (in_addr_is_set(route->family, &route->dest)) {
-                r = in_addr_prefix_to_string(route->family, &route->dest, route->prefixlen, &dest);
-                if (r < 0)
-                        return r;
-        }
-
-        r = in_addr_to_string(route->family, &route->gateway, &gateway);
-        if (r < 0)
-                return r;
-
         fputs("\n[Route]\n", f);
-        if (dest)
-                fprintf(f, "Destination=%s\n", dest);
-        fprintf(f, "Gateway=%s\n", gateway);
+        if (in_addr_is_set(route->family, &route->dest))
+                fprintf(f, "Destination=%s\n",
+                        IN_ADDR_PREFIX_TO_STRING(route->family, &route->dest, route->prefixlen));
+        fprintf(f, "Gateway=%s\n",
+                IN_ADDR_TO_STRING(route->family, &route->gateway));
 
         return 0;
 }
 
 void network_dump(Network *network, FILE *f) {
-        Address *address;
-        Route *route;
         const char *dhcp;
-        char **dns;
 
         assert(network);
         assert(f);
@@ -1115,13 +1174,27 @@ void link_dump(Link *link, FILE *f) {
 
         fputs("[Match]\n", f);
 
-        if (!ether_addr_is_null(&link->mac))
-                fprintf(f, "MACAddress=%s\n", ETHER_ADDR_TO_STR(&link->mac));
+        if (!hw_addr_is_null(&link->mac))
+                fprintf(f, "MACAddress=%s\n", HW_ADDR_TO_STR(&link->mac));
+        else
+                fputs("OriginalName=*\n", f);
 
-        fprintf(f,
-                "\n[Link]\n"
-                "Name=%s\n",
-                link->ifname);
+        fputs("\n[Link]\n", f);
+
+        if (!isempty(link->ifname))
+                fprintf(f, "Name=%s\n", link->ifname);
+
+        if (!strv_isempty(link->policies)) {
+                fputs("NamePolicy=", f);
+                fputstrv(f, link->policies, " ", NULL);
+                fputc('\n', f);
+        }
+
+        if (!strv_isempty(link->alt_policies)) {
+                fputs("AlternativeNamesPolicy=", f);
+                fputstrv(f, link->alt_policies, " ", NULL);
+                fputc('\n', f);
+        }
 }
 
 int network_format(Network *network, char **ret) {