summaryrefslogtreecommitdiff
path: root/src/network/networkd-route.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/networkd-route.c')
-rw-r--r--src/network/networkd-route.c174
1 files changed, 139 insertions, 35 deletions
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index fbaad40579..aa4ec230ab 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -19,15 +19,35 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "conf-parser.h"
+#include "in-addr-util.h"
#include "netlink-util.h"
+#include "util.h"
#include "networkd.h"
#include "networkd-route.h"
+int route_new(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;
+ route->protocol = RTPROT_UNSPEC;
+ route->table = RT_TABLE_DEFAULT;
+
+ *ret = route;
+ route = NULL;
+
+ return 0;
+}
+
int route_new_static(Network *network, unsigned section, Route **ret) {
_cleanup_route_free_ Route *route = NULL;
+ int r;
if (section) {
route = hashmap_get(network->routes_by_section,
@@ -40,14 +60,11 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
}
}
- route = new0(Route, 1);
- if (!route)
- return -ENOMEM;
+ r = route_new(&route);
+ if (r < 0)
+ return r;
- route->family = AF_UNSPEC;
- route->scope = RT_SCOPE_UNIVERSE;
route->protocol = RTPROT_STATIC;
-
route->network = network;
LIST_PREPEND(routes, network->static_routes, route);
@@ -64,23 +81,6 @@ int route_new_static(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;
@@ -96,7 +96,76 @@ void route_free(Route *route) {
free(route);
}
-int route_drop(Route *route, Link *link,
+static void route_hash_func(const void *b, struct siphash *state) {
+ const Route *route = b;
+
+ assert(route);
+
+ siphash24_compress(&route->family, sizeof(route->family), state);
+
+ switch (route->family) {
+ case AF_INET:
+ 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_prefixlen, sizeof(route->dst_prefixlen), state);
+ siphash24_compress(&route->tos, sizeof(route->tos), state);
+ siphash24_compress(&route->priority, sizeof(route->priority), state);
+ siphash24_compress(&route->table, sizeof(route->table), state);
+
+ break;
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ break;
+ }
+}
+
+static int route_compare_func(const void *_a, const void *_b) {
+ const Route *a = _a, *b = _b;
+
+ if (a->family < b->family)
+ return -1;
+ if (a->family > b->family)
+ return 1;
+
+ 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)
+ return 1;
+
+ if (a->tos < b->tos)
+ return -1;
+ if (a->tos > b->tos)
+ return 1;
+
+ if (a->priority < b->priority)
+ return -1;
+ if (a->priority > b->priority)
+ return 1;
+
+ if (a->table < b->table)
+ return -1;
+ if (a->table > b->table)
+ return 1;
+
+ return memcmp(&a->dst_addr, &b->dst_addr, FAMILY_ADDRESS_SIZE(a->family));
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ return 0;
+ }
+}
+
+static const struct hash_ops route_hash_ops = {
+ .hash = route_hash_func,
+ .compare = route_compare_func
+};
+
+int route_remove(Route *route, Link *link,
sd_netlink_message_handler_t callback) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
int r;
@@ -294,8 +363,7 @@ int config_parse_gateway(const char *unit,
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", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Route is invalid, ignoring assignment: %s", rvalue);
return 0;
}
@@ -306,6 +374,46 @@ int config_parse_gateway(const char *unit,
return 0;
}
+int config_parse_preferred_src(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;
+ union in_addr_union buffer;
+ int r, f;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = route_new_static(network, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = in_addr_from_string_auto(rvalue, &f, &buffer);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Preferred source is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ n->family = f;
+ n->prefsrc_addr = buffer;
+ n = NULL;
+
+ return 0;
+}
+
int config_parse_destination(const char *unit,
const char *filename,
unsigned line,
@@ -345,14 +453,12 @@ int config_parse_destination(const char *unit,
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);
+ log_syntax(unit, LOG_ERR, filename, line, r, "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);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown address family, ignoring assignment: %s", address);
return 0;
}
@@ -360,8 +466,7 @@ int config_parse_destination(const char *unit,
if (e) {
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);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
return 0;
}
} else {
@@ -456,8 +561,7 @@ int config_parse_route_scope(const char *unit,
else if (streq(rvalue, "global"))
n->scope = RT_SCOPE_UNIVERSE;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unknown route scope: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route scope: %s", rvalue);
return 0;
}