X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-route.c;h=590dd49df91efed445a6936f9e0527e4e606afb7;hp=3eaefa2cc741ffa42e84da99acdd2065d2be1613;hb=cb9fc36a1211967e8c58b0502a26c42552ac8060;hpb=ae4c67a7c6bb4efb858822838efe81008c965a98 diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 3eaefa2cc..590dd49df 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -22,19 +22,19 @@ #include #include "networkd.h" +#include "networkd-link.h" #include "utf8.h" #include "util.h" #include "conf-parser.h" -#include "net-util.h" +#include "network-internal.h" -int route_new(Network *network, unsigned section, Route **ret) { +int route_new_static(Network *network, unsigned section, Route **ret) { _cleanup_route_free_ Route *route = NULL; if (section) { - uint64_t key = section; - - route = hashmap_get(network->routes_by_section, &key); + route = hashmap_get(network->routes_by_section, + UINT_TO_PTR(section)); if (route) { *ret = route; route = NULL; @@ -47,13 +47,18 @@ int route_new(Network *network, unsigned section, Route **ret) { if (!route) return -ENOMEM; + route->family = AF_UNSPEC; + route->scope = RT_SCOPE_UNIVERSE; + route->protocol = RTPROT_STATIC; + route->network = network; - LIST_PREPEND(routes, network->routes, route); + LIST_PREPEND(routes, network->static_routes, route); if (section) { route->section = section; - hashmap_put(network->routes_by_section, &route->section, route); + hashmap_put(network->routes_by_section, + UINT_TO_PTR(route->section), route); } *ret = route; @@ -62,22 +67,123 @@ int route_new(Network *network, unsigned section, Route **ret) { return 0; } +int route_new_dynamic(Route **ret, unsigned char rtm_protocol) { + _cleanup_route_free_ Route *route = NULL; + + route = new0(Route, 1); + if (!route) + return -ENOMEM; + + route->family = AF_UNSPEC; + route->scope = RT_SCOPE_UNIVERSE; + route->protocol = rtm_protocol; + + *ret = route; + route = NULL; + + return 0; +} + void route_free(Route *route) { if (!route) return; - LIST_REMOVE(routes, route->network->routes, route); + if (route->network) { + LIST_REMOVE(routes, route->network->static_routes, route); - if (route->section) - hashmap_remove(route->network->routes_by_section, - &route->section); + if (route->section) + hashmap_remove(route->network->routes_by_section, + UINT_TO_PTR(route->section)); + } free(route); } +int route_drop(Route *route, Link *link, + sd_rtnl_message_handler_t callback) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; + int r; + + assert(link); + assert(link->manager); + assert(link->manager->rtnl); + assert(link->ifindex > 0); + assert(route->family == AF_INET || route->family == AF_INET6); + + r = sd_rtnl_message_new_route(link->manager->rtnl, &req, + RTM_DELROUTE, route->family, + route->protocol); + 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 (route->family == AF_INET) + r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in); + else if (route->family == AF_INET6) + r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.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_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in); + else if (route->family == AF_INET6) + r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6); + if (r < 0) + return log_error_errno(r, "Could not append RTA_DST attribute: %m"); + + r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen); + if (r < 0) + return log_error_errno(r, "Could not set destination prefix length: %m"); + } + + if (route->src_prefixlen) { + if (route->family == AF_INET) + r = sd_rtnl_message_append_in_addr(req, RTA_SRC, &route->src_addr.in); + else if (route->family == AF_INET6) + r = sd_rtnl_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6); + if (r < 0) + return log_error_errno(r, "Could not append RTA_DST attribute: %m"); + + r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen); + if (r < 0) + return log_error_errno(r, "Could not set source prefix length: %m"); + } + + if (!in_addr_is_null(route->family, &route->prefsrc_addr)) { + if (route->family == AF_INET) + r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in); + else if (route->family == AF_INET6) + r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6); + if (r < 0) + return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m"); + } + + r = sd_rtnl_message_route_set_scope(req, route->scope); + if (r < 0) + return log_error_errno(r, "Could not set scope: %m"); + + r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics); + if (r < 0) + return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m"); + + r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex); + if (r < 0) + return log_error_errno(r, "Could not append RTA_OIF attribute: %m"); + + r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL); + if (r < 0) + return log_error_errno(r, "Could not send rtnetlink message: %m"); + + link_ref(link); + + return 0; +} + int route_configure(Route *route, Link *link, sd_rtnl_message_handler_t callback) { - _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL; + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; int r; assert(link); @@ -86,19 +192,19 @@ int route_configure(Route *route, Link *link, assert(link->ifindex > 0); assert(route->family == AF_INET || route->family == AF_INET6); - r = sd_rtnl_message_route_new(RTM_NEWROUTE, route->family, &req); - if (r < 0) { - log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r)); - return r; - } + r = sd_rtnl_message_new_route(link->manager->rtnl, &req, + RTM_NEWROUTE, route->family, + route->protocol); + if (r < 0) + return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m"); - if (route->family == AF_INET) - r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in); - else if (route->family == AF_INET6) - r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6); - if (r < 0) { - log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r)); - return r; + if (!in_addr_is_null(route->family, &route->in_addr)) { + if (route->family == AF_INET) + r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in); + else if (route->family == AF_INET6) + r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6); + if (r < 0) + return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m"); } if (route->dst_prefixlen) { @@ -106,30 +212,54 @@ int route_configure(Route *route, Link *link, r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in); else if (route->family == AF_INET6) r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6); - if (r < 0) { - log_error("Could not append RTA_DST attribute: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Could not append RTA_DST attribute: %m"); r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen); - if (r < 0) { - log_error("Could not set destination prefix length: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Could not set destination prefix length: %m"); } - r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex); - if (r < 0) { - log_error("Could not append RTA_OIF attribute: %s", strerror(-r)); - return r; + if (route->src_prefixlen) { + if (route->family == AF_INET) + r = sd_rtnl_message_append_in_addr(req, RTA_SRC, &route->src_addr.in); + else if (route->family == AF_INET6) + r = sd_rtnl_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6); + if (r < 0) + return log_error_errno(r, "Could not append RTA_SRC attribute: %m"); + + r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen); + if (r < 0) + return log_error_errno(r, "Could not set source prefix length: %m"); } - r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL); - if (r < 0) { - log_error("Could not send rtnetlink message: %s", strerror(-r)); - return r; + if (!in_addr_is_null(route->family, &route->prefsrc_addr)) { + if (route->family == AF_INET) + r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in); + else if (route->family == AF_INET6) + r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6); + if (r < 0) + return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m"); } + r = sd_rtnl_message_route_set_scope(req, route->scope); + if (r < 0) + return log_error_errno(r, "Could not set scope: %m"); + + r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics); + if (r < 0) + return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m"); + + r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex); + if (r < 0) + return log_error_errno(r, "Could not append RTA_OIF attribute: %m"); + + r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL); + if (r < 0) + return log_error_errno(r, "Could not send rtnetlink message: %m"); + + link_ref(link); + return 0; } @@ -143,10 +273,11 @@ int config_parse_gateway(const char *unit, const char *rvalue, void *data, void *userdata) { + Network *network = userdata; _cleanup_route_free_ Route *n = NULL; - _cleanup_free_ char *route = NULL; - int r; + union in_addr_union buffer; + int r, f; assert(filename); assert(section); @@ -160,17 +291,19 @@ int config_parse_gateway(const char *unit, section_line = 0; } - r = route_new(network, section_line, &n); + r = route_new_static(network, section_line, &n); if (r < 0) return r; - r = net_parse_inaddr(rvalue, &n->family, &n->in_addr); + r = in_addr_from_string_auto(rvalue, &f, &buffer); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Route is invalid, ignoring assignment: %s", route); + "Route is invalid, ignoring assignment: %s", rvalue); return 0; } + n->family = f; + n->in_addr = buffer; n = NULL; return 0; @@ -186,11 +319,13 @@ int config_parse_destination(const char *unit, const char *rvalue, void *data, void *userdata) { + Network *network = userdata; _cleanup_route_free_ Route *n = NULL; - _cleanup_free_ char *address = NULL; - const char *e; - int r; + const char *address, *e; + union in_addr_union buffer; + unsigned char prefixlen; + int r, f; assert(filename); assert(section); @@ -198,55 +333,96 @@ int config_parse_destination(const char *unit, assert(rvalue); assert(data); - r = route_new(network, section_line, &n); + r = route_new_static(network, section_line, &n); if (r < 0) return r; - /* Destination=address/prefixlen */ + /* Destination|Source=address/prefixlen */ /* address */ e = strchr(rvalue, '/'); - if (e) { - address = strndup(rvalue, e - rvalue); - if (!address) - return log_oom(); - } else { - address = strdup(rvalue); - if (!address) - return log_oom(); - } + if (e) + address = strndupa(rvalue, e - rvalue); + else + address = rvalue; - r = net_parse_inaddr(address, &n->family, &n->dst_addr); + r = in_addr_from_string_auto(address, &f, &buffer); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Destination is invalid, ignoring assignment: %s", address); return 0; } + if (f != AF_INET && f != AF_INET6) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Unknown address family, ignoring assignment: %s", address); + return 0; + } + /* prefixlen */ if (e) { - unsigned i; - - r = safe_atou(e + 1, &i); + r = safe_atou8(e + 1, &prefixlen); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Route destination prefix length is invalid, " - "ignoring assignment: %s", e + 1); + "Route destination prefix length is invalid, ignoring assignment: %s", e + 1); return 0; } - - n->dst_prefixlen = (unsigned char) i; } else { - switch (n->family) { + switch (f) { case AF_INET: - n->dst_prefixlen = 32; + prefixlen = 32; break; case AF_INET6: - n->dst_prefixlen = 128; + prefixlen = 128; break; } } + n->family = f; + if (streq(lvalue, "Destination")) { + n->dst_addr = buffer; + n->dst_prefixlen = prefixlen; + } else if (streq(lvalue, "Source")) { + n->src_addr = buffer; + n->src_prefixlen = prefixlen; + } else + assert_not_reached(lvalue); + + n = NULL; + + return 0; +} + +int config_parse_route_priority(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Network *network = userdata; + _cleanup_route_free_ Route *n = NULL; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, section_line, &n); + if (r < 0) + return r; + + r = config_parse_unsigned(unit, filename, line, section, + section_line, lvalue, ltype, + rvalue, &n->metrics, userdata); + if (r < 0) + return r; + n = NULL; return 0;