networkd: route - add expiration support
authorTom Gundersen <teg@jklm.no>
Mon, 26 Oct 2015 11:29:37 +0000 (12:29 +0100)
committerTom Gundersen <teg@jklm.no>
Fri, 30 Oct 2015 11:32:49 +0000 (12:32 +0100)
This should really live in the kernel, but the netlink API currently
does not support it. Until support has been added, expire the route
from userspace.

src/network/networkd-link.c
src/network/networkd-route.c
src/network/networkd-route.h

index 9beaa78..7316a08 100644 (file)
@@ -26,6 +26,7 @@
 #include "alloc-util.h"
 #include "bus-util.h"
 #include "dhcp-lease-internal.h"
+#include "event-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "netlink-util.h"
@@ -2227,6 +2228,9 @@ network_file_fail:
                         return log_oom();
 
                 STRV_FOREACH(route_str, routes_strv) {
+                        Route *route;
+                        _cleanup_event_source_unref_ sd_event_source *expire = NULL;
+                        usec_t lifetime;
                         char *prefixlen_str;
                         int family;
                         unsigned char prefixlen, tos, table;
@@ -2240,9 +2244,11 @@ network_file_fail:
 
                         *prefixlen_str ++ = '\0';
 
-                        r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu", &prefixlen, &tos, &priority, &table);
-                        if (r != 4) {
-                                log_link_debug(link, "Failed to parse destination prefix length, tos, priority or table %s", prefixlen_str);
+                        r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime);
+                        if (r != 5) {
+                                log_link_debug(link,
+                                               "Failed to parse destination prefix length, tos, priority, table or expiration %s",
+                                               prefixlen_str);
                                 continue;
                         }
 
@@ -2252,9 +2258,21 @@ network_file_fail:
                                 continue;
                         }
 
-                        r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, NULL);
+                        r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, &route);
                         if (r < 0)
                                 return log_link_error_errno(link, r, "Failed to add route: %m");
+
+                        if (lifetime != USEC_INFINITY) {
+                                r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), lifetime,
+                                                      0, route_expire_handler, route);
+                                if (r < 0)
+                                        log_link_warning_errno(link, r, "Could not arm route expiration handler: %m");
+                        }
+
+                        route->lifetime = lifetime;
+                        sd_event_source_unref(route->expire);
+                        route->expire = expire;
+                        expire = NULL;
                 }
         }
 
@@ -2741,8 +2759,8 @@ int link_save(Link *link) {
                         if (r < 0)
                                 goto fail;
 
-                        fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%hhu", space ? " " : "", route_str,
-                                route->dst_prefixlen, route->tos, route->priority, route->table);
+                        fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%hhu/"USEC_FMT, space ? " " : "", route_str,
+                                route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
                         space = true;
                 }
 
index 7c0d03c..f4bbd06 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "alloc-util.h"
 #include "conf-parser.h"
+#include "event-util.h"
 #include "in-addr-util.h"
 #include "netlink-util.h"
 #include "networkd-route.h"
@@ -41,6 +42,7 @@ int route_new(Route **ret) {
         route->scope = RT_SCOPE_UNIVERSE;
         route->protocol = RTPROT_UNSPEC;
         route->table = RT_TABLE_DEFAULT;
+        route->lifetime = USEC_INFINITY;
 
         *ret = route;
         route = NULL;
@@ -101,6 +103,8 @@ void route_free(Route *route) {
                 set_remove(route->link->routes_foreign, route);
         }
 
+        sd_event_source_unref(route->expire);
+
         free(route);
 }
 
@@ -410,9 +414,24 @@ int route_remove(Route *route, Link *link,
         return 0;
 }
 
+int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
+        Route *route = userdata;
+        int r;
+
+        assert(route);
+
+        r = route_remove(route, route->link, NULL);
+        if (r < 0)
+                log_warning_errno(r, "Could not remove route: %m");
+
+        return 1;
+}
+
 int route_configure(Route *route, Link *link,
                     sd_netlink_message_handler_t callback) {
         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
+        _cleanup_event_source_unref_ sd_event_source *expire = NULL;
+        usec_t lifetime;
         int r;
 
         assert(link);
@@ -489,10 +508,26 @@ int route_configure(Route *route, Link *link,
 
         link_ref(link);
 
-        r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL);
+        lifetime = route->lifetime;
+
+        r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route);
         if (r < 0)
                 return log_error_errno(r, "Could not add route: %m");
 
+        /* TODO: drop expiration handling once it can be pushed into the kernel */
+        route->lifetime = lifetime;
+
+        if (route->lifetime != USEC_INFINITY) {
+                r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
+                                      route->lifetime, 0, route_expire_handler, route);
+                if (r < 0)
+                        return log_error_errno(r, "Could not arm expiration timer: %m");
+        }
+
+        sd_event_source_unref(route->expire);
+        route->expire = expire;
+        expire = NULL;
+
         return 0;
 }
 
index 785bd16..d0a5183 100644 (file)
@@ -46,6 +46,9 @@ struct Route {
         union in_addr_union src;
         union in_addr_union prefsrc;
 
+        usec_t lifetime;
+        sd_event_source *expire;
+
         LIST_FIELDS(Route, routes);
 };
 
@@ -61,6 +64,8 @@ int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned
 int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol);
 void route_drop(Route *route);
 
+int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free);
 #define _cleanup_route_free_ _cleanup_(route_freep)