chiark / gitweb /
networkd: add support for source routing
authorTom Gundersen <teg@jklm.no>
Thu, 4 Dec 2014 14:52:21 +0000 (15:52 +0100)
committerTom Gundersen <teg@jklm.no>
Thu, 4 Dec 2014 15:02:05 +0000 (16:02 +0100)
man/systemd.network.xml
src/libsystemd/sd-rtnl/rtnl-message.c
src/network/networkd-network-gperf.gperf
src/network/networkd-route.c
src/network/networkd.h
src/systemd/sd-rtnl.h

index c9c946c..a913fdf 100644 (file)
                                         </listitem>
                                 </varlistentry>
                                 <varlistentry>
+                                        <term><varname>Source=</varname></term>
+                                        <listitem>
+                                                <para>The source prefix of the route. Possibly followed by a slash and the
+                                                prefixlength. If omitted, a full-length host route is assumed.</para>
+                                        </listitem>
+                                </varlistentry>
+                                <varlistentry>
                                         <term><varname>Metric=</varname></term>
                                         <listitem>
                                                 <para>The metric of the route. An unsigned integer</para>
index a2f7547..4491a00 100644 (file)
@@ -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;
 
index 1aef090..4f0e05a 100644 (file)
@@ -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)
index 25db676..4e389db 100644 (file)
@@ -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;
index 1297ef9..07917f0 100644 (file)
@@ -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);
index bf1dde4..4754d29 100644 (file)
@@ -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);