summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorUmut Tezduyar Lindskog <umut.tezduyar@axis.com>2014-04-02 21:31:12 +0200
committerTom Gundersen <teg@jklm.no>2014-04-03 16:00:25 +0200
commitaba496a58acf9d9c61314de71353550e579f85ee (patch)
treee554123004bba327c3114539142047d4c124f40a /src
parent3e790eae01ce74f94a5233adeab12c64508916e0 (diff)
networkd: smooth transition from ipv4ll to dhcp address
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.
Diffstat (limited to 'src')
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c6
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-message.c50
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-types.c2
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-types.h1
-rw-r--r--src/libsystemd/sd-rtnl/test-rtnl.c2
-rw-r--r--src/network/networkd-address.c96
-rw-r--r--src/network/networkd-link.c94
-rw-r--r--src/network/networkd.h4
-rw-r--r--src/systemd/sd-ipv4ll.h12
-rw-r--r--src/systemd/sd-rtnl.h3
10 files changed, 250 insertions, 20 deletions
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index a201139b08..81fe85b68b 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -481,6 +481,12 @@ error:
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) {
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index 4ace94ce18..e5854de4c6 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -286,6 +286,19 @@ int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
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);
@@ -559,6 +572,24 @@ int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, c
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;
@@ -741,6 +772,25 @@ int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, str
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;
diff --git a/src/libsystemd/sd-rtnl/rtnl-types.c b/src/libsystemd/sd-rtnl/rtnl-types.c
index 29ee5bc1c8..4e70c95127 100644
--- a/src/libsystemd/sd-rtnl/rtnl-types.c
+++ b/src/libsystemd/sd-rtnl/rtnl-types.c
@@ -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_CACHEINFO] = { .type = NLA_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
/*
[IFA_ANYCAST],
- [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
[IFA_MULTICAST],
*/
#ifdef IFA_FLAGS
diff --git a/src/libsystemd/sd-rtnl/rtnl-types.h b/src/libsystemd/sd-rtnl/rtnl-types.h
index 2425dc92a3..7ce9597c84 100644
--- a/src/libsystemd/sd-rtnl/rtnl-types.h
+++ b/src/libsystemd/sd-rtnl/rtnl-types.h
@@ -31,6 +31,7 @@ enum {
NLA_STRING,
NLA_IN_ADDR,
NLA_ETHER_ADDR,
+ NLA_CACHE_INFO,
NLA_NESTED,
NLA_UNION,
};
diff --git a/src/libsystemd/sd-rtnl/test-rtnl.c b/src/libsystemd/sd-rtnl/test-rtnl.c
index 44369628f4..529231a70a 100644
--- a/src/libsystemd/sd-rtnl/test-rtnl.c
+++ b/src/libsystemd/sd-rtnl/test-rtnl.c
@@ -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;
+ struct ifa_cacheinfo cache;
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_cache_info(r, IFA_CACHEINFO, &cache) == 0);
assert_se(sd_rtnl_flush(rtnl) >= 0);
assert_se((m = sd_rtnl_message_unref(m)) == NULL);
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index dd4c822c67..87688a5ae6 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -28,6 +28,15 @@
#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;
@@ -46,8 +55,7 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
if (!address)
return -ENOMEM;
- address->family = AF_UNSPEC;
- address->scope = RT_SCOPE_UNIVERSE;
+ address_init(address);
address->network = network;
@@ -71,8 +79,7 @@ int address_new_dynamic(Address **ret) {
if (!address)
return -ENOMEM;
- address->family = AF_UNSPEC;
- address->scope = RT_SCOPE_UNIVERSE;
+ address_init(address);
*ret = address;
address = NULL;
@@ -140,6 +147,87 @@ int address_drop(Address *address, Link *link,
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;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 4e0fe0a271..63d253d941 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -30,6 +30,9 @@
#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;
@@ -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;
- struct in_addr a;
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->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");
@@ -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;
- struct in_addr a;
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->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");
@@ -456,6 +457,28 @@ static int link_enter_set_addresses(Link *link) {
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;
@@ -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;
- int r;
+ int r = 0;
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) {
- 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;
@@ -807,7 +833,10 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
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;
@@ -825,11 +854,44 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
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;
- assert(ll);
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;
}
+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;
@@ -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:
- r = ipv4ll_address_lost(ll, link);
+ r = ipv4ll_address_lost(link);
if (r < 0) {
link_enter_failed(link);
return;
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 8144031a99..36902e3c51 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -36,6 +36,8 @@
#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;
@@ -150,6 +152,7 @@ struct Address {
char *label;
struct in_addr broadcast;
+ struct ifa_cacheinfo cinfo;
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_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);
diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h
index 6273c8917a..28405a1d3b 100644
--- a/src/systemd/sd-ipv4ll.h
+++ b/src/systemd/sd-ipv4ll.h
@@ -22,6 +22,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <stdbool.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_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
diff --git a/src/systemd/sd-rtnl.h b/src/systemd/sd-rtnl.h
index 80e88e3838..f7f7074ab9 100644
--- a/src/systemd/sd-rtnl.h
+++ b/src/systemd/sd-rtnl.h
@@ -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);
+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,
@@ -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_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);
@@ -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_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);