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:
Tom Gundersen 2013-11-19 16:54:42 +01:00
parent 71a6151083
commit 6ae115c1fe
6 changed files with 229 additions and 15 deletions

View File

@ -162,6 +162,23 @@
.</para>
</listitem>
</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>
</refsect1>

View File

@ -28,9 +28,20 @@
#include "conf-parser.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;
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);
if (!address)
return -ENOMEM;
@ -39,6 +50,11 @@ int address_new(Network *network, Address **ret) {
LIST_PREPEND(addresses, network->addresses, address);
if (section) {
address->section = section;
hashmap_put(network->addresses_by_section, &address->section, address);
}
*ret = address;
address = NULL;
@ -51,7 +67,10 @@ void address_free(Address *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);
}
@ -121,17 +140,19 @@ int config_parse_address(const char *unit,
const char *rvalue,
void *data,
void *userdata) {
Network *network = userdata;
_cleanup_address_free_ Address *n = NULL;
_cleanup_free_ char *address = NULL;
const char *e;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = address_new(userdata, &n);
r = address_new(network, section_line, &n);
if (r < 0)
return r;
@ -172,3 +193,54 @@ int config_parse_address(const char *unit,
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;
}

View File

@ -23,3 +23,5 @@ Match.Name, config_parse_ifname, 0, offsetof(Networ
Network.Description, config_parse_string, 0, offsetof(Network, description)
Network.Address, config_parse_address, 0, 0
Network.Gateway, config_parse_gateway, 0, 0
Address.Address, config_parse_address, 0, 0
Address.Label, config_parse_label, 0, 0

View File

@ -45,8 +45,21 @@ static int network_load_one(Manager *manager, const char *filename) {
network->manager = manager;
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);
if (r < 0) {
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
log_debug("Parsed configuration file %s", filename);
network->filename = strdup(filename);
if (!network->filename)
return log_oom();
LIST_PREPEND(networks, manager->networks, network);
network = NULL;
@ -121,6 +130,9 @@ void network_free(Network *network) {
while ((address = network->addresses))
address_free(address);
hashmap_free(network->addresses_by_section);
hashmap_free(network->routes_by_section);
LIST_REMOVE(networks, network->manager->networks, network);
free(network);

View File

@ -28,9 +28,21 @@
#include "conf-parser.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;
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);
if (!route)
return -ENOMEM;
@ -39,6 +51,11 @@ int route_new(Network *network, Route **ret) {
LIST_PREPEND(routes, network->routes, route);
if (section) {
route->section = section;
hashmap_put(network->routes_by_section, &route->section, route);
}
*ret = route;
route = NULL;
@ -51,6 +68,10 @@ void route_free(Route *route) {
LIST_REMOVE(routes, route->network->routes, route);
if (route->section)
hashmap_remove(route->network->routes_by_section,
&route->section);
free(route);
}
@ -65,9 +86,9 @@ int route_configure(Route *route, Link *link,
assert(link->ifindex > 0);
assert(route->family == AF_INET || route->family == AF_INET6);
r = sd_rtnl_message_route_new(RTM_NEWROUTE, route->family, 0, 0, 0,
RT_TABLE_MAIN, RT_SCOPE_UNIVERSE, RTPROT_BOOT,
RTN_UNICAST, 0, &req);
r = sd_rtnl_message_route_new(RTM_NEWROUTE, route->family, route->dst_prefixlen,
0, 0, RT_TABLE_MAIN, RT_SCOPE_UNIVERSE,
RTPROT_BOOT, RTN_UNICAST, 0, &req);
if (r < 0) {
log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
return r;
@ -79,6 +100,12 @@ int route_configure(Route *route, Link *link,
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);
if (r < 0) {
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,
void *data,
void *userdata) {
Network *network = userdata;
_cleanup_route_free_ Route *n = NULL;
_cleanup_free_ char *route = NULL;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = route_new(userdata, &n);
r = route_new(network, section_line, &n);
if (r < 0)
return r;
@ -130,3 +159,66 @@ int config_parse_gateway(const char *unit,
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;
}

View File

@ -54,11 +54,15 @@ struct Network {
LIST_HEAD(Address, addresses);
LIST_HEAD(Route, routes);
Hashmap *addresses_by_section;
Hashmap *routes_by_section;
LIST_FIELDS(Network, networks);
};
struct Address {
Network *network;
uint64_t section;
unsigned char family;
unsigned char prefixlen;
@ -76,14 +80,21 @@ struct Address {
struct Route {
Network *network;
uint64_t section;
unsigned char family;
unsigned char dst_prefixlen;
union {
struct in_addr in;
struct in6_addr in6;
} in_addr;
union {
struct in_addr in;
struct in6_addr in6;
} dst_addr;
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);
/* Route */
int route_new(Network *network, Route **ret);
int route_new(Network *network, unsigned section, Route **ret);
void route_free(Route *route);
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,
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 */
int address_new(Network *network, Address **ret);
int address_new(Network *network, unsigned section, Address **ret);
void address_free(Address *address);
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,
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 */
int link_new(Manager *manager, struct udev_device *device, Link **ret);