X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-route.c;h=b88c622614f0458147ad9f26fe6fc509816eadae;hp=31586165c2a703dfacb0c67ac3ef7c9e8896fdde;hb=a9bc6d2df16c1d9f8a99d2cc9be2babf62bd173f;hpb=fe4824e065765f4536c84916694bb050c4a5d0af diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 31586165c..b88c62261 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -28,9 +28,21 @@ #include "conf-parser.h" #include "net-util.h" -int route_new(Network *network, Route **ret) { +int route_new(Network *network, unsigned section, Route **ret) { _cleanup_route_free_ Route *route = NULL; + if (section) { + uint64_t key = section; + + route = hashmap_get(network->routes_by_section, &key); + if (route) { + *ret = route; + route = NULL; + + return 0; + } + } + route = new0(Route, 1); if (!route) return -ENOMEM; @@ -39,6 +51,11 @@ int route_new(Network *network, Route **ret) { LIST_PREPEND(routes, network->routes, route); + if (section) { + route->section = section; + hashmap_put(network->routes_by_section, &route->section, route); + } + *ret = route; route = NULL; @@ -51,21 +68,27 @@ void route_free(Route *route) { LIST_REMOVE(routes, route->network->routes, route); + if (route->section) + hashmap_remove(route->network->routes_by_section, + &route->section); + free(route); } -int route_configure(Manager *manager, Route *route, Link *link) { +int route_configure(Route *route, Link *link, + sd_rtnl_message_handler_t callback) { _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL; int r; - assert(manager); 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_route_new(RTM_NEWROUTE, route->family, 0, 0, 0, - RT_TABLE_MAIN, RT_SCOPE_UNIVERSE, RTPROT_BOOT, - RTN_UNICAST, 0, &req); + r = sd_rtnl_message_route_new(RTM_NEWROUTE, route->family, route->dst_prefixlen, + 0, 0, RT_TABLE_MAIN, RT_SCOPE_UNIVERSE, + RTPROT_BOOT, RTN_UNICAST, 0, &req); if (r < 0) { log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r)); return r; @@ -77,19 +100,25 @@ int route_configure(Manager *manager, Route *route, Link *link) { return r; } + r = sd_rtnl_message_append(req, RTA_DST, &route->dst_addr); + if (r < 0) { + log_error("Could not append RTA_DST attribute: %s", strerror(-r)); + return r; + } + r = sd_rtnl_message_append(req, RTA_OIF, &link->ifindex); if (r < 0) { log_error("Could not append RTA_OIF attribute: %s", strerror(-r)); return r; } - r = sd_rtnl_call(manager->rtnl, req, 0, NULL); + r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL); if (r < 0) { - log_error("Could not configure route: %s", strerror(-r)); + log_error("Could not send rtnetlink message: %s", strerror(-r)); return r; } - log_info("Configured route"); + link->rtnl_messages ++; return 0; } @@ -98,21 +127,24 @@ int config_parse_gateway(const char *unit, const char *filename, unsigned line, const char *section, + unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { + Network *network = userdata; _cleanup_route_free_ Route *n = NULL; _cleanup_free_ char *route = NULL; int r; assert(filename); + assert(section); assert(lvalue); assert(rvalue); assert(data); - r = route_new(userdata, &n); + r = route_new(network, section_line, &n); if (r < 0) return r; @@ -127,3 +159,66 @@ int config_parse_gateway(const char *unit, return 0; } + +int config_parse_destination(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Network *network = userdata; + _cleanup_route_free_ Route *n = NULL; + _cleanup_free_ char *address = NULL; + const char *e; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new(network, section_line, &n); + if (r < 0) + return r; + + /* Destination=address/prefixlen */ + + /* prefixlen */ + e = strchr(rvalue, '/'); + if (e) { + unsigned i; + r = safe_atou(e + 1, &i); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Route destination prefix length is invalid, " + "ignoring assignment: %s", e + 1); + return 0; + } + + n->dst_prefixlen = (unsigned char) i; + + address = strndup(rvalue, e - rvalue); + if (!address) + return log_oom(); + } else { + address = strdup(rvalue); + if (!address) + return log_oom(); + } + + r = net_parse_inaddr(address, &n->family, &n->dst_addr); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Destination is invalid, ignoring assignment: %s", address); + return 0; + } + + n = NULL; + + return 0; +}