mirror of
https://github.com/systemd/systemd.git
synced 2025-01-11 09:18:07 +03:00
networkd: add support for [Address] sections
This will allow specifying more options per address than the simple Address= entry in the [Network] section. Preliminary support for the same functionality for [Route] sections are added, but not yet hooked up, as more testing is needed.
This commit is contained in:
parent
71a6151083
commit
6ae115c1fe
@ -162,6 +162,23 @@
|
|||||||
.</para>
|
.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
<para>The <literal>[Address]</literal> section accepts the following keys:</para>
|
||||||
|
|
||||||
|
<variablelist class='network-directives'>
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>Address</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>As in the <literal>[Network]</literal> section.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>Label</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>An address label.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -28,9 +28,20 @@
|
|||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
#include "net-util.h"
|
#include "net-util.h"
|
||||||
|
|
||||||
int address_new(Network *network, Address **ret) {
|
int address_new(Network *network, unsigned section, Address **ret) {
|
||||||
_cleanup_address_free_ Address *address = NULL;
|
_cleanup_address_free_ Address *address = NULL;
|
||||||
|
|
||||||
|
if (section) {
|
||||||
|
uint64_t key = section;
|
||||||
|
address = hashmap_get(network->addresses_by_section, &key);
|
||||||
|
if (address) {
|
||||||
|
*ret = address;
|
||||||
|
address = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
address = new0(Address, 1);
|
address = new0(Address, 1);
|
||||||
if (!address)
|
if (!address)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -39,6 +50,11 @@ int address_new(Network *network, Address **ret) {
|
|||||||
|
|
||||||
LIST_PREPEND(addresses, network->addresses, address);
|
LIST_PREPEND(addresses, network->addresses, address);
|
||||||
|
|
||||||
|
if (section) {
|
||||||
|
address->section = section;
|
||||||
|
hashmap_put(network->addresses_by_section, &address->section, address);
|
||||||
|
}
|
||||||
|
|
||||||
*ret = address;
|
*ret = address;
|
||||||
address = NULL;
|
address = NULL;
|
||||||
|
|
||||||
@ -51,7 +67,10 @@ void address_free(Address *address) {
|
|||||||
|
|
||||||
LIST_REMOVE(addresses, address->network->addresses, address);
|
LIST_REMOVE(addresses, address->network->addresses, address);
|
||||||
|
|
||||||
free(address->label);
|
if (address->section)
|
||||||
|
hashmap_remove(address->network->addresses_by_section,
|
||||||
|
&address->section);
|
||||||
|
|
||||||
free(address);
|
free(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,17 +140,19 @@ int config_parse_address(const char *unit,
|
|||||||
const char *rvalue,
|
const char *rvalue,
|
||||||
void *data,
|
void *data,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
Network *network = userdata;
|
||||||
_cleanup_address_free_ Address *n = NULL;
|
_cleanup_address_free_ Address *n = NULL;
|
||||||
_cleanup_free_ char *address = NULL;
|
_cleanup_free_ char *address = NULL;
|
||||||
const char *e;
|
const char *e;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
|
assert(section);
|
||||||
assert(lvalue);
|
assert(lvalue);
|
||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
assert(data);
|
||||||
|
|
||||||
r = address_new(userdata, &n);
|
r = address_new(network, section_line, &n);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -172,3 +193,54 @@ int config_parse_address(const char *unit,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int config_parse_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) {
|
||||||
|
Network *network = userdata;
|
||||||
|
_cleanup_address_free_ Address *n = NULL;
|
||||||
|
_cleanup_free_ char *address = NULL;
|
||||||
|
char *label;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(section);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
r = address_new(network, section_line, &n);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
label = strdup(rvalue);
|
||||||
|
if (!label)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||||
|
"Interface label is not ASCII clean or is too"
|
||||||
|
" long, ignoring assignment: %s", rvalue);
|
||||||
|
free(label);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(n->label);
|
||||||
|
if (*label)
|
||||||
|
n->label = label;
|
||||||
|
else {
|
||||||
|
free(label);
|
||||||
|
n->label = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -23,3 +23,5 @@ Match.Name, config_parse_ifname, 0, offsetof(Networ
|
|||||||
Network.Description, config_parse_string, 0, offsetof(Network, description)
|
Network.Description, config_parse_string, 0, offsetof(Network, description)
|
||||||
Network.Address, config_parse_address, 0, 0
|
Network.Address, config_parse_address, 0, 0
|
||||||
Network.Gateway, config_parse_gateway, 0, 0
|
Network.Gateway, config_parse_gateway, 0, 0
|
||||||
|
Address.Address, config_parse_address, 0, 0
|
||||||
|
Address.Label, config_parse_label, 0, 0
|
||||||
|
@ -45,8 +45,21 @@ static int network_load_one(Manager *manager, const char *filename) {
|
|||||||
network->manager = manager;
|
network->manager = manager;
|
||||||
|
|
||||||
LIST_HEAD_INIT(network->addresses);
|
LIST_HEAD_INIT(network->addresses);
|
||||||
|
LIST_HEAD_INIT(network->routes);
|
||||||
|
|
||||||
r = config_parse(NULL, filename, file, "Match\0Network\0", config_item_perf_lookup,
|
network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
|
||||||
|
if (!network->addresses_by_section)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
|
||||||
|
if (!network->routes_by_section)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
network->filename = strdup(filename);
|
||||||
|
if (!network->filename)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0", config_item_perf_lookup,
|
||||||
(void*) network_gperf_lookup, false, false, network);
|
(void*) network_gperf_lookup, false, false, network);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_warning("Could not parse config file %s: %s", filename, strerror(-r));
|
log_warning("Could not parse config file %s: %s", filename, strerror(-r));
|
||||||
@ -54,10 +67,6 @@ static int network_load_one(Manager *manager, const char *filename) {
|
|||||||
} else
|
} else
|
||||||
log_debug("Parsed configuration file %s", filename);
|
log_debug("Parsed configuration file %s", filename);
|
||||||
|
|
||||||
network->filename = strdup(filename);
|
|
||||||
if (!network->filename)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
LIST_PREPEND(networks, manager->networks, network);
|
LIST_PREPEND(networks, manager->networks, network);
|
||||||
network = NULL;
|
network = NULL;
|
||||||
|
|
||||||
@ -121,6 +130,9 @@ void network_free(Network *network) {
|
|||||||
while ((address = network->addresses))
|
while ((address = network->addresses))
|
||||||
address_free(address);
|
address_free(address);
|
||||||
|
|
||||||
|
hashmap_free(network->addresses_by_section);
|
||||||
|
hashmap_free(network->routes_by_section);
|
||||||
|
|
||||||
LIST_REMOVE(networks, network->manager->networks, network);
|
LIST_REMOVE(networks, network->manager->networks, network);
|
||||||
|
|
||||||
free(network);
|
free(network);
|
||||||
|
@ -28,9 +28,21 @@
|
|||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
#include "net-util.h"
|
#include "net-util.h"
|
||||||
|
|
||||||
int route_new(Network *network, Route **ret) {
|
int route_new(Network *network, unsigned section, Route **ret) {
|
||||||
_cleanup_route_free_ Route *route = NULL;
|
_cleanup_route_free_ Route *route = NULL;
|
||||||
|
|
||||||
|
if (section) {
|
||||||
|
uint64_t key = section;
|
||||||
|
|
||||||
|
route = hashmap_get(network->routes_by_section, &key);
|
||||||
|
if (route) {
|
||||||
|
*ret = route;
|
||||||
|
route = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
route = new0(Route, 1);
|
route = new0(Route, 1);
|
||||||
if (!route)
|
if (!route)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -39,6 +51,11 @@ int route_new(Network *network, Route **ret) {
|
|||||||
|
|
||||||
LIST_PREPEND(routes, network->routes, route);
|
LIST_PREPEND(routes, network->routes, route);
|
||||||
|
|
||||||
|
if (section) {
|
||||||
|
route->section = section;
|
||||||
|
hashmap_put(network->routes_by_section, &route->section, route);
|
||||||
|
}
|
||||||
|
|
||||||
*ret = route;
|
*ret = route;
|
||||||
route = NULL;
|
route = NULL;
|
||||||
|
|
||||||
@ -51,6 +68,10 @@ void route_free(Route *route) {
|
|||||||
|
|
||||||
LIST_REMOVE(routes, route->network->routes, route);
|
LIST_REMOVE(routes, route->network->routes, route);
|
||||||
|
|
||||||
|
if (route->section)
|
||||||
|
hashmap_remove(route->network->routes_by_section,
|
||||||
|
&route->section);
|
||||||
|
|
||||||
free(route);
|
free(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,9 +86,9 @@ int route_configure(Route *route, Link *link,
|
|||||||
assert(link->ifindex > 0);
|
assert(link->ifindex > 0);
|
||||||
assert(route->family == AF_INET || route->family == AF_INET6);
|
assert(route->family == AF_INET || route->family == AF_INET6);
|
||||||
|
|
||||||
r = sd_rtnl_message_route_new(RTM_NEWROUTE, route->family, 0, 0, 0,
|
r = sd_rtnl_message_route_new(RTM_NEWROUTE, route->family, route->dst_prefixlen,
|
||||||
RT_TABLE_MAIN, RT_SCOPE_UNIVERSE, RTPROT_BOOT,
|
0, 0, RT_TABLE_MAIN, RT_SCOPE_UNIVERSE,
|
||||||
RTN_UNICAST, 0, &req);
|
RTPROT_BOOT, RTN_UNICAST, 0, &req);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
|
log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
|
||||||
return r;
|
return r;
|
||||||
@ -79,6 +100,12 @@ int route_configure(Route *route, Link *link,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = sd_rtnl_message_append(req, RTA_DST, &route->dst_addr);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not append RTA_DST attribute: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = sd_rtnl_message_append(req, RTA_OIF, &link->ifindex);
|
r = sd_rtnl_message_append(req, RTA_OIF, &link->ifindex);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
|
log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
|
||||||
@ -106,16 +133,18 @@ int config_parse_gateway(const char *unit,
|
|||||||
const char *rvalue,
|
const char *rvalue,
|
||||||
void *data,
|
void *data,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
Network *network = userdata;
|
||||||
_cleanup_route_free_ Route *n = NULL;
|
_cleanup_route_free_ Route *n = NULL;
|
||||||
_cleanup_free_ char *route = NULL;
|
_cleanup_free_ char *route = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
|
assert(section);
|
||||||
assert(lvalue);
|
assert(lvalue);
|
||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
assert(data);
|
||||||
|
|
||||||
r = route_new(userdata, &n);
|
r = route_new(network, section_line, &n);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -130,3 +159,66 @@ int config_parse_gateway(const char *unit,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int config_parse_destination(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) {
|
||||||
|
Network *network = userdata;
|
||||||
|
_cleanup_route_free_ Route *n = NULL;
|
||||||
|
_cleanup_free_ char *address = NULL;
|
||||||
|
const char *e;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(section);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
r = route_new(network, section_line, &n);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Destination=address/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, EINVAL,
|
||||||
|
"Route destination prefix length is invalid, "
|
||||||
|
"ignoring assignment: %s", e + 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
n->dst_prefixlen = (unsigned char) i;
|
||||||
|
|
||||||
|
address = strndup(rvalue, e - rvalue);
|
||||||
|
if (!address)
|
||||||
|
return log_oom();
|
||||||
|
} else {
|
||||||
|
address = strdup(rvalue);
|
||||||
|
if (!address)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
|
r = net_parse_inaddr(address, &n->family, &n->dst_addr);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||||
|
"Destination is invalid, ignoring assignment: %s", address);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -54,11 +54,15 @@ struct Network {
|
|||||||
LIST_HEAD(Address, addresses);
|
LIST_HEAD(Address, addresses);
|
||||||
LIST_HEAD(Route, routes);
|
LIST_HEAD(Route, routes);
|
||||||
|
|
||||||
|
Hashmap *addresses_by_section;
|
||||||
|
Hashmap *routes_by_section;
|
||||||
|
|
||||||
LIST_FIELDS(Network, networks);
|
LIST_FIELDS(Network, networks);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Address {
|
struct Address {
|
||||||
Network *network;
|
Network *network;
|
||||||
|
uint64_t section;
|
||||||
|
|
||||||
unsigned char family;
|
unsigned char family;
|
||||||
unsigned char prefixlen;
|
unsigned char prefixlen;
|
||||||
@ -76,14 +80,21 @@ struct Address {
|
|||||||
|
|
||||||
struct Route {
|
struct Route {
|
||||||
Network *network;
|
Network *network;
|
||||||
|
uint64_t section;
|
||||||
|
|
||||||
unsigned char family;
|
unsigned char family;
|
||||||
|
unsigned char dst_prefixlen;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct in_addr in;
|
struct in_addr in;
|
||||||
struct in6_addr in6;
|
struct in6_addr in6;
|
||||||
} in_addr;
|
} in_addr;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct in_addr in;
|
||||||
|
struct in6_addr in6;
|
||||||
|
} dst_addr;
|
||||||
|
|
||||||
LIST_FIELDS(Route, routes);
|
LIST_FIELDS(Route, routes);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -156,7 +167,7 @@ int network_apply(Manager *manager, Network *network, Link *link);
|
|||||||
const struct ConfigPerfItem* network_gperf_lookup(const char *key, unsigned length);
|
const struct ConfigPerfItem* network_gperf_lookup(const char *key, unsigned length);
|
||||||
|
|
||||||
/* Route */
|
/* Route */
|
||||||
int route_new(Network *network, Route **ret);
|
int route_new(Network *network, unsigned section, Route **ret);
|
||||||
void route_free(Route *route);
|
void route_free(Route *route);
|
||||||
int route_configure(Route *route, Link *link, sd_rtnl_message_handler_t callback);
|
int route_configure(Route *route, Link *link, sd_rtnl_message_handler_t callback);
|
||||||
|
|
||||||
@ -167,8 +178,12 @@ int config_parse_gateway(const char *unit, const char *filename, unsigned line,
|
|||||||
const char *section, unsigned section_line, const char *lvalue,
|
const char *section, unsigned section_line, const char *lvalue,
|
||||||
int ltype, const char *rvalue, void *data, void *userdata);
|
int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
|
|
||||||
|
int config_parse_destination(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);
|
||||||
|
|
||||||
/* Address */
|
/* Address */
|
||||||
int address_new(Network *network, Address **ret);
|
int address_new(Network *network, unsigned section, Address **ret);
|
||||||
void address_free(Address *address);
|
void address_free(Address *address);
|
||||||
int address_configure(Address *address, Link *link, sd_rtnl_message_handler_t callback);
|
int address_configure(Address *address, Link *link, sd_rtnl_message_handler_t callback);
|
||||||
|
|
||||||
@ -179,6 +194,10 @@ int config_parse_address(const char *unit, const char *filename, unsigned line,
|
|||||||
const char *section, unsigned section_line, const char *lvalue,
|
const char *section, unsigned section_line, const char *lvalue,
|
||||||
int ltype, const char *rvalue, void *data, void *userdata);
|
int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
|
|
||||||
|
int config_parse_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);
|
||||||
|
|
||||||
/* Link */
|
/* Link */
|
||||||
|
|
||||||
int link_new(Manager *manager, struct udev_device *device, Link **ret);
|
int link_new(Manager *manager, struct udev_device *device, Link **ret);
|
||||||
|
Loading…
Reference in New Issue
Block a user