Merge pull request #5529 from ssahani/label

networkd / sd-netlink: add support for address label
This commit is contained in:
Lennart Poettering 2017-04-29 13:42:09 +02:00 committed by GitHub
commit ccefd046c6
13 changed files with 481 additions and 15 deletions

View File

@ -5812,6 +5812,8 @@ libnetworkd_core_la_SOURCES = \
src/network/networkd-network-bus.c \
src/network/networkd-address.h \
src/network/networkd-address.c \
src/network/networkd-address-label.h \
src/network/networkd-address-label.c \
src/network/networkd-route.h \
src/network/networkd-route.c \
src/network/networkd-fdb.h \

View File

@ -796,6 +796,33 @@
</variablelist>
</refsect1>
<refsect1>
<title>[IPv6AddressLabel] Section Options</title>
<para>An <literal>[IPv6AddressLabel]</literal> section accepts the
following keys. Specify several <literal>[IPv6AddressLabel]</literal>
sections to configure several addresse labels. IPv6 address labels are
used for address selection. See <ulink url="https://tools.ietf.org/html/rfc3484">RFC 3484</ulink>.
Precedence is managed by userspace, and only the label itself is stored in the kernel</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>Label=</varname></term>
<listitem>
<para> The label for the prefix (an unsigned integer) ranges 0 to 4294967294.
0xffffffff is reserved. This key is mandatory.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Prefix=</varname></term>
<listitem>
<para>IPv6 prefix is an address with a prefix length, separated by a slash <literal>/</literal> character.
This key is mandatory. </para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[Route] Section Options</title>
<para>The <literal>[Route]</literal> section accepts the

View File

@ -26,6 +26,7 @@
#include <linux/veth.h>
#include <linux/if_bridge.h>
#include <linux/if_addr.h>
#include <linux/if_addrlabel.h>
#include <linux/if.h>
#include <linux/ip.h>
#include <linux/if_link.h>
@ -586,22 +587,35 @@ static const NLTypeSystem rtnl_neigh_type_system = {
.types = rtnl_neigh_types,
};
static const NLType rtnl_addrlabel_types[] = {
[IFAL_ADDRESS] = { .type = NETLINK_TYPE_IN_ADDR, .size = sizeof(struct in6_addr) },
[IFAL_LABEL] = { .type = NETLINK_TYPE_U32 },
};
static const NLTypeSystem rtnl_addrlabel_type_system = {
.count = ELEMENTSOF(rtnl_addrlabel_types),
.types = rtnl_addrlabel_types,
};
static const NLType rtnl_types[] = {
[NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 },
[NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
[RTM_NEWLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_DELLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_GETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_SETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_NEWADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
[RTM_DELADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
[RTM_GETADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
[RTM_NEWROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
[RTM_DELROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
[RTM_GETROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
[RTM_NEWNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
[RTM_DELNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
[RTM_GETNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
[NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 },
[NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
[RTM_NEWLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_DELLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_GETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_SETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_NEWADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
[RTM_DELADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
[RTM_GETADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
[RTM_NEWROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
[RTM_DELROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
[RTM_GETROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
[RTM_NEWNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
[RTM_DELNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
[RTM_GETNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
[RTM_NEWADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
[RTM_DELADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
[RTM_GETADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
};
const NLTypeSystem type_system_root = {

View File

@ -32,6 +32,10 @@ bool rtnl_message_type_is_addr(uint16_t type);
bool rtnl_message_type_is_route(uint16_t type);
bool rtnl_message_type_is_neigh(uint16_t type);
static inline bool rtnl_message_type_is_addrlabel(uint16_t type) {
return IN_SET(type, RTM_NEWADDRLABEL, RTM_DELADDRLABEL, RTM_GETADDRLABEL);
}
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name);
int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu);

View File

@ -18,6 +18,7 @@
***/
#include <netinet/in.h>
#include <linux/if_addrlabel.h>
#include <stdbool.h>
#include <unistd.h>
@ -700,3 +701,42 @@ int sd_rtnl_message_get_family(sd_netlink_message *m, int *family) {
return -EOPNOTSUPP;
}
int sd_rtnl_message_new_addrlabel(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifindex, int ifal_family) {
struct ifaddrlblmsg *addrlabel;
int r;
assert_return(rtnl_message_type_is_addrlabel(nlmsg_type), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
if (r < 0)
return r;
if (nlmsg_type == RTM_NEWADDRLABEL)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
addrlabel = NLMSG_DATA((*ret)->hdr);
addrlabel->ifal_family = ifal_family;
addrlabel->ifal_index = ifindex;
return 0;
}
int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
struct ifaddrlblmsg *addrlabel;
assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_addrlabel(m->hdr->nlmsg_type), -EINVAL);
addrlabel = NLMSG_DATA(m->hdr);
if (prefixlen > 128)
return -ERANGE;
addrlabel->ifal_prefixlen = prefixlen;
return 0;
}

View File

@ -27,6 +27,8 @@ sources = files('''
netdev/vxlan.h
netdev/geneve.c
netdev/geneve.h
networkd-address-label.c
networkd-address-label.h
networkd-address-pool.c
networkd-address-pool.h
networkd-address.c

View File

@ -0,0 +1,257 @@
/***
This file is part of systemd.
Copyright 2017 Susant Sahani
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <net/if.h>
#include <linux/if_addrlabel.h>
#include "alloc-util.h"
#include "conf-parser.h"
#include "networkd-address-label.h"
#include "netlink-util.h"
#include "networkd-manager.h"
#include "parse-util.h"
#include "socket-util.h"
int address_label_new(AddressLabel **ret) {
_cleanup_address_label_free_ AddressLabel *addrlabel = NULL;
addrlabel = new0(AddressLabel, 1);
if (!addrlabel)
return -ENOMEM;
*ret = addrlabel;
addrlabel = NULL;
return 0;
}
void address_label_free(AddressLabel *label) {
if (!label)
return;
if (label->network) {
LIST_REMOVE(labels, label->network->address_labels, label);
assert(label->network->n_address_labels > 0);
label->network->n_address_labels--;
if (label->section) {
hashmap_remove(label->network->address_labels_by_section, label->section);
network_config_section_free(label->section);
}
}
free(label);
}
static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) {
_cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
_cleanup_address_label_free_ AddressLabel *label = NULL;
int r;
assert(network);
assert(ret);
assert(!!filename == (section_line > 0));
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
label = hashmap_get(network->address_labels_by_section, n);
if (label) {
*ret = label;
label = NULL;
return 0;
}
r = address_label_new(&label);
if (r < 0)
return r;
label->section = n;
n = NULL;
r = hashmap_put(network->address_labels_by_section, label->section, label);
if (r < 0)
return r;
label->network = network;
LIST_APPEND(labels, network->address_labels, label);
network->n_address_labels++;
*ret = label;
label = NULL;
return 0;
}
int address_label_configure(
AddressLabel *label,
Link *link,
sd_netlink_message_handler_t callback,
bool update) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(label);
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
r = sd_rtnl_message_new_addrlabel(link->manager->rtnl, &req, RTM_NEWADDRLABEL,
link->ifindex, label->family);
if (r < 0)
return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
r = sd_rtnl_message_addrlabel_set_prefixlen(req, label->prefixlen);
if (r < 0)
return log_error_errno(r, "Could not set prefixlen: %m");
r = sd_netlink_message_append_u32(req, IFAL_LABEL, label->label);
if (r < 0)
return log_error_errno(r, "Could not append IFAL_LABEL attribute: %m");
r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &label->in_addr.in6);
if (r < 0)
return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
link_ref(link);
return 0;
}
int config_parse_address_label_prefix(const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_address_label_free_ AddressLabel *n = NULL;
Network *network = userdata;
const char *prefix, *e;
union in_addr_union buffer;
int r, f;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = address_label_new_static(network, filename, section_line, &n);
if (r < 0)
return r;
/* AddressLabel=prefix/prefixlen */
/* prefixlen */
e = strchr(rvalue, '/');
if (e) {
unsigned i;
r = safe_atou(e + 1, &i);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
return 0;
}
if (i > 128) {
log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is out of range, ignoring assignment: %s", e + 1);
return 0;
}
n->prefixlen = (unsigned char) i;
prefix = strndupa(rvalue, e - rvalue);
} else
prefix = rvalue;
r = in_addr_from_string_auto(prefix, &f, &buffer);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Address label is invalid, ignoring assignment: %s", prefix);
return 0;
}
if (f != AF_INET6) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Address label family is not IPv6, ignoring assignment: %s", prefix);
return 0;
}
n->family = f;
n->in_addr = buffer;
n = NULL;
return 0;
}
int config_parse_address_label(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_address_label_free_ AddressLabel *n = NULL;
Network *network = userdata;
uint32_t k;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = address_label_new_static(network, filename, section_line, &n);
if (r < 0)
return r;
r = safe_atou32(rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address label, ignoring: %s", rvalue);
return 0;
}
if (k == 0xffffffffUL) {
log_syntax(unit, LOG_ERR, filename, line, r, "Adress label is invalid, ignoring: %s", rvalue);
return 0;
}
n->label = k;
n = NULL;
return 0;
}

View File

@ -0,0 +1,59 @@
#pragma once
/***
This file is part of systemd.
Copyright 2017 Susant Sahani
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
#include <stdbool.h>
#include "in-addr-util.h"
typedef struct AddressLabel AddressLabel;
#include "networkd-link.h"
#include "networkd-network.h"
typedef struct Network Network;
typedef struct Link Link;
typedef struct NetworkConfigSection NetworkConfigSection;
struct AddressLabel {
Network *network;
Link *link;
NetworkConfigSection *section;
int family;
unsigned char prefixlen;
uint32_t label;
union in_addr_union in_addr;
LIST_FIELDS(AddressLabel, labels);
};
int address_label_new(AddressLabel **ret);
void address_label_free(AddressLabel *label);
DEFINE_TRIVIAL_CLEANUP_FUNC(AddressLabel*, address_label_free);
#define _cleanup_address_label_free_ _cleanup_(address_label_freep)
int address_label_configure(AddressLabel *address, Link *link, sd_netlink_message_handler_t callback, bool update);
int config_parse_address_label(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_address_label_prefix(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);

View File

@ -853,6 +853,35 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
return 1;
}
static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
int r;
assert(rtnl);
assert(m);
assert(link);
assert(link->ifname);
assert(link->link_messages > 0);
link->link_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->link_messages == 0) {
log_link_debug(link, "Addresses label set");
link_enter_set_routes(link);
}
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;
@ -965,6 +994,7 @@ static int link_set_bridge_fdb(Link *link) {
}
static int link_enter_set_addresses(Link *link) {
AddressLabel *label;
Address *ad;
int r;
@ -989,6 +1019,17 @@ static int link_enter_set_addresses(Link *link) {
link->link_messages++;
}
LIST_FOREACH(labels, label, link->network->address_labels) {
r = address_label_configure(label, link, address_label_handler, false);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set address label: %m");
link_enter_failed(link);
return r;
}
link->link_messages++;
}
/* now that we can figure out a default address for the dhcp server,
start it */
if (link_dhcp4_server_enabled(link)) {

View File

@ -79,6 +79,8 @@ Address.DuplicateAddressDetection, config_parse_address_flags,
Address.ManageTemporaryAddress, config_parse_address_flags, 0, 0
Address.PrefixRoute, config_parse_address_flags, 0, 0
Address.AutoJoin, config_parse_address_flags, 0, 0
IPv6AddressLabel.Prefix, config_parse_address_label_prefix, 0, 0
IPv6AddressLabel.Label, config_parse_address_label, 0, 0
Route.Gateway, config_parse_gateway, 0, 0
Route.Destination, config_parse_destination, 0, 0
Route.Source, config_parse_destination, 0, 0

View File

@ -114,6 +114,7 @@ static int network_load_one(Manager *manager, const char *filename) {
LIST_HEAD_INIT(network->static_routes);
LIST_HEAD_INIT(network->static_fdb_entries);
LIST_HEAD_INIT(network->ipv6_proxy_ndp_addresses);
LIST_HEAD_INIT(network->address_labels);
network->stacked_netdevs = hashmap_new(&string_hash_ops);
if (!network->stacked_netdevs)
@ -131,6 +132,10 @@ static int network_load_one(Manager *manager, const char *filename) {
if (!network->fdb_entries_by_section)
return log_oom();
network->address_labels_by_section = hashmap_new(&network_config_hash_ops);
if (!network->address_labels_by_section)
return log_oom();
network->filename = strdup(filename);
if (!network->filename)
return log_oom();
@ -192,6 +197,7 @@ static int network_load_one(Manager *manager, const char *filename) {
"Link\0"
"Network\0"
"Address\0"
"IPv6AddressLabel\0"
"Route\0"
"DHCP\0"
"DHCPv4\0" /* compat */
@ -271,6 +277,7 @@ void network_free(Network *network) {
Address *address;
FdbEntry *fdb_entry;
IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
AddressLabel *label;
Iterator i;
if (!network)
@ -318,9 +325,13 @@ void network_free(Network *network) {
while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
while ((label = network->address_labels))
address_label_free(label);
hashmap_free(network->addresses_by_section);
hashmap_free(network->routes_by_section);
hashmap_free(network->fdb_entries_by_section);
hashmap_free(network->address_labels_by_section);
if (network->manager) {
if (network->manager->networks)

View File

@ -28,6 +28,7 @@
#include "resolve-util.h"
#include "networkd-address.h"
#include "networkd-address-label.h"
#include "networkd-brvlan.h"
#include "networkd-fdb.h"
#include "networkd-lldp-tx.h"
@ -202,15 +203,18 @@ struct Network {
LIST_HEAD(Route, static_routes);
LIST_HEAD(FdbEntry, static_fdb_entries);
LIST_HEAD(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
LIST_HEAD(AddressLabel, address_labels);
unsigned n_static_addresses;
unsigned n_static_routes;
unsigned n_static_fdb_entries;
unsigned n_ipv6_proxy_ndp_addresses;
unsigned n_address_labels;
Hashmap *addresses_by_section;
Hashmap *routes_by_section;
Hashmap *fdb_entries_by_section;
Hashmap *address_labels_by_section;
struct in_addr_data *dns;
unsigned n_dns;

View File

@ -155,6 +155,9 @@ int sd_rtnl_message_neigh_get_ifindex(sd_netlink_message *m, int *family);
int sd_rtnl_message_neigh_get_state(sd_netlink_message *m, uint16_t *state);
int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags);
int sd_rtnl_message_new_addrlabel(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifindex, int ifal_family);
int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink, sd_netlink_unref);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink_message, sd_netlink_message_unref);