From 2ce409569093f7c2c6732246978a901a27f2bce3 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sun, 25 Oct 2015 15:09:40 +0100 Subject: networkd: route - rename fields in struct --- src/network/networkd-dhcp4.c | 20 ++++++++-------- src/network/networkd-link.c | 18 +++++++-------- src/network/networkd-network.c | 2 +- src/network/networkd-route.c | 52 +++++++++++++++++++++--------------------- src/network/networkd-route.h | 8 +++---- 5 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index c412a2cc31..4f7f595adc 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -87,9 +87,9 @@ 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; @@ -101,8 +101,8 @@ 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->gw.in = gateway; + route->prefsrc.in = address; route->metrics = link->network->dhcp_route_metric; r = route_configure(route, link, &dhcp4_route_handler); @@ -130,8 +130,8 @@ 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; @@ -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); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index dcc2569660..0f73d2128c 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2450,9 +2450,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 +2499,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 +2537,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 +2545,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 +2558,7 @@ int link_save(Link *link) { space = true; } - fputs("\n", f); + fputc('\n', f); } if (!hashmap_isempty(link->bound_to_links)) { @@ -2573,7 +2573,7 @@ int link_save(Link *link) { space = true; } - fputs("\n", f); + fputc('\n', f); } if (!hashmap_isempty(link->bound_by_links)) { @@ -2588,7 +2588,7 @@ int link_save(Link *link) { space = true; } - fputs("\n", f); + fputc('\n', f); } if (link->dhcp_lease) { diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index cc8d019017..c73d68201b 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -361,7 +361,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) diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 4a74bc69f3..5674e0493b 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -110,7 +110,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); @@ -155,7 +155,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; @@ -184,20 +184,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 +208,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 +219,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"); } @@ -266,20 +266,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 +290,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 +301,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"); } @@ -370,7 +370,7 @@ int config_parse_gateway(const char *unit, } n->family = f; - n->in_addr = buffer; + n->gw = buffer; n = NULL; return 0; @@ -410,7 +410,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 +484,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); diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index c9972e4933..2c0b705402 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -40,10 +40,10 @@ struct Route { unsigned char priority; 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; LIST_FIELDS(Route, routes); }; -- cgit v1.2.3-54-g00ecf From 86655331bc28887def7998d321b14ef8fccbeaf9 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 26 Oct 2015 17:04:57 +0100 Subject: networkd: route - clean up confusion between 'metric' and 'priority' Different tools use different terms for the same concept, let's try to stick with 'priority', as that is what the netlink API uses. --- src/network/networkd-dhcp4.c | 6 +++--- src/network/networkd-ipv4ll.c | 4 ++-- src/network/networkd-network.c | 2 +- src/network/networkd-route.c | 11 +++++------ src/network/networkd-route.h | 3 +-- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 4f7f595adc..05a16f4033 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -92,7 +92,7 @@ static int link_set_dhcp_routes(Link *link) { 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) @@ -103,7 +103,7 @@ static int link_set_dhcp_routes(Link *link) { route->family = AF_INET; route->gw.in = gateway; route->prefsrc.in = address; - 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) { @@ -133,7 +133,7 @@ static int link_set_dhcp_routes(Link *link) { 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) diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 2fdb77ef6c..59abb1e8d4 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -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) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index c73d68201b..14c201e9a5 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -370,7 +370,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; } diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 5674e0493b..078d9c1618 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -134,7 +134,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) @@ -232,7 +231,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"); @@ -314,7 +313,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"); @@ -521,9 +520,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; diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 2c0b705402..b1ed5d1085 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -34,10 +34,9 @@ struct Route { 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 gw; -- cgit v1.2.3-54-g00ecf From a3a019e125ff2ab38505579eaddce08874e270aa Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Tue, 27 Oct 2015 00:06:10 +0100 Subject: networkd: address - update link operstate when address is updated The operstate may change based on address properties, so make a change of address trigger an operstate update. --- src/network/networkd-address.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index e550ee5701..0338fe9393 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -318,8 +318,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; } -- cgit v1.2.3-54-g00ecf From cab974b035c24a87f9a8cf152ea415b0c14404b7 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 26 Oct 2015 11:40:02 +0100 Subject: networkd: address - properly take over a foreign address --- src/network/networkd-address.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 0338fe9393..5b5492e02e 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -272,14 +272,34 @@ int address_add_foreign(Link *link, int family, const union in_addr_union *in_ad } static 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; } @@ -360,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; -- cgit v1.2.3-54-g00ecf From 1c8e710c2b479129c3ad06a0e8e2d21ae4aefd38 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sun, 25 Oct 2015 14:46:21 +0100 Subject: networkd: route - track routes --- src/network/networkd-link.h | 2 + src/network/networkd-manager.c | 235 ++++++++++++++++++++++++++++++++++++++++- src/network/networkd-route.c | 166 +++++++++++++++++++++++++++++ src/network/networkd-route.h | 8 ++ src/network/networkd.c | 6 ++ src/network/networkd.h | 2 + units/systemd-networkd.socket | 2 +- 7 files changed, 419 insertions(+), 2 deletions(-) diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 2a69f1c16b..a22041870e 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -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; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 6b2a661ca7..a5701001c1 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -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; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 078d9c1618..7c0d03cdc7 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -26,6 +26,7 @@ #include "networkd-route.h" #include "networkd.h" #include "parse-util.h" +#include "set.h" #include "string-util.h" #include "util.h" @@ -95,6 +96,11 @@ 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); + } + free(route); } @@ -166,6 +172,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; @@ -327,6 +489,10 @@ int route_configure(Route *route, Link *link, link_ref(link); + r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL); + if (r < 0) + return log_error_errno(r, "Could not add route: %m"); + return 0; } diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index b1ed5d1085..785bd1663a 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -30,6 +30,8 @@ struct Route { Network *network; unsigned section; + Link *link; + int family; unsigned char dst_prefixlen; unsigned char src_prefixlen; @@ -53,6 +55,12 @@ 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); + DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free); #define _cleanup_route_free_ _cleanup_(route_freep) diff --git a/src/network/networkd.c b/src/network/networkd.c index c03ac69e27..ef394e0c04 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -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, diff --git a/src/network/networkd.h b/src/network/networkd.h index 6c5a9939be..97665fac7a 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -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); diff --git a/units/systemd-networkd.socket b/units/systemd-networkd.socket index 2c20935d83..9e4e9dd338 100644 --- a/units/systemd-networkd.socket +++ b/units/systemd-networkd.socket @@ -14,7 +14,7 @@ Before=sockets.target [Socket] ReceiveBuffer=8M -ListenNetlink=route 273 +ListenNetlink=route 1361 PassCredentials=yes [Install] -- cgit v1.2.3-54-g00ecf From c1eb9872f6d21e04c361a44987f36451e80ac126 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 12 Oct 2015 17:54:41 +0200 Subject: networkd: link - serialize routes --- src/network/networkd-link.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 0f73d2128c..c5be599ecd 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2372,6 +2372,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; @@ -2559,6 +2560,22 @@ int link_save(Link *link) { } 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", space ? " " : "", route_str, + route->dst_prefixlen, route->tos, route->priority, route->table); + space = true; + } + + fputc('\n', f); } if (!hashmap_isempty(link->bound_to_links)) { -- cgit v1.2.3-54-g00ecf From c4a03a5669af8abd752bff9084c29683ae78e11e Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Thu, 1 Oct 2015 21:14:06 +0200 Subject: networkd: link - deserialize For now only deserialize some basic state and the applied addresses. When a link is added, try to deserialize it's state from /run. This is relevant only when networkd is restarted at runtime. --- src/network/networkd-address.c | 2 +- src/network/networkd-address.h | 1 + src/network/networkd-link.c | 123 +++++++++++++++++++++++++++++++++++------ src/network/networkd-network.c | 4 ++ 4 files changed, 111 insertions(+), 19 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 5b5492e02e..8b6acf2e1d 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -271,7 +271,7 @@ 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; diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index fd309bebb6..0b1f3b688b 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -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); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index c5be599ecd..4243f8cba9 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2057,28 +2057,30 @@ 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) @@ -2130,6 +2132,87 @@ 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; + int r; + + assert(link); + + r = parse_env_file(link->state_file, NEWLINE, + "NETWORK_FILE", &network_file, + "ADDRESSES", &addresses, + 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) { + _cleanup_strv_free_ char **addresses_strv = NULL; + char **address_str; + + addresses_strv = strv_split(addresses, " "); + if (!addresses_strv) + return log_oom(); + + STRV_FOREACH(address_str, addresses_strv) { + char *prefixlen_str; + int family; + unsigned char prefixlen; + union in_addr_union address; + + 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"); + } + } + + 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 +2232,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); diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 14c201e9a5..0188cb6fe5 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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) { -- cgit v1.2.3-54-g00ecf From 0bc70f1d9c5453ba614ec0ed041dc30b9cd52071 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Thu, 1 Oct 2015 22:29:50 +0200 Subject: networkd: link - (de)serialize IPv4LL and DHCPv4 addresses This initializes the clients to try rebinding the preexisting addresses before doing anything else. --- src/network/networkd-dhcp4.c | 8 +++-- src/network/networkd-ipv4ll.c | 8 +++-- src/network/networkd-link.c | 68 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 73 insertions(+), 11 deletions(-) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 05a16f4033..b58fc5808c 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -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) diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 59abb1e8d4..ed0d861e7a 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -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); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 4243f8cba9..5dcd862c21 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2133,7 +2133,11 @@ int link_initialized(Link *link, struct udev_device *device) { } static int link_load(Link *link) { - _cleanup_free_ char *network_file = NULL, *addresses = NULL; + _cleanup_free_ char *network_file = NULL, + *addresses = NULL, + *dhcp4_address = NULL, + *ipv4ll_address = NULL; + union in_addr_union address; int r; assert(link); @@ -2141,6 +2145,8 @@ static int link_load(Link *link) { r = parse_env_file(link->state_file, NEWLINE, "NETWORK_FILE", &network_file, "ADDRESSES", &addresses, + "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); @@ -2182,7 +2188,6 @@ network_file_fail: char *prefixlen_str; int family; unsigned char prefixlen; - union in_addr_union address; prefixlen_str = strchr(*address_str, '/'); if (!prefixlen_str) { @@ -2210,6 +2215,42 @@ network_file_fail: } } + 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; } @@ -2696,15 +2737,21 @@ int link_save(Link *link) { } 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) @@ -2716,6 +2763,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); -- cgit v1.2.3-54-g00ecf From f703cc2c5756088605a37d7d9a9b84e719b667f5 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sun, 25 Oct 2015 14:45:53 +0100 Subject: networkd: link - deserialize routes --- src/network/networkd-link.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 5dcd862c21..9beaa7822b 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2135,9 +2135,11 @@ int link_initialized(Link *link, struct udev_device *device) { 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; int r; assert(link); @@ -2145,6 +2147,7 @@ static int link_load(Link *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); @@ -2215,6 +2218,46 @@ network_file_fail: } } + if (routes) { + _cleanup_strv_free_ char **routes_strv = NULL; + char **route_str; + + routes_strv = strv_split(routes, " "); + if (!routes_strv) + return log_oom(); + + STRV_FOREACH(route_str, routes_strv) { + char *prefixlen_str; + int family; + unsigned char prefixlen, tos, table; + uint32_t priority; + + 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", &prefixlen, &tos, &priority, &table); + if (r != 4) { + log_link_debug(link, "Failed to parse destination prefix length, tos, priority or table %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, NULL); + if (r < 0) + return log_link_error_errno(link, r, "Failed to add route: %m"); + } + } + if (dhcp4_address) { r = in_addr_from_string(AF_INET, dhcp4_address, &address); if (r < 0) { -- cgit v1.2.3-54-g00ecf From f833694d4f6a6dffabc6a4e552ecbd40aa3ce479 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 26 Oct 2015 12:29:37 +0100 Subject: networkd: route - add expiration support This should really live in the kernel, but the netlink API currently does not support it. Until support has been added, expire the route from userspace. --- src/network/networkd-link.c | 30 ++++++++++++++++++++++++------ src/network/networkd-route.c | 37 ++++++++++++++++++++++++++++++++++++- src/network/networkd-route.h | 5 +++++ 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 9beaa7822b..7316a08d29 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -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" @@ -2227,6 +2228,9 @@ network_file_fail: return log_oom(); STRV_FOREACH(route_str, routes_strv) { + Route *route; + _cleanup_event_source_unref_ sd_event_source *expire = NULL; + usec_t lifetime; char *prefixlen_str; int family; unsigned char prefixlen, tos, table; @@ -2240,9 +2244,11 @@ network_file_fail: *prefixlen_str ++ = '\0'; - r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu", &prefixlen, &tos, &priority, &table); - if (r != 4) { - log_link_debug(link, "Failed to parse destination prefix length, tos, priority or table %s", prefixlen_str); + 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; } @@ -2252,9 +2258,21 @@ network_file_fail: continue; } - r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, NULL); + 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; } } @@ -2741,8 +2759,8 @@ int link_save(Link *link) { if (r < 0) goto fail; - fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%hhu", space ? " " : "", route_str, - route->dst_prefixlen, route->tos, route->priority, route->table); + 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; } diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 7c0d03cdc7..f4bbd06af1 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -21,6 +21,7 @@ #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" @@ -41,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; @@ -101,6 +103,8 @@ void route_free(Route *route) { set_remove(route->link->routes_foreign, route); } + sd_event_source_unref(route->expire); + free(route); } @@ -410,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); @@ -489,10 +508,26 @@ int route_configure(Route *route, Link *link, link_ref(link); - r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL); + 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; } diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 785bd1663a..d0a51838ed 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -46,6 +46,9 @@ struct Route { union in_addr_union src; union in_addr_union prefsrc; + usec_t lifetime; + sd_event_source *expire; + LIST_FIELDS(Route, routes); }; @@ -61,6 +64,8 @@ int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned 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) -- cgit v1.2.3-54-g00ecf From 93f660da98853995ee3ad4521112d2788eb0df53 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 26 Oct 2015 13:07:30 +0100 Subject: sd-dhcp6-client: fix assert in options parsing --- src/libsystemd-network/dhcp6-option.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 076bb2dac0..0f46df6a1b 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -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; -- cgit v1.2.3-54-g00ecf From c598ac76266572529b8959145651d18546010869 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Tue, 27 Oct 2015 17:37:42 +0100 Subject: networkd: link - port to extract_first_word() --- src/network/networkd-link.c | 51 +++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 7316a08d29..7509feaf4e 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2141,6 +2141,7 @@ static int link_load(Link *link) { *ipv4ll_address = NULL; union in_addr_union address; union in_addr_union route_dst; + const char *p; int r; assert(link); @@ -2181,21 +2182,24 @@ static int link_load(Link *link) { network_file_fail: if (addresses) { - _cleanup_strv_free_ char **addresses_strv = NULL; - char **address_str; + p = addresses; - addresses_strv = strv_split(addresses, " "); - if (!addresses_strv) - return log_oom(); - - STRV_FOREACH(address_str, addresses_strv) { + for (;;) { + _cleanup_free_ char *address_str = NULL; char *prefixlen_str; int family; unsigned char prefixlen; - prefixlen_str = strchr(*address_str, '/'); + 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); + log_link_debug(link, "Failed to parse address and prefix length %s", address_str); continue; } @@ -2207,9 +2211,9 @@ network_file_fail: continue; } - r = in_addr_from_string_auto(*address_str, &family, &address); + 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); + log_link_debug_errno(link, r, "Failed to parse address %s: %m", address_str); continue; } @@ -2220,15 +2224,9 @@ network_file_fail: } if (routes) { - _cleanup_strv_free_ char **routes_strv = NULL; - char **route_str; - - routes_strv = strv_split(routes, " "); - if (!routes_strv) - return log_oom(); - - STRV_FOREACH(route_str, routes_strv) { + for (;;) { Route *route; + _cleanup_free_ char *route_str = NULL; _cleanup_event_source_unref_ sd_event_source *expire = NULL; usec_t lifetime; char *prefixlen_str; @@ -2236,9 +2234,16 @@ network_file_fail: unsigned char prefixlen, tos, table; uint32_t priority; - prefixlen_str = strchr(*route_str, '/'); + 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); + log_link_debug(link, "Failed to parse route %s", route_str); continue; } @@ -2252,9 +2257,9 @@ network_file_fail: continue; } - r = in_addr_from_string_auto(*route_str, &family, &route_dst); + 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); + log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str); continue; } -- cgit v1.2.3-54-g00ecf