/* 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 "memstream-util.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>
[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);
[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);
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;
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) {
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,
union in_addr_union *addr, union in_addr_union *peer) {
Network *network;
- if (in_addr_is_null(family, addr) != 0)
+ if (!in_addr_is_set(family, addr))
return 0;
network = network_get(context, ifname);
Network *network;
int r;
- if (in_addr_is_null(family, gateway) != 0)
+ if (!in_addr_is_set(family, gateway))
return 0;
network = network_get(context, ifname);
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)
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;
}
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;
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)
return -EINVAL;
if (p != value) {
- hostname = strndupa(value, p - value);
+ hostname = strndupa_safe(value, p - value);
if (!hostname_is_valid(hostname, 0))
return -EINVAL;
}
if (!p)
return -EINVAL;
- ifname = strndupa(value, p - value);
+ ifname = strndupa_safe(value, p - value);
value = p + 1;
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)
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;
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)
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] == '[')
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 {
if (!p)
return -EINVAL;
- buf = strndupa(value, p - value);
+ buf = strndupa_safe(value, p - value);
value = p + 1;
family = AF_INET;
}
if (!p)
return -EINVAL;
- name = strndupa(value, p - value);
+ name = strndupa_safe(value, p - value);
netdev = netdev_get(context, name);
if (!netdev) {
if (!p)
return -EINVAL;
- name = strndupa(value, p - value);
+ name = strndupa_safe(value, p - value);
netdev = netdev_get(context, name);
if (!netdev) {
if (!p)
return -EINVAL;
- name = strndupa(value, p - value);
+ name = strndupa_safe(value, p - value);
netdev = netdev_get(context, name);
if (!netdev) {
if (!p)
slaves = value;
else
- slaves = strndupa(value, p - value);
+ slaves = strndupa_safe(value, p - value);
if (isempty(slaves))
return -EINVAL;
}
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;
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);
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);
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_null(address->family, &address->peer) == 0) {
- 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_null(route->family, &route->dest) == 0) {
- 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) {
- char mac[ETHER_ADDR_TO_STRING_MAX];
- Address *address;
- Route *route;
const char *dhcp;
- char **dns;
assert(network);
assert(f);
fputs("\n[Link]\n", f);
if (!ether_addr_is_null(&network->mac))
- fprintf(f, "MACAddress=%s\n", ether_addr_to_string(&network->mac, mac));
+ fprintf(f, "MACAddress=%s\n", ETHER_ADDR_TO_STR(&network->mac));
if (network->mtu > 0)
fprintf(f, "MTUBytes=%" PRIu32 "\n", network->mtu);
}
void link_dump(Link *link, FILE *f) {
- char mac[ETHER_ADDR_TO_STRING_MAX];
-
assert(link);
assert(f);
fputs("[Match]\n", f);
- if (!ether_addr_is_null(&link->mac))
- fprintf(f, "MACAddress=%s\n", ether_addr_to_string(&link->mac, mac));
+ if (!hw_addr_is_null(&link->mac))
+ fprintf(f, "MACAddress=%s\n", HW_ADDR_TO_STR(&link->mac));
+ else
+ fputs("OriginalName=*\n", f);
+
+ fputs("\n[Link]\n", f);
- fprintf(f,
- "\n[Link]\n"
- "Name=%s\n",
- link->ifname);
+ 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) {
- _cleanup_free_ char *s = NULL;
- size_t sz = 0;
- int r;
+ _cleanup_(memstream_done) MemStream m = {};
+ FILE *f;
assert(network);
assert(ret);
- {
- _cleanup_fclose_ FILE *f = NULL;
-
- f = open_memstream_unlocked(&s, &sz);
- if (!f)
- return -ENOMEM;
-
- network_dump(network, f);
-
- /* Add terminating 0, so that the output buffer is a valid string. */
- fputc('\0', f);
+ f = memstream_init(&m);
+ if (!f)
+ return -ENOMEM;
- r = fflush_and_check(f);
- }
- if (r < 0)
- return r;
+ network_dump(network, f);
- assert(s);
- *ret = TAKE_PTR(s);
- assert(sz > 0);
- return (int) sz - 1;
+ return memstream_finalize(&m, ret, NULL);
}
int netdev_format(NetDev *netdev, char **ret) {
- _cleanup_free_ char *s = NULL;
- size_t sz = 0;
- int r;
+ _cleanup_(memstream_done) MemStream m = {};
+ FILE *f;
assert(netdev);
assert(ret);
- {
- _cleanup_fclose_ FILE *f = NULL;
-
- f = open_memstream_unlocked(&s, &sz);
- if (!f)
- return -ENOMEM;
-
- netdev_dump(netdev, f);
+ f = memstream_init(&m);
+ if (!f)
+ return -ENOMEM;
- /* Add terminating 0, so that the output buffer is a valid string. */
- fputc('\0', f);
+ netdev_dump(netdev, f);
- r = fflush_and_check(f);
- }
- if (r < 0)
- return r;
-
- assert(s);
- *ret = TAKE_PTR(s);
- assert(sz > 0);
- return (int) sz - 1;
+ return memstream_finalize(&m, ret, NULL);
}
int link_format(Link *link, char **ret) {
- _cleanup_free_ char *s = NULL;
- size_t sz = 0;
- int r;
+ _cleanup_(memstream_done) MemStream m = {};
+ FILE *f;
assert(link);
assert(ret);
- {
- _cleanup_fclose_ FILE *f = NULL;
-
- f = open_memstream_unlocked(&s, &sz);
- if (!f)
- return -ENOMEM;
-
- link_dump(link, f);
-
- /* Add terminating 0, so that the output buffer is a valid string. */
- fputc('\0', f);
+ f = memstream_init(&m);
+ if (!f)
+ return -ENOMEM;
- r = fflush_and_check(f);
- }
- if (r < 0)
- return r;
+ link_dump(link, f);
- assert(s);
- *ret = TAKE_PTR(s);
- assert(sz > 0);
- return (int) sz - 1;
+ return memstream_finalize(&m, ret, NULL);
}