chiark / gitweb /
networkd: smooth transition from ipv4ll to dhcp address
authorUmut Tezduyar Lindskog <umut.tezduyar@axis.com>
Wed, 2 Apr 2014 19:31:12 +0000 (21:31 +0200)
committerTom Gundersen <teg@jklm.no>
Thu, 3 Apr 2014 14:00:25 +0000 (16:00 +0200)
Currently when both ipv4ll and dhcp are enabled, ipv4ll
address (if one has been claimed) is removed when dhcp
address is aquired. This is not the best thing to do
since there might be clients unaware of the removal
trying to communicate.

This patch provides a smooth transition between ipv4ll
and dhcp. If ipv4ll address was claimed [1] before dhcp,
address is marked as deprecated. Deprecated address is still
a valid address and packets can be received on it but address
cannot be selected as a source address. If dhcp lease cannot
be extended, then ipv4ll address is marked as valid again.

[1] If there is no collision, claiming IPv4LL takes between 4 to
7 seconds.

12 files changed:
TODO
man/systemd.network.xml
src/libsystemd-network/sd-ipv4ll.c
src/libsystemd/sd-rtnl/rtnl-message.c
src/libsystemd/sd-rtnl/rtnl-types.c
src/libsystemd/sd-rtnl/rtnl-types.h
src/libsystemd/sd-rtnl/test-rtnl.c
src/network/networkd-address.c
src/network/networkd-link.c
src/network/networkd.h
src/systemd/sd-ipv4ll.h
src/systemd/sd-rtnl.h

diff --git a/TODO b/TODO
index 2d56e816aae8faa81b95694c7957954196a2a4c7..4ff69ff144fc41f876778f35aabdf2d8a5b9167d 100644 (file)
--- a/TODO
+++ b/TODO
@@ -665,7 +665,6 @@ Features:
    - add reduced [Link] support to .network files
    - add IPv4LL tests (inspire by DHCP)
    - add Scope= parsing option for [Network]
    - add reduced [Link] support to .network files
    - add IPv4LL tests (inspire by DHCP)
    - add Scope= parsing option for [Network]
-   - have smooth transition from LL to routable address, without disconnecting clients.
 
 * sd-network:
    - make sure ipv4ll and dhcp clients can handle changing mac addresses while running
 
 * sd-network:
    - make sure ipv4ll and dhcp clients can handle changing mac addresses while running
index f3b3b315b6589cf2a8aae89fc8e915b4088565ad..f49de17ee175c64f530ecfc3140d7de27ae11485 100644 (file)
                                         <term><varname>IPv4LL=</varname></term>
                                         <listitem>
                                                 <para>A boolean. When true, enables IPv4 link-local support.
                                         <term><varname>IPv4LL=</varname></term>
                                         <listitem>
                                                 <para>A boolean. When true, enables IPv4 link-local support.
-                                                If <literal>DHCP=</literal> is also true, IPv4 link-local
-                                                address will be removed upon acquiring a DHCP lease.
+                                                If <literal>DHCP=</literal> is also true, acquiring DHCP address
+                                                will deprecate previously acquired IPv4 link-local address or
+                                                stop acquiring process if there hasn't been one acquired before.
                                                 </para>
                                         </listitem>
                                 </varlistentry>
                                                 </para>
                                         </listitem>
                                 </varlistentry>
index a201139b08eabbd404f055b187c4f5e322ddcac8..81fe85b68bdcf0906c9aa5ec537006611151dd72 100644 (file)
@@ -481,6 +481,12 @@ error:
         return r;
 }
 
         return r;
 }
 
+bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
+        assert_return(ll, -EINVAL);
+
+        return ll->state != IPV4LL_STATE_INIT;
+}
+
 #define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
 
 int sd_ipv4ll_start (sd_ipv4ll *ll) {
 #define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
 
 int sd_ipv4ll_start (sd_ipv4ll *ll) {
index 4ace94ce18465f16e57d97ca0815ab4b8266e4b4..e5854de4c6e8fc9edced662682dec5e3b31cac44 100644 (file)
@@ -286,6 +286,19 @@ int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
         return 0;
 }
 
         return 0;
 }
 
+int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret,
+                             int index, unsigned char family) {
+        int r;
+
+        r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
+        if (r < 0)
+                return r;
+
+        (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
+
+        return 0;
+}
+
 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
         if (m)
                 assert_se(REFCNT_INC(m->n_ref) >= 2);
 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
         if (m)
                 assert_se(REFCNT_INC(m->n_ref) >= 2);
@@ -559,6 +572,24 @@ int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, c
         return 0;
 }
 
         return 0;
 }
 
+int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(info, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
+        if (r < 0)
+                return r;
+
+        r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
         size_t size;
         int r;
 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
         size_t size;
         int r;
@@ -741,6 +772,25 @@ int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, str
         return 0;
 }
 
         return 0;
 }
 
+int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
+        int r;
+        void *attr_data;
+
+        r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
+        if (r < 0)
+                return r;
+
+        r = rtnl_message_read_internal(m, type, &attr_data);
+        if (r < 0)
+                return r;
+        else if ((size_t)r < sizeof(struct ifa_cacheinfo))
+                return -EIO;
+
+        memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
+
+        return 0;
+}
+
 int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
         int r;
         void *attr_data;
 int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
         int r;
         void *attr_data;
index 29ee5bc1c8ed30c6f98758553d989908bbd63835..4e70c9512707e0726ec04e822b31e747558df781 100644 (file)
@@ -216,9 +216,9 @@ static const NLType rtnl_address_types[IFA_MAX + 1] = {
         [IFA_LOCAL]             = { .type = NLA_IN_ADDR },
         [IFA_LABEL]             = { .type = NLA_STRING, .size = IFNAMSIZ - 1 },
         [IFA_BROADCAST]         = { .type = NLA_IN_ADDR }, /* 6? */
         [IFA_LOCAL]             = { .type = NLA_IN_ADDR },
         [IFA_LABEL]             = { .type = NLA_STRING, .size = IFNAMSIZ - 1 },
         [IFA_BROADCAST]         = { .type = NLA_IN_ADDR }, /* 6? */
+        [IFA_CACHEINFO]         = { .type = NLA_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
 /*
         [IFA_ANYCAST],
 /*
         [IFA_ANYCAST],
-        [IFA_CACHEINFO]         = { .len = sizeof(struct ifa_cacheinfo) },
         [IFA_MULTICAST],
 */
 #ifdef IFA_FLAGS
         [IFA_MULTICAST],
 */
 #ifdef IFA_FLAGS
index 2425dc92a3235818cd2acab838378e05f2dde132..7ce9597c847151eb16c0ca2839080ec77e081988 100644 (file)
@@ -31,6 +31,7 @@ enum {
         NLA_STRING,
         NLA_IN_ADDR,
         NLA_ETHER_ADDR,
         NLA_STRING,
         NLA_IN_ADDR,
         NLA_ETHER_ADDR,
+        NLA_CACHE_INFO,
         NLA_NESTED,
         NLA_UNION,
 };
         NLA_NESTED,
         NLA_UNION,
 };
index 44369628f4d904b991325af6ccf0de0a92ede872..529231a70a82d371f4378d6ab0332a4c202d23ba 100644 (file)
@@ -106,6 +106,7 @@ static void test_address_get(sd_rtnl *rtnl, int ifindex) {
         sd_rtnl_message *m;
         sd_rtnl_message *r;
         struct in_addr in_data;
         sd_rtnl_message *m;
         sd_rtnl_message *r;
         struct in_addr in_data;
+        struct ifa_cacheinfo cache;
         char *label;
 
         assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0);
         char *label;
 
         assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0);
@@ -116,6 +117,7 @@ static void test_address_get(sd_rtnl *rtnl, int ifindex) {
         assert_se(sd_rtnl_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0);
         assert_se(sd_rtnl_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0);
         assert_se(sd_rtnl_message_read_string(r, IFA_LABEL, &label) == 0);
         assert_se(sd_rtnl_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0);
         assert_se(sd_rtnl_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0);
         assert_se(sd_rtnl_message_read_string(r, IFA_LABEL, &label) == 0);
+        assert_se(sd_rtnl_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0);
 
         assert_se(sd_rtnl_flush(rtnl) >= 0);
         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
 
         assert_se(sd_rtnl_flush(rtnl) >= 0);
         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
index dd4c822c674a52b44ce8e99a7651fcc91e397b0c..87688a5ae60db115dbc465963a3f50f986ed33aa 100644 (file)
 #include "conf-parser.h"
 #include "network-internal.h"
 
 #include "conf-parser.h"
 #include "network-internal.h"
 
+static void address_init(Address *address) {
+        assert(address);
+
+        address->family = AF_UNSPEC;
+        address->scope = RT_SCOPE_UNIVERSE;
+        address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
+        address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
+}
+
 int address_new_static(Network *network, unsigned section, Address **ret) {
         _cleanup_address_free_ Address *address = NULL;
 
 int address_new_static(Network *network, unsigned section, Address **ret) {
         _cleanup_address_free_ Address *address = NULL;
 
@@ -46,8 +55,7 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
         if (!address)
                 return -ENOMEM;
 
         if (!address)
                 return -ENOMEM;
 
-        address->family = AF_UNSPEC;
-        address->scope = RT_SCOPE_UNIVERSE;
+        address_init(address);
 
         address->network = network;
 
 
         address->network = network;
 
@@ -71,8 +79,7 @@ int address_new_dynamic(Address **ret) {
         if (!address)
                 return -ENOMEM;
 
         if (!address)
                 return -ENOMEM;
 
-        address->family = AF_UNSPEC;
-        address->scope = RT_SCOPE_UNIVERSE;
+        address_init(address);
 
         *ret = address;
         address = NULL;
 
         *ret = address;
         address = NULL;
@@ -140,6 +147,87 @@ int address_drop(Address *address, Link *link,
         return 0;
 }
 
         return 0;
 }
 
+int address_update(Address *address, Link *link,
+                   sd_rtnl_message_handler_t callback) {
+        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+        int r;
+
+        assert(address);
+        assert(address->family == AF_INET || address->family == AF_INET6);
+        assert(link->ifindex > 0);
+        assert(link->manager);
+        assert(link->manager->rtnl);
+
+        r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
+                                     link->ifindex, address->family);
+        if (r < 0) {
+                log_error("Could not allocate RTM_NEWADDR message: %s",
+                          strerror(-r));
+                return r;
+        }
+
+        r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
+        if (r < 0) {
+                log_error("Could not set prefixlen: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
+        if (r < 0) {
+                log_error("Could not set flags: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_rtnl_message_addr_set_scope(req, address->scope);
+        if (r < 0) {
+                log_error("Could not set scope: %s", strerror(-r));
+                return r;
+        }
+
+        if (address->family == AF_INET)
+                r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
+        else if (address->family == AF_INET6)
+                r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
+        if (r < 0) {
+                log_error("Could not append IFA_LOCAL attribute: %s",
+                          strerror(-r));
+                return r;
+        }
+
+        if (address->family == AF_INET) {
+                r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
+                if (r < 0) {
+                        log_error("Could not append IFA_BROADCAST attribute: %s",
+                                  strerror(-r));
+                        return r;
+                }
+        }
+
+        if (address->label) {
+                r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
+                if (r < 0) {
+                        log_error("Could not append IFA_LABEL attribute: %s",
+                                  strerror(-r));
+                        return r;
+                }
+        }
+
+        r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
+        if (r < 0) {
+                log_error("Could not append IFA_CACHEINFO attribute: %s",
+                          strerror(-r));
+                return r;
+        }
+
+        r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+        if (r < 0) {
+                log_error("Could not send rtnetlink message: %s", strerror(-r));
+                return r;
+        }
+
+        return 0;
+}
+
 int address_configure(Address *address, Link *link,
                       sd_rtnl_message_handler_t callback) {
         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
 int address_configure(Address *address, Link *link,
                       sd_rtnl_message_handler_t callback) {
         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
index 4e0fe0a271f128fd3e2612d487c9e994b6c8eee8..63d253d94130e99fc6dbe86dc955cb455078af9d 100644 (file)
@@ -30,6 +30,9 @@
 
 #include "dhcp-lease-internal.h"
 
 
 #include "dhcp-lease-internal.h"
 
+static int ipv4ll_address_update(Link *link, bool deprecate);
+static bool ipv4ll_is_bound(sd_ipv4ll *ll);
+
 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
         _cleanup_link_free_ Link *link = NULL;
         const char *ifname;
 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
         _cleanup_link_free_ Link *link = NULL;
         const char *ifname;
@@ -168,7 +171,6 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 
 static int link_enter_set_routes(Link *link) {
         Route *rt;
 
 static int link_enter_set_routes(Link *link) {
         Route *rt;
-        struct in_addr a;
         int r;
 
         assert(link);
         int r;
 
         assert(link);
@@ -178,7 +180,7 @@ static int link_enter_set_routes(Link *link) {
         link->state = LINK_STATE_SETTING_ROUTES;
 
         if (!link->network->static_routes && !link->dhcp_lease &&
         link->state = LINK_STATE_SETTING_ROUTES;
 
         if (!link->network->static_routes && !link->dhcp_lease &&
-                (!link->ipv4ll || sd_ipv4ll_get_address(link->ipv4ll, &a) < 0))
+                (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
                 return link_enter_configured(link);
 
         log_debug_link(link, "setting routes");
                 return link_enter_configured(link);
 
         log_debug_link(link, "setting routes");
@@ -345,7 +347,6 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 
 static int link_enter_set_addresses(Link *link) {
         Address *ad;
 
 static int link_enter_set_addresses(Link *link) {
         Address *ad;
-        struct in_addr a;
         int r;
 
         assert(link);
         int r;
 
         assert(link);
@@ -355,7 +356,7 @@ static int link_enter_set_addresses(Link *link) {
         link->state = LINK_STATE_SETTING_ADDRESSES;
 
         if (!link->network->static_addresses && !link->dhcp_lease &&
         link->state = LINK_STATE_SETTING_ADDRESSES;
 
         if (!link->network->static_addresses && !link->dhcp_lease &&
-                (!link->ipv4ll || sd_ipv4ll_get_address(link->ipv4ll, &a) < 0))
+                (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
                 return link_enter_set_routes(link);
 
         log_debug_link(link, "setting addresses");
                 return link_enter_set_routes(link);
 
         log_debug_link(link, "setting addresses");
@@ -456,6 +457,28 @@ static int link_enter_set_addresses(Link *link) {
         return 0;
 }
 
         return 0;
 }
 
+static int address_update_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+        Link *link = userdata;
+        int r;
+
+        assert(m);
+        assert(link);
+        assert(link->ifname);
+
+        if (link->state == LINK_STATE_FAILED)
+                return 1;
+
+        r = sd_rtnl_message_get_errno(m);
+        if (r < 0 && r != -ENOENT)
+                log_struct_link(LOG_WARNING, link,
+                                "MESSAGE=%s: could not update address: %s",
+                                link->ifname, strerror(-r),
+                                "ERRNO=%d", -r,
+                                NULL);
+
+        return 0;
+}
+
 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         Link *link = userdata;
         int r;
 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         Link *link = userdata;
         int r;
@@ -753,7 +776,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
 
 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
         Link *link = userdata;
 
 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
         Link *link = userdata;
-        int r;
+        int r = 0;
 
         assert(link);
         assert(link->network);
 
         assert(link);
         assert(link->network);
@@ -792,7 +815,10 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
                         }
 
                         if (event == DHCP_EVENT_EXPIRED && link->network->ipv4ll) {
                         }
 
                         if (event == DHCP_EVENT_EXPIRED && link->network->ipv4ll) {
-                                r = sd_ipv4ll_start (link->ipv4ll);
+                                if (!sd_ipv4ll_is_running(link->ipv4ll))
+                                        r = sd_ipv4ll_start(link->ipv4ll);
+                                else if (ipv4ll_is_bound(link->ipv4ll))
+                                        r = ipv4ll_address_update(link, false);
                                 if (r < 0) {
                                         link_enter_failed(link);
                                         return;
                                 if (r < 0) {
                                         link_enter_failed(link);
                                         return;
@@ -807,7 +833,10 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
                                 return;
                         }
                         if (link->ipv4ll) {
                                 return;
                         }
                         if (link->ipv4ll) {
-                                r = sd_ipv4ll_stop(link->ipv4ll);
+                                if (ipv4ll_is_bound(link->ipv4ll))
+                                        r = ipv4ll_address_update(link, true);
+                                else
+                                        r = sd_ipv4ll_stop(link->ipv4ll);
                                 if (r < 0) {
                                         link_enter_failed(link);
                                         return;
                                 if (r < 0) {
                                         link_enter_failed(link);
                                         return;
@@ -825,11 +854,44 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
         return;
 }
 
         return;
 }
 
-static int ipv4ll_address_lost(sd_ipv4ll *ll, Link *link) {
+static int ipv4ll_address_update(Link *link, bool deprecate) {
+        int r;
+        struct in_addr addr;
+
+        assert(link);
+
+        r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
+        if (r >= 0) {
+                _cleanup_address_free_ Address *address = NULL;
+
+                log_debug_link(link, "IPv4 link-local %s %u.%u.%u.%u",
+                               deprecate ? "deprecate" : "approve",
+                               ADDRESS_FMT_VAL(addr));
+
+                r = address_new_dynamic(&address);
+                if (r < 0) {
+                        log_error_link(link, "Could not allocate address: %s", strerror(-r));
+                        return r;
+                }
+
+                address->family = AF_INET;
+                address->in_addr.in = addr;
+                address->prefixlen = 16;
+                address->scope = RT_SCOPE_LINK;
+                address->cinfo.ifa_prefered = deprecate ? 0 : CACHE_INFO_INFINITY_LIFE_TIME;
+                address->broadcast.s_addr = address->in_addr.in.s_addr | htonl(0xfffffffflu >> address->prefixlen);
+
+                address_update(address, link, &address_update_handler);
+        }
+
+        return 0;
+
+}
+
+static int ipv4ll_address_lost(Link *link) {
         int r;
         struct in_addr addr;
 
         int r;
         struct in_addr addr;
 
-        assert(ll);
         assert(link);
 
         r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
         assert(link);
 
         r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
@@ -870,6 +932,18 @@ static int ipv4ll_address_lost(sd_ipv4ll *ll, Link *link) {
         return 0;
 }
 
         return 0;
 }
 
+static bool ipv4ll_is_bound(sd_ipv4ll *ll) {
+        int r;
+        struct in_addr addr;
+
+        assert(ll);
+
+        r = sd_ipv4ll_get_address(ll, &addr);
+        if (r < 0)
+                return false;
+        return true;
+}
+
 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
         struct in_addr address;
         int r;
 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
         struct in_addr address;
         int r;
@@ -903,7 +977,7 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
         switch(event) {
                 case IPV4LL_EVENT_STOP:
                 case IPV4LL_EVENT_CONFLICT:
         switch(event) {
                 case IPV4LL_EVENT_STOP:
                 case IPV4LL_EVENT_CONFLICT:
-                        r = ipv4ll_address_lost(ll, link);
+                        r = ipv4ll_address_lost(link);
                         if (r < 0) {
                                 link_enter_failed(link);
                                 return;
                         if (r < 0) {
                                 link_enter_failed(link);
                                 return;
index 8144031a99d286987181a190ca5dcf21993528c8..36902e3c51f810eef252be844b2014eb80e2f703 100644 (file)
@@ -36,6 +36,8 @@
 #include "set.h"
 #include "condition-util.h"
 
 #include "set.h"
 #include "condition-util.h"
 
+#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
+
 typedef struct NetDev NetDev;
 typedef struct Network Network;
 typedef struct Link Link;
 typedef struct NetDev NetDev;
 typedef struct Network Network;
 typedef struct Link Link;
@@ -150,6 +152,7 @@ struct Address {
         char *label;
 
         struct in_addr broadcast;
         char *label;
 
         struct in_addr broadcast;
+        struct ifa_cacheinfo cinfo;
 
         union {
                 struct in_addr in;
 
         union {
                 struct in_addr in;
@@ -335,6 +338,7 @@ int address_new_static(Network *network, unsigned section, Address **ret);
 int address_new_dynamic(Address **ret);
 void address_free(Address *address);
 int address_configure(Address *address, Link *link, sd_rtnl_message_handler_t callback);
 int address_new_dynamic(Address **ret);
 void address_free(Address *address);
 int address_configure(Address *address, Link *link, sd_rtnl_message_handler_t callback);
+int address_update(Address *address, Link *link, sd_rtnl_message_handler_t callback);
 int address_drop(Address *address, Link *link, sd_rtnl_message_handler_t callback);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
 int address_drop(Address *address, Link *link, sd_rtnl_message_handler_t callback);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
index 6273c8917aee69f2d70c52a575c86caf0b914420..28405a1d3b72c29898f697bbc0d76326cfe8c5a0 100644 (file)
@@ -22,6 +22,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <stdbool.h>
 #include <netinet/in.h>
 #include <net/ethernet.h>
 
 #include <netinet/in.h>
 #include <net/ethernet.h>
 
@@ -42,10 +43,11 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
 int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata);
 int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
 int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index);
 int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata);
 int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
 int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index);
-int sd_ipv4ll_set_address_seed (sd_ipv4ll *ll, uint8_t seed[8]);
-int sd_ipv4ll_start (sd_ipv4ll *ll);
-int sd_ipv4ll_stop (sd_ipv4ll *ll);
-void sd_ipv4ll_free (sd_ipv4ll *ll);
-int sd_ipv4ll_new (sd_ipv4ll **ret);
+int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint8_t seed[8]);
+bool sd_ipv4ll_is_running(sd_ipv4ll *ll);
+int sd_ipv4ll_start(sd_ipv4ll *ll);
+int sd_ipv4ll_stop(sd_ipv4ll *ll);
+void sd_ipv4ll_free(sd_ipv4ll *ll);
+int sd_ipv4ll_new(sd_ipv4ll **ret);
 
 #endif
 
 #endif
index 80e88e3838ba9bc1a9f67b8c6aec5a82934c6c32..f7f7074ab9bf759e22d2e1bde71388a63a3411d4 100644 (file)
@@ -68,6 +68,7 @@ int sd_rtnl_detach_event(sd_rtnl *nl);
 
 /* messages */
 int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t msg_type, int index);
 
 /* messages */
 int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t msg_type, int index);
+int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret, int index, unsigned char family);
 int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t msg_type, int index,
                              unsigned char family);
 int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type,
 int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t msg_type, int index,
                              unsigned char family);
 int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type,
@@ -99,6 +100,7 @@ int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t
 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data);
 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data);
 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data);
 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data);
 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data);
 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data);
+int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info);
 
 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type);
 int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key);
 
 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type);
 int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key);
@@ -109,6 +111,7 @@ int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *da
 int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data);
 int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data);
 int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data);
 int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data);
 int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data);
 int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data);
+int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info);
 int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data);
 int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data);
 int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type);
 int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data);
 int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data);
 int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type);