]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-link.c
networkd: Use only a generic CONFIGURING state
[thirdparty/systemd.git] / src / network / networkd-link.c
index f4ab8aadb80b3eb02cdb1ae7284c21b9ecdbbf05..637bd3c554d80f39e1bb8e9367144e05759ab94e 100644 (file)
 #include "bus-util.h"
 #include "dhcp-identifier.h"
 #include "dhcp-lease-internal.h"
+#include "env-file.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "missing_network.h"
 #include "netlink-util.h"
 #include "network-internal.h"
 #include "networkd-ipv6-proxy-ndp.h"
@@ -25,6 +27,7 @@
 #include "stdio-util.h"
 #include "string-table.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "util.h"
 #include "virt.h"
 
@@ -270,7 +273,7 @@ static int link_enable_ipv6(Link *link) {
 
         p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/disable_ipv6");
 
-        r = write_string_file(p, one_zero(disabled), WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        r = write_string_file(p, one_zero(disabled), WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot %s IPv6 for interface %s: %m",
                                        enable_disable(!disabled), link->ifname);
@@ -449,16 +452,19 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
         if (r < 0)
                 return r;
 
-        link = new0(Link, 1);
+        link = new(Link, 1);
         if (!link)
                 return -ENOMEM;
 
-        link->n_ref = 1;
-        link->manager = manager;
-        link->state = LINK_STATE_PENDING;
-        link->rtnl_extended_attrs = true;
-        link->ifindex = ifindex;
-        link->iftype = iftype;
+        *link = (Link) {
+                .n_ref = 1,
+                .manager = manager,
+                .state = LINK_STATE_PENDING,
+                .rtnl_extended_attrs = true,
+                .ifindex = ifindex,
+                .iftype = iftype,
+        };
+
         link->ifname = strdup(ifname);
         if (!link->ifname)
                 return -ENOMEM;
@@ -469,6 +475,10 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
                         return -ENOMEM;
         }
 
+        r = sd_netlink_message_read_u32(message, IFLA_MASTER, (uint32_t *)&link->master_ifindex);
+        if (r < 0)
+                log_link_debug_errno(link, r, "New device has no master, continuing without");
+
         r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
         if (r < 0)
                 log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
@@ -499,6 +509,17 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
         return 0;
 }
 
+static void link_detach_from_manager(Link *link) {
+        if (!link || !link->manager)
+                return;
+
+        hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
+        set_remove(link->manager->links_requesting_uuid, link);
+        link_clean(link);
+
+        link->manager = NULL;
+}
+
 static Link *link_free(Link *link) {
         Address *address;
         Link *carrier;
@@ -548,11 +569,7 @@ static Link *link_free(Link *link) {
         sd_ndisc_unref(link->ndisc);
         sd_radv_unref(link->radv);
 
-        if (link->manager) {
-                hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
-                set_remove(link->manager->links_requesting_uuid, link);
-                link_clean(link);
-        }
+        link_detach_from_manager(link);
 
         free(link->ifname);
 
@@ -576,14 +593,6 @@ static Link *link_free(Link *link) {
 
 DEFINE_TRIVIAL_REF_UNREF_FUNC(Link, link, link_free);
 
-void link_netlink_destroy_callback(void *userdata) {
-        Link *link = userdata;
-
-        assert(userdata);
-
-        link_unref(link);
-}
-
 int link_get(Manager *m, int ifindex, Link **ret) {
         Link *link;
 
@@ -710,7 +719,7 @@ static void link_enter_configured(Link *link) {
         assert(link);
         assert(link->network);
 
-        if (link->state != LINK_STATE_SETTING_ROUTES)
+        if (link->state != LINK_STATE_CONFIGURING)
                 return;
 
         log_link_info(link, "Configured");
@@ -732,6 +741,9 @@ void link_check_ready(Link *link) {
         if (!link->network)
                 return;
 
+        if (!link->addresses_configured)
+                return;
+
         if (!link->static_routes_configured)
                 return;
 
@@ -780,13 +792,14 @@ static int link_set_routing_policy_rule(Link *link) {
 
         LIST_FOREACH(rules, rule, link->network->rules) {
                 r = routing_policy_rule_get(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
-                                            rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, &rrule);
-                if (r == 1) {
+                                            rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif,
+                                            rule->protocol, &rule->sport, &rule->dport, &rrule);
+                if (r == 0) {
                         (void) routing_policy_rule_make_local(link->manager, rrule);
                         continue;
                 }
 
-                r = routing_policy_rule_configure(rule, link, link_routing_policy_rule_handler, false);
+                r = routing_policy_rule_configure(rule, link, NULL, false);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "Could not set routing policy rules: %m");
                         link_enter_failed(link);
@@ -806,15 +819,13 @@ static int link_set_routing_policy_rule(Link *link) {
         return 0;
 }
 
-static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
         assert(link->route_messages > 0);
-        assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
-                      LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
-                      LINK_STATE_LINGER));
+        assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
+                      LINK_STATE_FAILED, LINK_STATE_LINGER));
 
         link->route_messages--;
 
@@ -834,28 +845,41 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata
         return 1;
 }
 
-static int link_enter_set_routes(Link *link) {
+static int link_request_set_routes(Link *link) {
+        enum {
+                PHASE_NON_GATEWAY, /* First phase: Routes without a gateway */
+                PHASE_GATEWAY,     /* Second phase: Routes with a gateway */
+                _PHASE_MAX
+        } phase;
         Route *rt;
         int r;
 
         assert(link);
         assert(link->network);
-        assert(link->state == LINK_STATE_SETTING_ADDRESSES);
+        assert(link->addresses_configured);
+        assert(link->address_messages == 0);
+        assert(link->state != _LINK_STATE_INVALID);
+
+        link_set_state(link, LINK_STATE_CONFIGURING);
 
         (void) link_set_routing_policy_rule(link);
 
-        link_set_state(link, LINK_STATE_SETTING_ROUTES);
+        /* First add the routes that enable us to talk to gateways, then add in the others that need a gateway. */
+        for (phase = 0; phase < _PHASE_MAX; phase++)
+                LIST_FOREACH(routes, rt, link->network->static_routes) {
 
-        LIST_FOREACH(routes, rt, link->network->static_routes) {
-                r = route_configure(rt, link, route_handler);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "Could not set routes: %m");
-                        link_enter_failed(link);
-                        return r;
-                }
+                        if (in_addr_is_null(rt->family, &rt->gw) != (phase == PHASE_NON_GATEWAY))
+                                continue;
 
-                link->route_messages++;
-        }
+                        r = route_configure(rt, link, route_handler);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "Could not set routes: %m");
+                                link_enter_failed(link);
+                                return r;
+                        }
+
+                        link->route_messages++;
+                }
 
         if (link->route_messages == 0) {
                 link->static_routes_configured = true;
@@ -866,26 +890,7 @@ static int link_enter_set_routes(Link *link) {
         return 0;
 }
 
-int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
-        int r;
-
-        assert(m);
-        assert(link);
-        assert(link->ifname);
-
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return 1;
-
-        r = sd_netlink_message_get_errno(m);
-        if (r < 0 && r != -ESRCH)
-                log_link_warning_errno(link, r, "Could not drop route: %m");
-
-        return 1;
-}
-
-static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(rtnl);
@@ -893,7 +898,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
         assert(link);
         assert(link->ifname);
         assert(link->address_messages > 0);
-        assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
+        assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
                LINK_STATE_FAILED, LINK_STATE_LINGER));
 
         link->address_messages--;
@@ -909,39 +914,13 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
 
         if (link->address_messages == 0) {
                 log_link_debug(link, "Addresses set");
-                link_enter_set_routes(link);
+                link->addresses_configured = true;
+                link_request_set_routes(link);
         }
 
         return 1;
 }
 
-static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
-        int r;
-
-        assert(rtnl);
-        assert(m);
-        assert(link);
-        assert(link->ifname);
-        assert(link->address_label_messages > 0);
-
-        link->address_label_messages--;
-
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return 1;
-
-        r = sd_netlink_message_get_errno(m);
-        if (r < 0 && r != -EEXIST)
-                log_link_warning_errno(link, r, "could not set address label: %m");
-        else if (r >= 0)
-                manager_rtnl_process_address(rtnl, m, link->manager);
-
-        if (link->address_label_messages == 0)
-                log_link_debug(link, "Addresses label set");
-
-        return 1;
-}
-
 static int link_push_uplink_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
         _cleanup_free_ struct in_addr *addresses = NULL;
         size_t n_addresses = 0, n_allocated = 0;
@@ -1053,7 +1032,7 @@ static int link_set_bridge_fdb(Link *link) {
         return 0;
 }
 
-static int link_enter_set_addresses(Link *link) {
+static int link_request_set_addresses(Link *link) {
         AddressLabel *label;
         Address *ad;
         int r;
@@ -1066,7 +1045,7 @@ static int link_enter_set_addresses(Link *link) {
         if (r < 0)
                 return r;
 
-        link_set_state(link, LINK_STATE_SETTING_ADDRESSES);
+        link_set_state(link, LINK_STATE_CONFIGURING);
 
         LIST_FOREACH(addresses, ad, link->network->static_addresses) {
                 r = address_configure(ad, link, address_handler, false);
@@ -1080,7 +1059,7 @@ static int link_enter_set_addresses(Link *link) {
         }
 
         LIST_FOREACH(labels, label, link->network->address_labels) {
-                r = address_label_configure(label, link, address_label_handler, false);
+                r = address_label_configure(label, link, NULL, false);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "Could not set address label: %m");
                         link_enter_failed(link);
@@ -1207,32 +1186,15 @@ static int link_enter_set_addresses(Link *link) {
                 log_link_debug(link, "Offering DHCPv4 leases");
         }
 
-        if (link->address_messages == 0)
-                link_enter_set_routes(link);
-        else
+        if (link->address_messages == 0) {
+                link->addresses_configured = true;
+                link_request_set_routes(link);
+        } else
                 log_link_debug(link, "Setting addresses");
 
         return 0;
 }
 
-int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
-        int r;
-
-        assert(m);
-        assert(link);
-        assert(link->ifname);
-
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return 1;
-
-        r = sd_netlink_message_get_errno(m);
-        if (r < 0 && r != -EADDRNOTAVAIL)
-                log_link_warning_errno(link, r, "Could not drop address: %m");
-
-        return 1;
-}
-
 static int link_set_bridge_vlan(Link *link) {
         int r = 0;
 
@@ -1252,15 +1214,14 @@ static int link_set_proxy_arp(Link *link) {
 
         p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/proxy_arp");
 
-        r = write_string_file(p, one_zero(link->network->proxy_arp), WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        r = write_string_file(p, one_zero(link->network->proxy_arp), WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface: %m");
 
         return 0;
 }
 
-static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -1278,8 +1239,7 @@ static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd
 
 static int link_configure_after_setting_mtu(Link *link);
 
-static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(m);
@@ -1340,8 +1300,8 @@ int link_set_mtu(Link *link, uint32_t mtu) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append MTU: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, set_mtu_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, set_mtu_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1351,8 +1311,7 @@ int link_set_mtu(Link *link, uint32_t mtu) {
         return 0;
 }
 
-static int set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(m);
@@ -1411,8 +1370,8 @@ static int link_set_flags(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set link flags: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, set_flags_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, set_flags_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1469,7 +1428,12 @@ static int link_set_bridge(Link *link) {
                 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
+        }
 
+        if (link->network->multicast_to_unicast >= 0) {
+                r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_TO_UCAST, link->network->multicast_to_unicast);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_TO_UCAST attribute: %m");
         }
 
         if (link->network->cost != 0) {
@@ -1477,6 +1441,7 @@ static int link_set_bridge(Link *link) {
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m");
         }
+
         if (link->network->priority != LINK_BRIDGE_PORT_PRIORITY_INVALID) {
                 r = sd_netlink_message_append_u16(req, IFLA_BRPORT_PRIORITY, link->network->priority);
                 if (r < 0)
@@ -1487,8 +1452,8 @@ static int link_set_bridge(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, link_set_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1540,8 +1505,8 @@ static int link_bond_set(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, set_flags_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, set_flags_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r,  "Could not send rtnetlink message: %m");
 
@@ -1740,8 +1705,7 @@ bool link_has_carrier(Link *link) {
         return false;
 }
 
-static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -1833,8 +1797,8 @@ int link_up(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1859,8 +1823,8 @@ static int link_up_can(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set link flags: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1949,8 +1913,8 @@ static int link_set_can(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to close netlink container: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, m, link_set_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, m, link_set_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1969,8 +1933,7 @@ static int link_set_can(Link *link) {
         return r;
 }
 
-static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -2007,8 +1970,8 @@ int link_down(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set link flags: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, link_down_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_down_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -2261,6 +2224,9 @@ void link_drop(Link *link) {
         log_link_debug(link, "Link removed");
 
         (void) unlink(link->state_file);
+
+        link_detach_from_manager(link);
+
         link_unref(link);
 
         return;
@@ -2309,11 +2275,10 @@ static int link_joined(Link *link) {
         if (!link_has_carrier(link) && !link->network->configure_without_carrier)
                 return 0;
 
-        return link_enter_set_addresses(link);
+        return link_request_set_addresses(link);
 }
 
-static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        Link *link = userdata;
+static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -2347,7 +2312,7 @@ static int link_enter_join_netdev(Link *link) {
         assert(link->network);
         assert(link->state == LINK_STATE_PENDING);
 
-        link_set_state(link, LINK_STATE_ENSLAVING);
+        link_set_state(link, LINK_STATE_CONFIGURING);
 
         link_dirty(link);
 
@@ -2358,6 +2323,10 @@ static int link_enter_join_netdev(Link *link) {
                 return link_joined(link);
 
         if (link->network->bond) {
+                if (link->network->bond->state == NETDEV_STATE_READY &&
+                    link->network->bond->ifindex == link->master_ifindex)
+                        return link_joined(link);
+
                 log_struct(LOG_DEBUG,
                            LOG_LINK_INTERFACE(link),
                            LOG_NETDEV_INTERFACE(link->network->bond),
@@ -2455,7 +2424,7 @@ static int link_set_ipv4_forward(Link *link) {
          * primarily to keep IPv4 and IPv6 packet forwarding behaviour
          * somewhat in sync (see below). */
 
-        r = write_string_file("/proc/sys/net/ipv4/ip_forward", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        r = write_string_file("/proc/sys/net/ipv4/ip_forward", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
 
@@ -2477,7 +2446,7 @@ static int link_set_ipv6_forward(Link *link) {
          * same behaviour there and also propagate the setting from
          * one to all, to keep things simple (see above). */
 
-        r = write_string_file("/proc/sys/net/ipv6/conf/all/forwarding", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        r = write_string_file("/proc/sys/net/ipv6/conf/all/forwarding", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m");
 
@@ -2497,7 +2466,7 @@ static int link_set_ipv6_privacy_extensions(Link *link) {
         p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr");
         xsprintf(buf, "%u", (unsigned) link->network->ipv6_privacy_extensions);
 
-        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m");
 
@@ -2521,7 +2490,7 @@ static int link_set_ipv6_accept_ra(Link *link) {
         p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra");
 
         /* We handle router advertisements ourselves, tell the kernel to GTFO */
-        r = write_string_file(p, "0", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        r = write_string_file(p, "0", WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface: %m");
 
@@ -2549,7 +2518,7 @@ static int link_set_ipv6_dad_transmits(Link *link) {
         p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/dad_transmits");
         xsprintf(buf, "%i", link->network->ipv6_dad_transmits);
 
-        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface: %m");
 
@@ -2577,7 +2546,7 @@ static int link_set_ipv6_hop_limit(Link *link) {
         p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/hop_limit");
         xsprintf(buf, "%i", link->network->ipv6_hop_limit);
 
-        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface: %m");
 
@@ -2603,13 +2572,45 @@ static int link_set_ipv6_mtu(Link *link) {
 
         xsprintf(buf, "%" PRIu32, link->network->ipv6_mtu);
 
-        r = write_string_file(p, buf, 0);
+        r = write_string_file(p, buf, WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot set IPv6 MTU for interface: %m");
 
         return 0;
 }
 
+static bool link_is_static_address_configured(Link *link, Address *address) {
+        Address *net_address;
+
+        assert(link);
+        assert(address);
+
+        if (!link->network)
+                return false;
+
+        LIST_FOREACH(addresses, net_address, link->network->static_addresses)
+                if (address_equal(net_address, address))
+                        return true;
+
+        return false;
+}
+
+static bool link_is_static_route_configured(Link *link, Route *route) {
+        Route *net_route;
+
+        assert(link);
+        assert(route);
+
+        if (!link->network)
+                return false;
+
+        LIST_FOREACH(routes, net_route, link->network->static_routes)
+                if (route_equal(net_route, route))
+                        return true;
+
+        return false;
+}
+
 static int link_drop_foreign_config(Link *link) {
         Address *address;
         Route *route;
@@ -2621,9 +2622,15 @@ static int link_drop_foreign_config(Link *link) {
                 if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1)
                         continue;
 
-                r = address_remove(address, link, link_address_remove_handler);
-                if (r < 0)
-                        return r;
+                if (link_is_static_address_configured(link, address)) {
+                        r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
+                        if (r < 0)
+                                return log_link_error_errno(link, r, "Failed to add address: %m");
+                } else {
+                        r = address_remove(address, link, NULL);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         SET_FOREACH(route, link->routes_foreign, i) {
@@ -2631,9 +2638,15 @@ static int link_drop_foreign_config(Link *link) {
                 if (route->protocol == RTPROT_KERNEL)
                         continue;
 
-                r = route_remove(route, link, link_route_remove_handler);
-                if (r < 0)
-                        return r;
+                if (link_is_static_route_configured(link, route)) {
+                        r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL);
+                        if (r < 0)
+                                return r;
+                } else {
+                        r = route_remove(route, link, NULL);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         return 0;
@@ -2650,7 +2663,7 @@ static int link_drop_config(Link *link) {
                 if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1)
                         continue;
 
-                r = address_remove(address, link, link_address_remove_handler);
+                r = address_remove(address, link, NULL);
                 if (r < 0)
                         return r;
 
@@ -2669,7 +2682,7 @@ static int link_drop_config(Link *link) {
                 if (route->protocol == RTPROT_KERNEL)
                         continue;
 
-                r = route_remove(route, link, link_route_remove_handler);
+                r = route_remove(route, link, NULL);
                 if (r < 0)
                         return r;
         }
@@ -3088,8 +3101,8 @@ static int link_initialized_and_synced(Link *link) {
         return 1;
 }
 
-static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        (void) link_initialized_and_synced(userdata);
+static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        (void) link_initialized_and_synced(link);
         return 1;
 }
 
@@ -3122,8 +3135,8 @@ int link_initialized(Link *link, sd_device *device) {
         if (r < 0)
                 return r;
 
-        r = sd_netlink_call_async(link->manager->rtnl, NULL, req, link_initialized_handler,
-                                  link_netlink_destroy_callback, link, 0, __func__);
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_initialized_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return r;
 
@@ -3145,13 +3158,12 @@ static int link_load(Link *link) {
 
         assert(link);
 
-        r = parse_env_file(NULL, link->state_file, NEWLINE,
+        r = parse_env_file(NULL, link->state_file,
                            "NETWORK_FILE", &network_file,
                            "ADDRESSES", &addresses,
                            "ROUTES", &routes,
                            "DHCP4_ADDRESS", &dhcp4_address,
-                           "IPV4LL_ADDRESS", &ipv4ll_address,
-                           NULL);
+                           "IPV4LL_ADDRESS", &ipv4ll_address);
         if (r < 0 && r != -ENOENT)
                 return log_link_error_errno(link, r, "Failed to read %s: %m", link->state_file);
 
@@ -3325,8 +3337,8 @@ ipv4ll_address_fail:
 int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         char ifindex_str[2 + DECIMAL_STR_MAX(int)];
-        int initialized, r;
         Link *link;
+        int r;
 
         assert(m);
         assert(m->rtnl);
@@ -3354,12 +3366,12 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
                         goto failed;
                 }
 
-                r = sd_device_get_is_initialized(device, &initialized);
+                r = sd_device_get_is_initialized(device);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "Could not determine whether the device is initialized or not: %m");
                         goto failed;
                 }
-                if (!initialized) {
+                if (r == 0) {
                         /* not yet ready */
                         log_link_debug(link, "link pending udev initialization...");
                         return 0;
@@ -3413,7 +3425,7 @@ static int link_carrier_gained(Link *link) {
                         return r;
                 }
 
-                r = link_enter_set_addresses(link);
+                r = link_request_set_addresses(link);
                 if (r < 0)
                         return r;
         }
@@ -3496,7 +3508,7 @@ int link_update(Link *link, sd_netlink_message *m) {
 
         if (link->state == LINK_STATE_LINGER) {
                 log_link_info(link, "Link readded");
-                link_set_state(link, LINK_STATE_ENSLAVING);
+                link_set_state(link, LINK_STATE_CONFIGURING);
 
                 r = link_new_carrier_maps(link);
                 if (r < 0)
@@ -4024,9 +4036,7 @@ void link_clean(Link *link) {
 
 static const char* const link_state_table[_LINK_STATE_MAX] = {
         [LINK_STATE_PENDING] = "pending",
-        [LINK_STATE_ENSLAVING] = "configuring",
-        [LINK_STATE_SETTING_ADDRESSES] = "configuring",
-        [LINK_STATE_SETTING_ROUTES] = "configuring",
+        [LINK_STATE_CONFIGURING] = "configuring",
         [LINK_STATE_CONFIGURED] = "configured",
         [LINK_STATE_UNMANAGED] = "unmanaged",
         [LINK_STATE_FAILED] = "failed",