diff options
author | Tom Gundersen <teg@jklm.no> | 2014-12-04 15:52:21 +0100 |
---|---|---|
committer | Tom Gundersen <teg@jklm.no> | 2014-12-04 16:02:05 +0100 |
commit | 9e7e440835c43d81ffdbc299d2c07daaa641ed50 (patch) | |
tree | 9b55e90d4085997aeebaa738198765d2fa5bac4a /src | |
parent | 66bba0e701b95dc42ed53e8f0799a7e2b944c147 (diff) |
networkd: add support for source routing
Diffstat (limited to 'src')
-rw-r--r-- | src/libsystemd/sd-rtnl/rtnl-message.c | 18 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 1 | ||||
-rw-r--r-- | src/network/networkd-route.c | 49 | ||||
-rw-r--r-- | src/network/networkd.h | 2 | ||||
-rw-r--r-- | src/systemd/sd-rtnl.h | 1 |
5 files changed, 62 insertions, 9 deletions
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c index a2f75471b4..4491a00f4f 100644 --- a/src/libsystemd/sd-rtnl/rtnl-message.c +++ b/src/libsystemd/sd-rtnl/rtnl-message.c @@ -114,6 +114,24 @@ int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char pr return 0; } +int sd_rtnl_message_route_set_src_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + if ((rtm->rtm_family == AF_INET && prefixlen > 32) || + (rtm->rtm_family == AF_INET6 && prefixlen > 128)) + return -ERANGE; + + rtm->rtm_src_len = prefixlen; + + return 0; +} + int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) { struct rtmsg *rtm; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 1aef09007a..4f0e05aeb6 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -47,6 +47,7 @@ Address.Broadcast, config_parse_broadcast, 0, Address.Label, config_parse_label, 0, 0 Route.Gateway, config_parse_gateway, 0, 0 Route.Destination, config_parse_destination, 0, 0 +Route.Source, config_parse_destination, 0, 0 Route.Metric, config_parse_route_priority, 0, 0 DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 25db676f05..4e389db5ef 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -138,6 +138,19 @@ int route_drop(Route *route, Link *link, 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); @@ -207,6 +220,19 @@ int route_configure(Route *route, Link *link, 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_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"); + } + 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); @@ -298,6 +324,7 @@ int config_parse_destination(const char *unit, _cleanup_route_free_ Route *n = NULL; const char *address, *e; union in_addr_union buffer; + unsigned char prefixlen; int r, f; assert(filename); @@ -310,7 +337,7 @@ int config_parse_destination(const char *unit, if (r < 0) return r; - /* Destination=address/prefixlen */ + /* Destination|Source=address/prefixlen */ /* address */ e = strchr(rvalue, '/'); @@ -328,29 +355,33 @@ int config_parse_destination(const char *unit, /* 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); return 0; } - - n->dst_prefixlen = (unsigned char) i; } else { switch (n->family) { case AF_INET: - n->dst_prefixlen = 32; + prefixlen = 32; break; case AF_INET6: - n->dst_prefixlen = 128; + prefixlen = 128; break; } } n->family = f; - n->dst_addr = buffer; + 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; diff --git a/src/network/networkd.h b/src/network/networkd.h index 1297ef98a7..07917f0ef4 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -147,12 +147,14 @@ struct Route { int family; unsigned char dst_prefixlen; + unsigned char src_prefixlen; unsigned char scope; uint32_t metrics; unsigned char protocol; /* RTPROT_* */ union in_addr_union in_addr; union in_addr_union dst_addr; + union in_addr_union src_addr; union in_addr_union prefsrc_addr; LIST_FIELDS(Route, routes); diff --git a/src/systemd/sd-rtnl.h b/src/systemd/sd-rtnl.h index bf1dde4008..4754d29157 100644 --- a/src/systemd/sd-rtnl.h +++ b/src/systemd/sd-rtnl.h @@ -102,6 +102,7 @@ int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags); int sd_rtnl_message_link_get_type(sd_rtnl_message *m, unsigned *type); int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen); +int sd_rtnl_message_route_set_src_prefixlen(sd_rtnl_message *m, unsigned char prefixlen); int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope); int sd_rtnl_message_route_get_family(sd_rtnl_message *m, int *family); int sd_rtnl_message_route_get_dst_len(sd_rtnl_message *m, unsigned char *dst_len); |