mirror of
https://github.com/systemd/systemd.git
synced 2025-01-16 03:24:49 +03:00
networkd: add support for address label
IPv6 address labels are used for address selection; they are described in RFC 3484. Precedence is managed by userspace, and only the label itself is stored in the kernel. enp0s25.network [Match] Name=enp0s25 [Network] DHCP=yes Address = 2001:db8:f00:baa::b [AddressLabel] Label=199 Prefix=2001:db8:41::/64 [AddressLabel] Label=11 Prefix=2001:db8:31::/64 [AddressLabel] Label=123 Prefix=2001:db8:21::/64 [AddressLabel] Label=124 Prefix=2001:db8:11::/64 [sus@maximus label]$ ip addrlabel list prefix ::1/128 label 0 prefix ::/96 label 3 prefix ::ffff:0.0.0.0/96 label 4 prefix 2001:db8:41::/64 dev enp0s25 label 199 prefix 2001:db8:31::/64 dev enp0s25 label 11 prefix 2001:db8:21::/64 dev enp0s25 label 123 prefix 2001:db8:11::/64 dev enp0s25 label 124 prefix 2001::/32 label 6 prefix 2001:10::/28 label 7 prefix 3ffe::/16 label 12 prefix 2002::/16 label 2 prefix fec0::/10 label 11 prefix fc00::/7 label 5 prefix ::/0 label 1
This commit is contained in:
parent
30746d6088
commit
95b74ef6ea
@ -5812,6 +5812,8 @@ libnetworkd_core_la_SOURCES = \
|
||||
src/network/networkd-network-bus.c \
|
||||
src/network/networkd-address.h \
|
||||
src/network/networkd-address.c \
|
||||
src/network/networkd-address-label.h \
|
||||
src/network/networkd-address-label.c \
|
||||
src/network/networkd-route.h \
|
||||
src/network/networkd-route.c \
|
||||
src/network/networkd-fdb.h \
|
||||
|
@ -796,6 +796,33 @@
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[IPv6AddressLabel] Section Options</title>
|
||||
|
||||
<para>An <literal>[IPv6AddressLabel]</literal> section accepts the
|
||||
following keys. Specify several <literal>[IPv6AddressLabel]</literal>
|
||||
sections to configure several addresse labels. IPv6 address labels are
|
||||
used for address selection. See <ulink url="https://tools.ietf.org/html/rfc3484">RFC 3484</ulink>.
|
||||
Precedence is managed by userspace, and only the label itself is stored in the kernel</para>
|
||||
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>Label=</varname></term>
|
||||
<listitem>
|
||||
<para> The label for the prefix (an unsigned integer) ranges 0 to 4294967294.
|
||||
0xffffffff is reserved. This key is mandatory.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>Prefix=</varname></term>
|
||||
<listitem>
|
||||
<para>IPv6 prefix is an address with a prefix length, separated by a slash <literal>/</literal> character.
|
||||
This key is mandatory. </para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[Route] Section Options</title>
|
||||
<para>The <literal>[Route]</literal> section accepts the
|
||||
|
257
src/network/networkd-address-label.c
Normal file
257
src/network/networkd-address-label.c
Normal file
@ -0,0 +1,257 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2017 Susant Sahani
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/if.h>
|
||||
#include <linux/if_addrlabel.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "networkd-address-label.h"
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "parse-util.h"
|
||||
#include "socket-util.h"
|
||||
|
||||
int address_label_new(AddressLabel **ret) {
|
||||
_cleanup_address_label_free_ AddressLabel *addrlabel = NULL;
|
||||
|
||||
addrlabel = new0(AddressLabel, 1);
|
||||
if (!addrlabel)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = addrlabel;
|
||||
addrlabel = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void address_label_free(AddressLabel *label) {
|
||||
if (!label)
|
||||
return;
|
||||
|
||||
if (label->network) {
|
||||
LIST_REMOVE(labels, label->network->address_labels, label);
|
||||
assert(label->network->n_address_labels > 0);
|
||||
label->network->n_address_labels--;
|
||||
|
||||
if (label->section) {
|
||||
hashmap_remove(label->network->address_labels_by_section, label->section);
|
||||
network_config_section_free(label->section);
|
||||
}
|
||||
}
|
||||
|
||||
free(label);
|
||||
}
|
||||
|
||||
static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) {
|
||||
_cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
|
||||
_cleanup_address_label_free_ AddressLabel *label = NULL;
|
||||
int r;
|
||||
|
||||
assert(network);
|
||||
assert(ret);
|
||||
assert(!!filename == (section_line > 0));
|
||||
|
||||
r = network_config_section_new(filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
label = hashmap_get(network->address_labels_by_section, n);
|
||||
if (label) {
|
||||
*ret = label;
|
||||
label = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = address_label_new(&label);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
label->section = n;
|
||||
n = NULL;
|
||||
|
||||
r = hashmap_put(network->address_labels_by_section, label->section, label);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
label->network = network;
|
||||
LIST_APPEND(labels, network->address_labels, label);
|
||||
network->n_address_labels++;
|
||||
|
||||
*ret = label;
|
||||
label = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int address_label_configure(
|
||||
AddressLabel *label,
|
||||
Link *link,
|
||||
sd_netlink_message_handler_t callback,
|
||||
bool update) {
|
||||
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
int r;
|
||||
|
||||
assert(label);
|
||||
assert(link);
|
||||
assert(link->ifindex > 0);
|
||||
assert(link->manager);
|
||||
assert(link->manager->rtnl);
|
||||
|
||||
r = sd_rtnl_message_new_addrlabel(link->manager->rtnl, &req, RTM_NEWADDRLABEL,
|
||||
link->ifindex, label->family);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
|
||||
|
||||
r = sd_rtnl_message_addrlabel_set_prefixlen(req, label->prefixlen);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not set prefixlen: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(req, IFAL_LABEL, label->label);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append IFAL_LABEL attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &label->in_addr.in6);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
|
||||
|
||||
r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not send rtnetlink message: %m");
|
||||
|
||||
link_ref(link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_address_label_prefix(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_address_label_free_ AddressLabel *n = NULL;
|
||||
Network *network = userdata;
|
||||
const char *prefix, *e;
|
||||
union in_addr_union buffer;
|
||||
int r, f;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = address_label_new_static(network, filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* AddressLabel=prefix/prefixlen */
|
||||
|
||||
/* prefixlen */
|
||||
e = strchr(rvalue, '/');
|
||||
if (e) {
|
||||
unsigned i;
|
||||
|
||||
r = safe_atou(e + 1, &i);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i > 128) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is out of range, ignoring assignment: %s", e + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n->prefixlen = (unsigned char) i;
|
||||
|
||||
prefix = strndupa(rvalue, e - rvalue);
|
||||
} else
|
||||
prefix = rvalue;
|
||||
|
||||
r = in_addr_from_string_auto(prefix, &f, &buffer);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Address label is invalid, ignoring assignment: %s", prefix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (f != AF_INET6) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Address label family is not IPv6, ignoring assignment: %s", prefix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n->family = f;
|
||||
n->in_addr = buffer;
|
||||
|
||||
n = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_address_label(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_address_label_free_ AddressLabel *n = NULL;
|
||||
Network *network = userdata;
|
||||
uint32_t k;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = address_label_new_static(network, filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = safe_atou32(rvalue, &k);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address label, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (k == 0xffffffffUL) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Adress label is invalid, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n->label = k;
|
||||
n = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
59
src/network/networkd-address-label.h
Normal file
59
src/network/networkd-address-label.h
Normal file
@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2017 Susant Sahani
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "in-addr-util.h"
|
||||
|
||||
typedef struct AddressLabel AddressLabel;
|
||||
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-network.h"
|
||||
|
||||
typedef struct Network Network;
|
||||
typedef struct Link Link;
|
||||
typedef struct NetworkConfigSection NetworkConfigSection;
|
||||
|
||||
struct AddressLabel {
|
||||
Network *network;
|
||||
Link *link;
|
||||
NetworkConfigSection *section;
|
||||
|
||||
int family;
|
||||
unsigned char prefixlen;
|
||||
uint32_t label;
|
||||
|
||||
union in_addr_union in_addr;
|
||||
|
||||
LIST_FIELDS(AddressLabel, labels);
|
||||
};
|
||||
|
||||
int address_label_new(AddressLabel **ret);
|
||||
void address_label_free(AddressLabel *label);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(AddressLabel*, address_label_free);
|
||||
#define _cleanup_address_label_free_ _cleanup_(address_label_freep)
|
||||
|
||||
int address_label_configure(AddressLabel *address, Link *link, sd_netlink_message_handler_t callback, bool update);
|
||||
|
||||
int config_parse_address_label(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_address_label_prefix(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
@ -853,6 +853,35 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
||||
_cleanup_link_unref_ Link *link = userdata;
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(m);
|
||||
assert(link);
|
||||
assert(link->ifname);
|
||||
assert(link->link_messages > 0);
|
||||
|
||||
link->link_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
log_link_warning_errno(link, r, "could not set address label: %m");
|
||||
else if (r >= 0)
|
||||
manager_rtnl_process_address(rtnl, m, link->manager);
|
||||
|
||||
if (link->link_messages == 0) {
|
||||
log_link_debug(link, "Addresses label set");
|
||||
link_enter_set_routes(link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_push_uplink_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
|
||||
_cleanup_free_ struct in_addr *addresses = NULL;
|
||||
size_t n_addresses = 0, n_allocated = 0;
|
||||
@ -965,6 +994,7 @@ static int link_set_bridge_fdb(Link *link) {
|
||||
}
|
||||
|
||||
static int link_enter_set_addresses(Link *link) {
|
||||
AddressLabel *label;
|
||||
Address *ad;
|
||||
int r;
|
||||
|
||||
@ -989,6 +1019,17 @@ static int link_enter_set_addresses(Link *link) {
|
||||
link->link_messages++;
|
||||
}
|
||||
|
||||
LIST_FOREACH(labels, label, link->network->address_labels) {
|
||||
r = address_label_configure(label, link, address_label_handler, false);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not set address label: %m");
|
||||
link_enter_failed(link);
|
||||
return r;
|
||||
}
|
||||
|
||||
link->link_messages++;
|
||||
}
|
||||
|
||||
/* now that we can figure out a default address for the dhcp server,
|
||||
start it */
|
||||
if (link_dhcp4_server_enabled(link)) {
|
||||
|
@ -79,6 +79,8 @@ Address.DuplicateAddressDetection, config_parse_address_flags,
|
||||
Address.ManageTemporaryAddress, config_parse_address_flags, 0, 0
|
||||
Address.PrefixRoute, config_parse_address_flags, 0, 0
|
||||
Address.AutoJoin, config_parse_address_flags, 0, 0
|
||||
IPv6AddressLabel.Prefix, config_parse_address_label_prefix, 0, 0
|
||||
IPv6AddressLabel.Label, config_parse_address_label, 0, 0
|
||||
Route.Gateway, config_parse_gateway, 0, 0
|
||||
Route.Destination, config_parse_destination, 0, 0
|
||||
Route.Source, config_parse_destination, 0, 0
|
||||
|
@ -114,6 +114,7 @@ static int network_load_one(Manager *manager, const char *filename) {
|
||||
LIST_HEAD_INIT(network->static_routes);
|
||||
LIST_HEAD_INIT(network->static_fdb_entries);
|
||||
LIST_HEAD_INIT(network->ipv6_proxy_ndp_addresses);
|
||||
LIST_HEAD_INIT(network->address_labels);
|
||||
|
||||
network->stacked_netdevs = hashmap_new(&string_hash_ops);
|
||||
if (!network->stacked_netdevs)
|
||||
@ -131,6 +132,10 @@ static int network_load_one(Manager *manager, const char *filename) {
|
||||
if (!network->fdb_entries_by_section)
|
||||
return log_oom();
|
||||
|
||||
network->address_labels_by_section = hashmap_new(&network_config_hash_ops);
|
||||
if (!network->address_labels_by_section)
|
||||
return log_oom();
|
||||
|
||||
network->filename = strdup(filename);
|
||||
if (!network->filename)
|
||||
return log_oom();
|
||||
@ -192,6 +197,7 @@ static int network_load_one(Manager *manager, const char *filename) {
|
||||
"Link\0"
|
||||
"Network\0"
|
||||
"Address\0"
|
||||
"IPv6AddressLabel\0"
|
||||
"Route\0"
|
||||
"DHCP\0"
|
||||
"DHCPv4\0" /* compat */
|
||||
@ -271,6 +277,7 @@ void network_free(Network *network) {
|
||||
Address *address;
|
||||
FdbEntry *fdb_entry;
|
||||
IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
|
||||
AddressLabel *label;
|
||||
Iterator i;
|
||||
|
||||
if (!network)
|
||||
@ -318,9 +325,13 @@ void network_free(Network *network) {
|
||||
while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
|
||||
ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
|
||||
|
||||
while ((label = network->address_labels))
|
||||
address_label_free(label);
|
||||
|
||||
hashmap_free(network->addresses_by_section);
|
||||
hashmap_free(network->routes_by_section);
|
||||
hashmap_free(network->fdb_entries_by_section);
|
||||
hashmap_free(network->address_labels_by_section);
|
||||
|
||||
if (network->manager) {
|
||||
if (network->manager->networks)
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "resolve-util.h"
|
||||
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-address-label.h"
|
||||
#include "networkd-brvlan.h"
|
||||
#include "networkd-fdb.h"
|
||||
#include "networkd-lldp-tx.h"
|
||||
@ -202,15 +203,18 @@ struct Network {
|
||||
LIST_HEAD(Route, static_routes);
|
||||
LIST_HEAD(FdbEntry, static_fdb_entries);
|
||||
LIST_HEAD(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
|
||||
LIST_HEAD(AddressLabel, address_labels);
|
||||
|
||||
unsigned n_static_addresses;
|
||||
unsigned n_static_routes;
|
||||
unsigned n_static_fdb_entries;
|
||||
unsigned n_ipv6_proxy_ndp_addresses;
|
||||
unsigned n_address_labels;
|
||||
|
||||
Hashmap *addresses_by_section;
|
||||
Hashmap *routes_by_section;
|
||||
Hashmap *fdb_entries_by_section;
|
||||
Hashmap *address_labels_by_section;
|
||||
|
||||
struct in_addr_data *dns;
|
||||
unsigned n_dns;
|
||||
|
Loading…
x
Reference in New Issue
Block a user