#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) {
if (!route)
return -ENOMEM;
+ route->family = AF_UNSPEC;
+ route->scope = RT_SCOPE_UNIVERSE;
+
route->network = network;
- LIST_PREPEND(routes, network->routes, route);
+ LIST_PREPEND(routes, network->static_routes, route);
if (section) {
route->section = section;
return 0;
}
+int route_new_dynamic(Route **ret) {
+ _cleanup_route_free_ Route *route = NULL;
+
+ route = new0(Route, 1);
+ if (!route)
+ return -ENOMEM;
+
+ route->family = AF_UNSPEC;
+ route->scope = RT_SCOPE_UNIVERSE;
+
+ *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,
+ &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);
+ if (r < 0) {
+ log_error("Could not create RTM_DELROUTE message: %s", strerror(-r));
+ return r;
+ }
+
+ 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 (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) {
+ log_error("Could not append RTA_DST attribute: %s", strerror(-r));
+ return r;
+ }
+
+ 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;
+ }
+ }
+
+ r = sd_rtnl_message_route_set_scope(req, route->scope);
+ if (r < 0) {
+ log_error("Could not set scope: %s", strerror(-r));
+ return r;
+ }
+
+ r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
+ if (r < 0) {
+ log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
+ return r;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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);
assert(link->ifindex > 0);
assert(route->family == AF_INET || route->family == AF_INET6);
- r = sd_rtnl_message_route_new(RTM_NEWROUTE, route->family, &req);
+ r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
+ RTM_NEWROUTE, route->family);
if (r < 0) {
log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
return r;
log_error("Could not append RTA_DST attribute: %s", strerror(-r));
return r;
}
+
+ 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;
+ }
}
- r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
+ r = sd_rtnl_message_route_set_scope(req, route->scope);
if (r < 0) {
- log_error("Could not set destination prefix length: %s", strerror(-r));
+ log_error("Could not set scope: %s", strerror(-r));
+ return r;
+ }
+
+ r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
+ if (r < 0) {
+ log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
return r;
}
return r;
}
+ link_ref(link);
+
return 0;
}
section_line = 0;
}
- r = route_new(network, section_line, &n);
+ r = route_new_static(network, section_line, &n);
if (r < 0)
return r;
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 */
- /* prefixlen */
+ /* address */
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();
return 0;
}
+ /* prefixlen */
+ 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;
+ } else {
+ switch (n->family) {
+ case AF_INET:
+ n->dst_prefixlen = 32;
+ break;
+ case AF_INET6:
+ n->dst_prefixlen = 128;
+ break;
+ }
+ }
+
n = NULL;
return 0;