mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-10-27 01:55:32 +03:00
Merge pull request #1726 from teg/networkd-2
networkd: (de)serialize more state and support expiring routes
This commit is contained in:
commit
4084052911
@ -344,7 +344,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
|
||||
int r;
|
||||
|
||||
assert_return(optlen > 1, -ENODATA);
|
||||
assert_return(optval[optlen] == '\0', -EINVAL);
|
||||
assert_return(optval[optlen - 1] == '\0', -EINVAL);
|
||||
|
||||
while (pos < optlen) {
|
||||
_cleanup_free_ char *ret = NULL;
|
||||
|
@ -271,15 +271,35 @@ int address_add_foreign(Link *link, int family, const union in_addr_union *in_ad
|
||||
return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
|
||||
}
|
||||
|
||||
static int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
|
||||
int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
|
||||
Address *address;
|
||||
int r;
|
||||
|
||||
r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, ret);
|
||||
if (r < 0)
|
||||
r = address_get(link, family, in_addr, prefixlen, &address);
|
||||
if (r == -ENOENT) {
|
||||
/* Address does not exist, create a new one */
|
||||
r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r == 0) {
|
||||
/* Take over a foreign address */
|
||||
r = set_ensure_allocated(&link->addresses, &address_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = set_put(link->addresses, address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
set_remove(link->addresses_foreign, address);
|
||||
} else if (r == 1) {
|
||||
/* Already exists, do nothing */
|
||||
;
|
||||
} else
|
||||
return r;
|
||||
|
||||
link_update_operstate(link);
|
||||
link_dirty(link);
|
||||
if (ret)
|
||||
*ret = address;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -318,8 +338,12 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s
|
||||
address->scope = scope;
|
||||
address->cinfo = *cinfo;
|
||||
|
||||
if (!ready && address_is_ready(address) && address->link)
|
||||
link_check_ready(address->link);
|
||||
if (address->link) {
|
||||
link_update_operstate(address->link);
|
||||
|
||||
if (!ready && address_is_ready(address))
|
||||
link_check_ready(address->link);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -356,7 +380,11 @@ int address_get(Link *link, int family, const union in_addr_union *in_addr, unsi
|
||||
address.prefixlen = prefixlen;
|
||||
|
||||
existing = set_get(link->addresses, &address);
|
||||
if (!existing) {
|
||||
if (existing) {
|
||||
*ret = existing;
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
existing = set_get(link->addresses_foreign, &address);
|
||||
if (!existing)
|
||||
return -ENOENT;
|
||||
|
@ -62,6 +62,7 @@ int address_new_static(Network *network, unsigned section, Address **ret);
|
||||
int address_new(Address **ret);
|
||||
void address_free(Address *address);
|
||||
int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
|
||||
int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
|
||||
int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
|
||||
int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo);
|
||||
int address_drop(Address *address);
|
||||
|
@ -87,12 +87,12 @@ static int link_set_dhcp_routes(Link *link) {
|
||||
* route for the gw host so that we can route no matter the
|
||||
* netmask or existing kernel route tables. */
|
||||
route_gw->family = AF_INET;
|
||||
route_gw->dst_addr.in = gateway;
|
||||
route_gw->dst.in = gateway;
|
||||
route_gw->dst_prefixlen = 32;
|
||||
route_gw->prefsrc_addr.in = address;
|
||||
route_gw->prefsrc.in = address;
|
||||
route_gw->scope = RT_SCOPE_LINK;
|
||||
route_gw->protocol = RTPROT_DHCP;
|
||||
route_gw->metrics = link->network->dhcp_route_metric;
|
||||
route_gw->priority = link->network->dhcp_route_metric;
|
||||
|
||||
r = route_configure(route_gw, link, &dhcp4_route_handler);
|
||||
if (r < 0)
|
||||
@ -101,9 +101,9 @@ static int link_set_dhcp_routes(Link *link) {
|
||||
link->dhcp4_messages ++;
|
||||
|
||||
route->family = AF_INET;
|
||||
route->in_addr.in = gateway;
|
||||
route->prefsrc_addr.in = address;
|
||||
route->metrics = link->network->dhcp_route_metric;
|
||||
route->gw.in = gateway;
|
||||
route->prefsrc.in = address;
|
||||
route->priority = link->network->dhcp_route_metric;
|
||||
|
||||
r = route_configure(route, link, &dhcp4_route_handler);
|
||||
if (r < 0) {
|
||||
@ -130,10 +130,10 @@ static int link_set_dhcp_routes(Link *link) {
|
||||
|
||||
route->family = AF_INET;
|
||||
route->protocol = RTPROT_DHCP;
|
||||
route->in_addr.in = static_routes[i].gw_addr;
|
||||
route->dst_addr.in = static_routes[i].dst_addr;
|
||||
route->gw.in = static_routes[i].gw_addr;
|
||||
route->dst.in = static_routes[i].dst_addr;
|
||||
route->dst_prefixlen = static_routes[i].dst_prefixlen;
|
||||
route->metrics = link->network->dhcp_route_metric;
|
||||
route->priority = link->network->dhcp_route_metric;
|
||||
|
||||
r = route_configure(route, link, &dhcp4_route_handler);
|
||||
if (r < 0)
|
||||
@ -170,8 +170,8 @@ static int dhcp_lease_lost(Link *link) {
|
||||
r = route_new(&route);
|
||||
if (r >= 0) {
|
||||
route->family = AF_INET;
|
||||
route->in_addr.in = routes[i].gw_addr;
|
||||
route->dst_addr.in = routes[i].dst_addr;
|
||||
route->gw.in = routes[i].gw_addr;
|
||||
route->dst.in = routes[i].dst_addr;
|
||||
route->dst_prefixlen = routes[i].dst_prefixlen;
|
||||
|
||||
route_remove(route, link,
|
||||
@ -191,7 +191,7 @@ static int dhcp_lease_lost(Link *link) {
|
||||
r = route_new(&route_gw);
|
||||
if (r >= 0) {
|
||||
route_gw->family = AF_INET;
|
||||
route_gw->dst_addr.in = gateway;
|
||||
route_gw->dst.in = gateway;
|
||||
route_gw->dst_prefixlen = 32;
|
||||
route_gw->scope = RT_SCOPE_LINK;
|
||||
|
||||
@ -202,7 +202,7 @@ static int dhcp_lease_lost(Link *link) {
|
||||
r = route_new(&route);
|
||||
if (r >= 0) {
|
||||
route->family = AF_INET;
|
||||
route->in_addr.in = gateway;
|
||||
route->gw.in = gateway;
|
||||
|
||||
route_remove(route, link,
|
||||
&link_route_remove_handler);
|
||||
@ -533,9 +533,11 @@ int dhcp4_configure(Link *link) {
|
||||
assert(link->network);
|
||||
assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
|
||||
|
||||
r = sd_dhcp_client_new(&link->dhcp_client);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!link->dhcp_client) {
|
||||
r = sd_dhcp_client_new(&link->dhcp_client);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
|
||||
if (r < 0)
|
||||
|
@ -63,7 +63,7 @@ static int ipv4ll_address_lost(Link *link) {
|
||||
|
||||
route->family = AF_INET;
|
||||
route->scope = RT_SCOPE_LINK;
|
||||
route->metrics = IPV4LL_ROUTE_METRIC;
|
||||
route->priority = IPV4LL_ROUTE_METRIC;
|
||||
|
||||
route_remove(route, link, &link_route_remove_handler);
|
||||
|
||||
@ -156,7 +156,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
|
||||
route->family = AF_INET;
|
||||
route->scope = RT_SCOPE_LINK;
|
||||
route->protocol = RTPROT_STATIC;
|
||||
route->metrics = IPV4LL_ROUTE_METRIC;
|
||||
route->priority = IPV4LL_ROUTE_METRIC;
|
||||
|
||||
r = route_configure(route, link, ipv4ll_route_handler);
|
||||
if (r < 0)
|
||||
@ -208,9 +208,11 @@ int ipv4ll_configure(Link *link) {
|
||||
assert(link->network);
|
||||
assert(link->network->link_local & ADDRESS_FAMILY_IPV4);
|
||||
|
||||
r = sd_ipv4ll_new(&link->ipv4ll);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!link->ipv4ll) {
|
||||
r = sd_ipv4ll_new(&link->ipv4ll);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->udev_device) {
|
||||
r = net_get_unique_predictable_data(link->udev_device, seed);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "bus-util.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "event-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "netlink-util.h"
|
||||
@ -2057,29 +2058,31 @@ static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = network_get(link->manager, link->udev_device, link->ifname,
|
||||
&link->mac, &network);
|
||||
if (r == -ENOENT) {
|
||||
link_enter_unmanaged(link);
|
||||
return 1;
|
||||
} else if (r < 0)
|
||||
return r;
|
||||
if (!link->network) {
|
||||
r = network_get(link->manager, link->udev_device, link->ifname,
|
||||
&link->mac, &network);
|
||||
if (r == -ENOENT) {
|
||||
link_enter_unmanaged(link);
|
||||
return 1;
|
||||
} else if (r < 0)
|
||||
return r;
|
||||
|
||||
if (link->flags & IFF_LOOPBACK) {
|
||||
if (network->link_local != ADDRESS_FAMILY_NO)
|
||||
log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
|
||||
if (link->flags & IFF_LOOPBACK) {
|
||||
if (network->link_local != ADDRESS_FAMILY_NO)
|
||||
log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
|
||||
|
||||
if (network->dhcp != ADDRESS_FAMILY_NO)
|
||||
log_link_debug(link, "Ignoring DHCP clients for loopback link");
|
||||
if (network->dhcp != ADDRESS_FAMILY_NO)
|
||||
log_link_debug(link, "Ignoring DHCP clients for loopback link");
|
||||
|
||||
if (network->dhcp_server)
|
||||
log_link_debug(link, "Ignoring DHCP server for loopback link");
|
||||
if (network->dhcp_server)
|
||||
log_link_debug(link, "Ignoring DHCP server for loopback link");
|
||||
}
|
||||
|
||||
r = network_apply(link->manager, network, link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = network_apply(link->manager, network, link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_new_bound_to_list(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -2130,6 +2133,193 @@ int link_initialized(Link *link, struct udev_device *device) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_load(Link *link) {
|
||||
_cleanup_free_ char *network_file = NULL,
|
||||
*addresses = NULL,
|
||||
*routes = NULL,
|
||||
*dhcp4_address = NULL,
|
||||
*ipv4ll_address = NULL;
|
||||
union in_addr_union address;
|
||||
union in_addr_union route_dst;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
r = parse_env_file(link->state_file, NEWLINE,
|
||||
"NETWORK_FILE", &network_file,
|
||||
"ADDRESSES", &addresses,
|
||||
"ROUTES", &routes,
|
||||
"DHCP4_ADDRESS", &dhcp4_address,
|
||||
"IPV4LL_ADDRESS", &ipv4ll_address,
|
||||
NULL);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return log_link_error_errno(link, r, "Failed to read %s: %m", link->state_file);
|
||||
|
||||
if (network_file) {
|
||||
Network *network;
|
||||
char *suffix;
|
||||
|
||||
/* drop suffix */
|
||||
suffix = strrchr(network_file, '.');
|
||||
if (!suffix) {
|
||||
log_link_debug(link, "Failed to get network name from %s", network_file);
|
||||
goto network_file_fail;
|
||||
}
|
||||
*suffix = '\0';
|
||||
|
||||
r = network_get_by_name(link->manager, basename(network_file), &network);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Failed to get network %s: %m", basename(network_file));
|
||||
goto network_file_fail;
|
||||
}
|
||||
|
||||
r = network_apply(link->manager, network, link);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to apply network %s: %m", basename(network_file));
|
||||
}
|
||||
|
||||
network_file_fail:
|
||||
|
||||
if (addresses) {
|
||||
p = addresses;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *address_str = NULL;
|
||||
char *prefixlen_str;
|
||||
int family;
|
||||
unsigned char prefixlen;
|
||||
|
||||
r = extract_first_word(&p, &address_str, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Failed to extract next address string: %m");
|
||||
continue;
|
||||
} if (r == 0)
|
||||
break;
|
||||
|
||||
prefixlen_str = strchr(address_str, '/');
|
||||
if (!prefixlen_str) {
|
||||
log_link_debug(link, "Failed to parse address and prefix length %s", address_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
*prefixlen_str ++ = '\0';
|
||||
|
||||
r = sscanf(prefixlen_str, "%hhu", &prefixlen);
|
||||
if (r != 1) {
|
||||
log_link_error(link, "Failed to parse prefixlen %s", prefixlen_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = in_addr_from_string_auto(address_str, &family, &address);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Failed to parse address %s: %m", address_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = address_add(link, family, &address, prefixlen, NULL);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to add address: %m");
|
||||
}
|
||||
}
|
||||
|
||||
if (routes) {
|
||||
for (;;) {
|
||||
Route *route;
|
||||
_cleanup_free_ char *route_str = NULL;
|
||||
_cleanup_event_source_unref_ sd_event_source *expire = NULL;
|
||||
usec_t lifetime;
|
||||
char *prefixlen_str;
|
||||
int family;
|
||||
unsigned char prefixlen, tos, table;
|
||||
uint32_t priority;
|
||||
|
||||
r = extract_first_word(&p, &route_str, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Failed to extract next route string: %m");
|
||||
continue;
|
||||
} if (r == 0)
|
||||
break;
|
||||
|
||||
prefixlen_str = strchr(route_str, '/');
|
||||
if (!prefixlen_str) {
|
||||
log_link_debug(link, "Failed to parse route %s", route_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
*prefixlen_str ++ = '\0';
|
||||
|
||||
r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime);
|
||||
if (r != 5) {
|
||||
log_link_debug(link,
|
||||
"Failed to parse destination prefix length, tos, priority, table or expiration %s",
|
||||
prefixlen_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = in_addr_from_string_auto(route_str, &family, &route_dst);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, &route);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to add route: %m");
|
||||
|
||||
if (lifetime != USEC_INFINITY) {
|
||||
r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), lifetime,
|
||||
0, route_expire_handler, route);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not arm route expiration handler: %m");
|
||||
}
|
||||
|
||||
route->lifetime = lifetime;
|
||||
sd_event_source_unref(route->expire);
|
||||
route->expire = expire;
|
||||
expire = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (dhcp4_address) {
|
||||
r = in_addr_from_string(AF_INET, dhcp4_address, &address);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Falied to parse DHCPv4 address %s: %m", dhcp4_address);
|
||||
goto dhcp4_address_fail;
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_new(&link->dhcp_client);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Falied to create DHCPv4 client: %m");
|
||||
|
||||
r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Falied to set inital DHCPv4 address %s: %m", dhcp4_address);
|
||||
}
|
||||
|
||||
dhcp4_address_fail:
|
||||
|
||||
if (ipv4ll_address) {
|
||||
r = in_addr_from_string(AF_INET, ipv4ll_address, &address);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Falied to parse IPv4LL address %s: %m", ipv4ll_address);
|
||||
goto ipv4ll_address_fail;
|
||||
}
|
||||
|
||||
r = sd_ipv4ll_new(&link->ipv4ll);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Falied to create IPv4LL client: %m");
|
||||
|
||||
r = sd_ipv4ll_set_address(link->ipv4ll, &address.in);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Falied to set inital IPv4LL address %s: %m", ipv4ll_address);
|
||||
}
|
||||
|
||||
ipv4ll_address_fail:
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
|
||||
Link *link;
|
||||
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
|
||||
@ -2149,6 +2339,10 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
|
||||
|
||||
log_link_debug(link, "Link %d added", link->ifindex);
|
||||
|
||||
r = link_load(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (detect_container() <= 0) {
|
||||
/* not in a container, udev will be around */
|
||||
sprintf(ifindex_str, "n%d", link->ifindex);
|
||||
@ -2372,6 +2566,7 @@ int link_save(Link *link) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
const char *admin_state, *oper_state;
|
||||
Address *a;
|
||||
Route *route;
|
||||
Iterator i;
|
||||
int r;
|
||||
|
||||
@ -2450,9 +2645,9 @@ int link_save(Link *link) {
|
||||
}
|
||||
}
|
||||
|
||||
fputs("\n", f);
|
||||
fputc('\n', f);
|
||||
|
||||
fprintf(f, "NTP=");
|
||||
fputs("NTP=", f);
|
||||
space = false;
|
||||
STRV_FOREACH(address, link->network->ntp) {
|
||||
if (space)
|
||||
@ -2499,9 +2694,9 @@ int link_save(Link *link) {
|
||||
}
|
||||
}
|
||||
|
||||
fputs("\n", f);
|
||||
fputc('\n', f);
|
||||
|
||||
fprintf(f, "DOMAINS=");
|
||||
fputs("DOMAINS=", f);
|
||||
space = false;
|
||||
STRV_FOREACH(domain, link->network->domains) {
|
||||
if (space)
|
||||
@ -2537,7 +2732,7 @@ int link_save(Link *link) {
|
||||
}
|
||||
}
|
||||
|
||||
fputs("\n", f);
|
||||
fputc('\n', f);
|
||||
|
||||
fprintf(f, "WILDCARD_DOMAIN=%s\n",
|
||||
yes_no(link->network->wildcard_domain));
|
||||
@ -2545,7 +2740,7 @@ int link_save(Link *link) {
|
||||
fprintf(f, "LLMNR=%s\n",
|
||||
resolve_support_to_string(link->network->llmnr));
|
||||
|
||||
fprintf(f, "ADDRESSES=");
|
||||
fputs("ADDRESSES=", f);
|
||||
space = false;
|
||||
SET_FOREACH(a, link->addresses, i) {
|
||||
_cleanup_free_ char *address_str = NULL;
|
||||
@ -2558,7 +2753,23 @@ int link_save(Link *link) {
|
||||
space = true;
|
||||
}
|
||||
|
||||
fputs("\n", f);
|
||||
fputc('\n', f);
|
||||
|
||||
fputs("ROUTES=", f);
|
||||
space = false;
|
||||
SET_FOREACH(route, link->routes, i) {
|
||||
_cleanup_free_ char *route_str = NULL;
|
||||
|
||||
r = in_addr_to_string(route->family, &route->dst, &route_str);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%hhu/"USEC_FMT, space ? " " : "", route_str,
|
||||
route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
|
||||
space = true;
|
||||
}
|
||||
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
if (!hashmap_isempty(link->bound_to_links)) {
|
||||
@ -2573,7 +2784,7 @@ int link_save(Link *link) {
|
||||
space = true;
|
||||
}
|
||||
|
||||
fputs("\n", f);
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
if (!hashmap_isempty(link->bound_by_links)) {
|
||||
@ -2588,19 +2799,25 @@ int link_save(Link *link) {
|
||||
space = true;
|
||||
}
|
||||
|
||||
fputs("\n", f);
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
if (link->dhcp_lease) {
|
||||
struct in_addr address;
|
||||
const char *tz = NULL;
|
||||
|
||||
assert(link->network);
|
||||
|
||||
r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
|
||||
if (r >= 0)
|
||||
fprintf(f, "TIMEZONE=%s\n", tz);
|
||||
}
|
||||
|
||||
if (link->dhcp_lease) {
|
||||
assert(link->network);
|
||||
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
|
||||
if (r >= 0) {
|
||||
fputs("DHCP4_ADDRESS=", f);
|
||||
serialize_in_addrs(f, &address, 1);
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
|
||||
if (r < 0)
|
||||
@ -2612,6 +2829,17 @@ int link_save(Link *link) {
|
||||
} else
|
||||
unlink(link->lease_file);
|
||||
|
||||
if (link->ipv4ll) {
|
||||
struct in_addr address;
|
||||
|
||||
r = sd_ipv4ll_get_address(link->ipv4ll, &address);
|
||||
if (r >= 0) {
|
||||
fputs("IPV4LL_ADDRESS=", f);
|
||||
serialize_in_addrs(f, &address, 1);
|
||||
fputc('\n', f);
|
||||
}
|
||||
}
|
||||
|
||||
if (link->lldp) {
|
||||
assert(link->network);
|
||||
|
||||
|
@ -85,6 +85,8 @@ struct Link {
|
||||
|
||||
Set *addresses;
|
||||
Set *addresses_foreign;
|
||||
Set *routes;
|
||||
Set *routes_foreign;
|
||||
|
||||
sd_dhcp_client *dhcp_client;
|
||||
sd_dhcp_lease *dhcp_lease;
|
||||
|
@ -279,6 +279,196 @@ static int manager_connect_udev(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
||||
Manager *m = userdata;
|
||||
Link *link = NULL;
|
||||
uint16_t type;
|
||||
uint32_t ifindex, priority = 0;
|
||||
unsigned char protocol, scope, tos, table;
|
||||
int family;
|
||||
unsigned char dst_prefixlen, src_prefixlen;
|
||||
union in_addr_union dst = {}, gw = {}, src = {}, prefsrc = {};
|
||||
Route *route = NULL;
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
if (sd_netlink_message_is_error(message)) {
|
||||
r = sd_netlink_message_get_errno(message);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: failed to receive route: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_get_type(message, &type);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: could not get message type: %m");
|
||||
return 0;
|
||||
} else if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
|
||||
log_warning("rtnl: received unexpected message type when processing route");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
|
||||
if (r == -ENODATA) {
|
||||
log_debug("rtnl: received route without ifindex, ignoring");
|
||||
return 0;
|
||||
} else if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: could not get ifindex from route, ignoring: %m");
|
||||
return 0;
|
||||
} else if (ifindex <= 0) {
|
||||
log_warning("rtnl: received route message with invalid ifindex, ignoring: %d", ifindex);
|
||||
return 0;
|
||||
} else {
|
||||
r = link_get(m, ifindex, &link);
|
||||
if (r < 0 || !link) {
|
||||
/* when enumerating we might be out of sync, but we will
|
||||
* get the route again, so just ignore it */
|
||||
if (!m->enumerating)
|
||||
log_warning("rtnl: received route for nonexistent link (%d), ignoring", ifindex);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_family(message, &family);
|
||||
if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
|
||||
log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_protocol(message, &protocol);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: could not get route protocol: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_DST, &dst.in);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &gw.in);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_SRC, &src.in);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &prefsrc.in);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_DST, &dst.in6);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &gw.in6);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &src.in6);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &prefsrc.in6);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_dst_prefixlen(message, &dst_prefixlen);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid destination prefixlen, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_src_prefixlen(message, &src_prefixlen);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid source prefixlen, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_scope(message, &scope);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid scope, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_tos(message, &tos);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid tos, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_route_get_table(message, &table);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid table, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &priority);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route with invalid priority, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
route_get(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
|
||||
|
||||
switch (type) {
|
||||
case RTM_NEWROUTE:
|
||||
if (!route) {
|
||||
/* A route appeared that we did not request */
|
||||
r = route_add_foreign(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, protocol);
|
||||
|
||||
break;
|
||||
|
||||
case RTM_DELROUTE:
|
||||
|
||||
if (route)
|
||||
route_drop(route);
|
||||
|
||||
break;
|
||||
default:
|
||||
assert_not_reached("Received invalid RTNL message type");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
||||
Manager *m = userdata;
|
||||
Link *link = NULL;
|
||||
@ -377,7 +567,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("invalid address family");
|
||||
log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family);
|
||||
}
|
||||
|
||||
if (!inet_ntop(family, &in_addr, buf, INET6_ADDRSTRLEN)) {
|
||||
@ -572,6 +762,14 @@ static int manager_connect_rtnl(Manager *m) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_add_match(m->rtnl, RTM_NEWROUTE, &manager_rtnl_process_route, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_add_match(m->rtnl, RTM_DELROUTE, &manager_rtnl_process_route, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1019,6 +1217,41 @@ int manager_rtnl_enumerate_addresses(Manager *m) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int manager_rtnl_enumerate_routes(Manager *m) {
|
||||
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
|
||||
sd_netlink_message *route;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(m->rtnl);
|
||||
|
||||
r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_request_dump(req, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_call(m->rtnl, req, 0, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (route = reply; route; route = sd_netlink_message_next(route)) {
|
||||
int k;
|
||||
|
||||
m->enumerating = true;
|
||||
|
||||
k = manager_rtnl_process_route(m->rtnl, route, m);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
m->enumerating = false;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
|
||||
AddressPool *p;
|
||||
int r;
|
||||
|
@ -352,6 +352,10 @@ int network_get(Manager *manager, struct udev_device *device,
|
||||
int network_apply(Manager *manager, Network *network, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(manager);
|
||||
assert(network);
|
||||
assert(link);
|
||||
|
||||
link->network = network;
|
||||
|
||||
if (network->ipv4ll_route) {
|
||||
@ -361,7 +365,7 @@ int network_apply(Manager *manager, Network *network, Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
|
||||
r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
|
||||
if (r == 0)
|
||||
return -EINVAL;
|
||||
if (r < 0)
|
||||
@ -370,7 +374,7 @@ int network_apply(Manager *manager, Network *network, Link *link) {
|
||||
route->family = AF_INET;
|
||||
route->dst_prefixlen = 16;
|
||||
route->scope = RT_SCOPE_LINK;
|
||||
route->metrics = IPV4LL_ROUTE_METRIC;
|
||||
route->priority = IPV4LL_ROUTE_METRIC;
|
||||
route->protocol = RTPROT_STATIC;
|
||||
}
|
||||
|
||||
|
@ -21,11 +21,13 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "event-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-route.h"
|
||||
#include "networkd.h"
|
||||
#include "parse-util.h"
|
||||
#include "set.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
@ -40,6 +42,7 @@ int route_new(Route **ret) {
|
||||
route->scope = RT_SCOPE_UNIVERSE;
|
||||
route->protocol = RTPROT_UNSPEC;
|
||||
route->table = RT_TABLE_DEFAULT;
|
||||
route->lifetime = USEC_INFINITY;
|
||||
|
||||
*ret = route;
|
||||
route = NULL;
|
||||
@ -95,6 +98,13 @@ void route_free(Route *route) {
|
||||
UINT_TO_PTR(route->section));
|
||||
}
|
||||
|
||||
if (route->link) {
|
||||
set_remove(route->link->routes, route);
|
||||
set_remove(route->link->routes_foreign, route);
|
||||
}
|
||||
|
||||
sd_event_source_unref(route->expire);
|
||||
|
||||
free(route);
|
||||
}
|
||||
|
||||
@ -110,7 +120,7 @@ static void route_hash_func(const void *b, struct siphash *state) {
|
||||
case AF_INET6:
|
||||
/* Equality of routes are given by the 4-touple
|
||||
(dst_prefix,dst_prefixlen,tos,priority,table) */
|
||||
siphash24_compress(&route->dst_addr, FAMILY_ADDRESS_SIZE(route->family), state);
|
||||
siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
|
||||
siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
|
||||
siphash24_compress(&route->tos, sizeof(route->tos), state);
|
||||
siphash24_compress(&route->priority, sizeof(route->priority), state);
|
||||
@ -134,7 +144,6 @@ static int route_compare_func(const void *_a, const void *_b) {
|
||||
switch (a->family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
//TODO: check IPv6 routes
|
||||
if (a->dst_prefixlen < b->dst_prefixlen)
|
||||
return -1;
|
||||
if (a->dst_prefixlen > b->dst_prefixlen)
|
||||
@ -155,7 +164,7 @@ static int route_compare_func(const void *_a, const void *_b) {
|
||||
if (a->table > b->table)
|
||||
return 1;
|
||||
|
||||
return memcmp(&a->dst_addr, &b->dst_addr, FAMILY_ADDRESS_SIZE(a->family));
|
||||
return memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
|
||||
default:
|
||||
/* treat any other address family as AF_UNSPEC */
|
||||
return 0;
|
||||
@ -167,6 +176,162 @@ static const struct hash_ops route_hash_ops = {
|
||||
.compare = route_compare_func
|
||||
};
|
||||
|
||||
int route_get(Link *link,
|
||||
int family,
|
||||
union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
unsigned char table,
|
||||
Route **ret) {
|
||||
Route route = {
|
||||
.family = family,
|
||||
.dst_prefixlen = dst_prefixlen,
|
||||
.tos = tos,
|
||||
.priority = priority,
|
||||
.table = table,
|
||||
}, *existing;
|
||||
|
||||
assert(link);
|
||||
assert(dst);
|
||||
assert(ret);
|
||||
|
||||
route.dst = *dst;
|
||||
|
||||
existing = set_get(link->routes, &route);
|
||||
if (existing) {
|
||||
*ret = existing;
|
||||
return 1;
|
||||
} else {
|
||||
existing = set_get(link->routes_foreign, &route);
|
||||
if (!existing)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
*ret = existing;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int route_add_internal(Link *link, Set **routes,
|
||||
int family,
|
||||
union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
unsigned char table, Route **ret) {
|
||||
_cleanup_route_free_ Route *route = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(routes);
|
||||
assert(dst);
|
||||
|
||||
r = route_new(&route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
route->family = family;
|
||||
route->dst = *dst;
|
||||
route->dst_prefixlen = dst_prefixlen;
|
||||
route->tos = tos;
|
||||
route->priority = priority;
|
||||
route->table = table;
|
||||
|
||||
r = set_ensure_allocated(routes, &route_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = set_put(*routes, route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
route->link = link;
|
||||
|
||||
if (ret)
|
||||
*ret = route;
|
||||
|
||||
route = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int route_add_foreign(Link *link,
|
||||
int family,
|
||||
union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
unsigned char table, Route **ret) {
|
||||
return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
|
||||
}
|
||||
|
||||
int route_add(Link *link,
|
||||
int family,
|
||||
union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
unsigned char table, Route **ret) {
|
||||
Route *route;
|
||||
int r;
|
||||
|
||||
r = route_get(link, family, dst, dst_prefixlen, tos, priority, table, &route);
|
||||
if (r == -ENOENT) {
|
||||
/* Route does not exist, create a new one */
|
||||
r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, tos, priority, table, &route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r == 0) {
|
||||
/* Take over a foreign route */
|
||||
r = set_ensure_allocated(&link->routes, &route_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = set_put(link->routes, route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
set_remove(link->routes_foreign, route);
|
||||
} else if (r == 1) {
|
||||
/* Route exists, do nothing */
|
||||
;
|
||||
} else
|
||||
return r;
|
||||
|
||||
*ret = route;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int route_update(Route *route,
|
||||
union in_addr_union *src,
|
||||
unsigned char src_prefixlen,
|
||||
union in_addr_union *gw,
|
||||
union in_addr_union *prefsrc,
|
||||
unsigned char scope,
|
||||
unsigned char protocol) {
|
||||
assert(route);
|
||||
assert(src);
|
||||
assert(gw);
|
||||
assert(prefsrc);
|
||||
|
||||
route->src = *src;
|
||||
route->src_prefixlen = src_prefixlen;
|
||||
route->gw = *gw;
|
||||
route->prefsrc = *prefsrc;
|
||||
route->scope = scope;
|
||||
route->protocol = protocol;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void route_drop(Route *route) {
|
||||
assert(route);
|
||||
|
||||
route_free(route);
|
||||
}
|
||||
|
||||
int route_remove(Route *route, Link *link,
|
||||
sd_netlink_message_handler_t callback) {
|
||||
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
|
||||
@ -184,20 +349,20 @@ int route_remove(Route *route, Link *link,
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not create RTM_DELROUTE message: %m");
|
||||
|
||||
if (!in_addr_is_null(route->family, &route->in_addr)) {
|
||||
if (!in_addr_is_null(route->family, &route->gw)) {
|
||||
if (route->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
|
||||
else if (route->family == AF_INET6)
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
|
||||
}
|
||||
|
||||
if (route->dst_prefixlen) {
|
||||
if (route->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
|
||||
else if (route->family == AF_INET6)
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append RTA_DST attribute: %m");
|
||||
|
||||
@ -208,9 +373,9 @@ int route_remove(Route *route, Link *link,
|
||||
|
||||
if (route->src_prefixlen) {
|
||||
if (route->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
|
||||
else if (route->family == AF_INET6)
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append RTA_DST attribute: %m");
|
||||
|
||||
@ -219,11 +384,11 @@ int route_remove(Route *route, Link *link,
|
||||
return log_error_errno(r, "Could not set source prefix length: %m");
|
||||
}
|
||||
|
||||
if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
|
||||
if (!in_addr_is_null(route->family, &route->prefsrc)) {
|
||||
if (route->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
|
||||
else if (route->family == AF_INET6)
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
|
||||
}
|
||||
@ -232,7 +397,7 @@ int route_remove(Route *route, Link *link,
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not set scope: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
|
||||
r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
|
||||
|
||||
@ -249,9 +414,24 @@ int route_remove(Route *route, Link *link,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
Route *route = userdata;
|
||||
int r;
|
||||
|
||||
assert(route);
|
||||
|
||||
r = route_remove(route, route->link, NULL);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not remove route: %m");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int route_configure(Route *route, Link *link,
|
||||
sd_netlink_message_handler_t callback) {
|
||||
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
|
||||
_cleanup_event_source_unref_ sd_event_source *expire = NULL;
|
||||
usec_t lifetime;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@ -266,20 +446,20 @@ int route_configure(Route *route, Link *link,
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
|
||||
|
||||
if (!in_addr_is_null(route->family, &route->in_addr)) {
|
||||
if (!in_addr_is_null(route->family, &route->gw)) {
|
||||
if (route->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
|
||||
else if (route->family == AF_INET6)
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
|
||||
}
|
||||
|
||||
if (route->dst_prefixlen) {
|
||||
if (route->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
|
||||
else if (route->family == AF_INET6)
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append RTA_DST attribute: %m");
|
||||
|
||||
@ -290,9 +470,9 @@ int route_configure(Route *route, Link *link,
|
||||
|
||||
if (route->src_prefixlen) {
|
||||
if (route->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
|
||||
else if (route->family == AF_INET6)
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
|
||||
|
||||
@ -301,11 +481,11 @@ int route_configure(Route *route, Link *link,
|
||||
return log_error_errno(r, "Could not set source prefix length: %m");
|
||||
}
|
||||
|
||||
if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
|
||||
if (!in_addr_is_null(route->family, &route->prefsrc)) {
|
||||
if (route->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
|
||||
r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
|
||||
else if (route->family == AF_INET6)
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
|
||||
r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
|
||||
}
|
||||
@ -314,7 +494,7 @@ int route_configure(Route *route, Link *link,
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not set scope: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
|
||||
r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
|
||||
|
||||
@ -328,6 +508,26 @@ int route_configure(Route *route, Link *link,
|
||||
|
||||
link_ref(link);
|
||||
|
||||
lifetime = route->lifetime;
|
||||
|
||||
r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not add route: %m");
|
||||
|
||||
/* TODO: drop expiration handling once it can be pushed into the kernel */
|
||||
route->lifetime = lifetime;
|
||||
|
||||
if (route->lifetime != USEC_INFINITY) {
|
||||
r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
|
||||
route->lifetime, 0, route_expire_handler, route);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not arm expiration timer: %m");
|
||||
}
|
||||
|
||||
sd_event_source_unref(route->expire);
|
||||
route->expire = expire;
|
||||
expire = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -370,7 +570,7 @@ int config_parse_gateway(const char *unit,
|
||||
}
|
||||
|
||||
n->family = f;
|
||||
n->in_addr = buffer;
|
||||
n->gw = buffer;
|
||||
n = NULL;
|
||||
|
||||
return 0;
|
||||
@ -410,7 +610,7 @@ int config_parse_preferred_src(const char *unit,
|
||||
}
|
||||
|
||||
n->family = f;
|
||||
n->prefsrc_addr = buffer;
|
||||
n->prefsrc = buffer;
|
||||
n = NULL;
|
||||
|
||||
return 0;
|
||||
@ -484,10 +684,10 @@ int config_parse_destination(const char *unit,
|
||||
|
||||
n->family = f;
|
||||
if (streq(lvalue, "Destination")) {
|
||||
n->dst_addr = buffer;
|
||||
n->dst = buffer;
|
||||
n->dst_prefixlen = prefixlen;
|
||||
} else if (streq(lvalue, "Source")) {
|
||||
n->src_addr = buffer;
|
||||
n->src = buffer;
|
||||
n->src_prefixlen = prefixlen;
|
||||
} else
|
||||
assert_not_reached(lvalue);
|
||||
@ -521,9 +721,9 @@ int config_parse_route_priority(const char *unit,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = config_parse_unsigned(unit, filename, line, section,
|
||||
section_line, lvalue, ltype,
|
||||
rvalue, &n->metrics, userdata);
|
||||
r = config_parse_uint32(unit, filename, line, section,
|
||||
section_line, lvalue, ltype,
|
||||
rvalue, &n->priority, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -30,20 +30,24 @@ struct Route {
|
||||
Network *network;
|
||||
unsigned section;
|
||||
|
||||
Link *link;
|
||||
|
||||
int family;
|
||||
unsigned char dst_prefixlen;
|
||||
unsigned char src_prefixlen;
|
||||
unsigned char scope;
|
||||
uint32_t metrics;
|
||||
unsigned char protocol; /* RTPROT_* */
|
||||
unsigned char tos;
|
||||
unsigned char priority;
|
||||
uint32_t priority; /* note that ip(8) calls this 'metric' */
|
||||
unsigned char table;
|
||||
|
||||
union in_addr_union in_addr;
|
||||
union in_addr_union dst_addr;
|
||||
union in_addr_union src_addr;
|
||||
union in_addr_union prefsrc_addr;
|
||||
union in_addr_union gw;
|
||||
union in_addr_union dst;
|
||||
union in_addr_union src;
|
||||
union in_addr_union prefsrc;
|
||||
|
||||
usec_t lifetime;
|
||||
sd_event_source *expire;
|
||||
|
||||
LIST_FIELDS(Route, routes);
|
||||
};
|
||||
@ -54,6 +58,14 @@ void route_free(Route *route);
|
||||
int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback);
|
||||
int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback);
|
||||
|
||||
int route_get(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
|
||||
int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
|
||||
int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
|
||||
int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol);
|
||||
void route_drop(Route *route);
|
||||
|
||||
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free);
|
||||
#define _cleanup_route_free_ _cleanup_(route_freep)
|
||||
|
||||
|
@ -109,6 +109,12 @@ int main(int argc, char *argv[]) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = manager_rtnl_enumerate_routes(m);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Could not enumerate routes: %m");
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_info("Enumeration completed");
|
||||
|
||||
sd_notify(false,
|
||||
|
@ -82,8 +82,10 @@ bool manager_should_reload(Manager *m);
|
||||
|
||||
int manager_rtnl_enumerate_links(Manager *m);
|
||||
int manager_rtnl_enumerate_addresses(Manager *m);
|
||||
int manager_rtnl_enumerate_routes(Manager *m);
|
||||
|
||||
int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata);
|
||||
int manager_rtnl_process_route(sd_netlink *nl, sd_netlink_message *message, void *userdata);
|
||||
|
||||
int manager_send_changed(Manager *m, const char *property, ...) _sentinel_;
|
||||
void manager_dirty(Manager *m);
|
||||
|
@ -14,7 +14,7 @@ Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
ReceiveBuffer=8M
|
||||
ListenNetlink=route 273
|
||||
ListenNetlink=route 1361
|
||||
PassCredentials=yes
|
||||
|
||||
[Install]
|
||||
|
Loading…
Reference in New Issue
Block a user