summaryrefslogtreecommitdiff
path: root/src/libsystemd/sd-netlink
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd/sd-netlink')
-rw-r--r--src/libsystemd/sd-netlink/local-addresses.c19
-rw-r--r--src/libsystemd/sd-netlink/local-addresses.h3
-rw-r--r--src/libsystemd/sd-netlink/netlink-internal.h19
-rw-r--r--src/libsystemd/sd-netlink/netlink-message.c108
-rw-r--r--src/libsystemd/sd-netlink/netlink-socket.c180
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c282
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.h8
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.c9
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.h10
-rw-r--r--src/libsystemd/sd-netlink/rtnl-message.c134
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c117
-rw-r--r--src/libsystemd/sd-netlink/test-local-addresses.c8
-rw-r--r--src/libsystemd/sd-netlink/test-netlink.c68
13 files changed, 679 insertions, 286 deletions
diff --git a/src/libsystemd/sd-netlink/local-addresses.c b/src/libsystemd/sd-netlink/local-addresses.c
index e2f637f7f9..ed9ee041ab 100644
--- a/src/libsystemd/sd-netlink/local-addresses.c
+++ b/src/libsystemd/sd-netlink/local-addresses.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -21,9 +19,11 @@
***/
#include "sd-netlink.h"
-#include "netlink-util.h"
-#include "macro.h"
+
+#include "alloc-util.h"
#include "local-addresses.h"
+#include "macro.h"
+#include "netlink-util.h"
static int address_compare(const void *_a, const void *_b) {
const struct local_address *a = _a, *b = _b;
@@ -54,8 +54,8 @@ static int address_compare(const void *_a, const void *_b) {
}
int local_addresses(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
- _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
- _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_free_ struct local_address *list = NULL;
size_t n_list = 0, n_allocated = 0;
sd_netlink_message *m;
@@ -155,8 +155,7 @@ int local_addresses(sd_netlink *context, int ifindex, int af, struct local_addre
n_list++;
};
- if (n_list > 0)
- qsort(list, n_list, sizeof(struct local_address), address_compare);
+ qsort_safe(list, n_list, sizeof(struct local_address), address_compare);
*ret = list;
list = NULL;
@@ -165,8 +164,8 @@ int local_addresses(sd_netlink *context, int ifindex, int af, struct local_addre
}
int local_gateways(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
- _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
- _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_free_ struct local_address *list = NULL;
sd_netlink_message *m = NULL;
size_t n_list = 0, n_allocated = 0;
diff --git a/src/libsystemd/sd-netlink/local-addresses.h b/src/libsystemd/sd-netlink/local-addresses.h
index 5d0f11a2c1..18d71e797e 100644
--- a/src/libsystemd/sd-netlink/local-addresses.h
+++ b/src/libsystemd/sd-netlink/local-addresses.h
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
#pragma once
/***
@@ -23,6 +21,7 @@
#include "sd-netlink.h"
+
#include "in-addr-util.h"
struct local_address {
diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h
index 4026e2c341..dcfb080ad3 100644
--- a/src/libsystemd/sd-netlink/netlink-internal.h
+++ b/src/libsystemd/sd-netlink/netlink-internal.h
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
#pragma once
/***
@@ -23,13 +21,12 @@
#include <linux/netlink.h>
-#include "refcnt.h"
-#include "prioq.h"
-#include "list.h"
-
#include "sd-netlink.h"
+#include "list.h"
#include "netlink-types.h"
+#include "prioq.h"
+#include "refcnt.h"
#define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
@@ -64,6 +61,9 @@ struct sd_netlink {
struct sockaddr_nl nl;
} sockaddr;
+ Hashmap *broadcast_group_refs;
+ bool broadcast_group_dont_leave:1; /* until we can rely on 4.2 */
+
sd_netlink_message **rqueue;
unsigned rqueue_size;
size_t rqueue_allocated;
@@ -124,7 +124,8 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret);
int socket_open(int family);
int socket_bind(sd_netlink *nl);
-int socket_join_broadcast_group(sd_netlink *nl, unsigned group);
+int socket_broadcast_group_ref(sd_netlink *nl, unsigned group);
+int socket_broadcast_group_unref(sd_netlink *nl, unsigned group);
int socket_write_message(sd_netlink *nl, sd_netlink_message *m);
int socket_read_message(sd_netlink *nl);
@@ -132,5 +133,5 @@ int rtnl_rqueue_make_room(sd_netlink *rtnl);
int rtnl_rqueue_partial_make_room(sd_netlink *rtnl);
/* Make sure callbacks don't destroy the rtnl connection */
-#define RTNL_DONT_DESTROY(rtnl) \
- _cleanup_netlink_unref_ _unused_ sd_netlink *_dont_destroy_##rtnl = sd_netlink_ref(rtnl)
+#define NETLINK_DONT_DESTROY(rtnl) \
+ _cleanup_(sd_netlink_unrefp) _unused_ sd_netlink *_dont_destroy_##rtnl = sd_netlink_ref(rtnl)
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index b0ed2f2882..df3b3c922e 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -23,19 +21,20 @@
#include <stdbool.h>
#include <unistd.h>
-#include "util.h"
-#include "socket-util.h"
+#include "sd-netlink.h"
+
+#include "alloc-util.h"
#include "formats-util.h"
-#include "refcnt.h"
#include "missing.h"
-
-#include "sd-netlink.h"
-#include "netlink-util.h"
#include "netlink-internal.h"
#include "netlink-types.h"
+#include "netlink-util.h"
+#include "refcnt.h"
+#include "socket-util.h"
+#include "util.h"
#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
-#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
+#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
@@ -64,7 +63,7 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
}
int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
- _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLType *nl_type;
size_t size;
int r;
@@ -108,10 +107,7 @@ int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
m->hdr->nlmsg_type == RTM_GETNEIGH,
-EINVAL);
- if (dump)
- m->hdr->nlmsg_flags |= NLM_F_DUMP;
- else
- m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
+ SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
return 0;
}
@@ -124,7 +120,9 @@ sd_netlink_message *sd_netlink_message_ref(sd_netlink_message *m) {
}
sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
- if (m && REFCNT_DEC(m->n_ref) == 0) {
+ sd_netlink_message *t;
+
+ while (m && REFCNT_DEC(m->n_ref) == 0) {
unsigned i;
free(m->hdr);
@@ -132,9 +130,9 @@ sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
for (i = 0; i <= m->n_containers; i++)
free(m->containers[i].attributes);
- sd_netlink_message_unref(m->next);
-
- free(m);
+ t = m;
+ m = m->next;
+ free(t);
}
return NULL;
@@ -149,6 +147,15 @@ int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
return 0;
}
+int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
+ assert_return(m, -EINVAL);
+ assert_return(flags, -EINVAL);
+
+ m->hdr->nlmsg_flags = flags;
+
+ return 0;
+}
+
int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
assert_return(m, -EINVAL);
@@ -202,11 +209,11 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da
* and gives us too little data (so don't do that)
*/
padding = mempcpy(RTA_DATA(rta), data, data_length);
- else {
+
+ else
/* if no data was passed, make sure we still initialize the padding
note that we can have data_length > 0 (used by some containers) */
padding = RTA_DATA(rta);
- }
/* make sure also the padding at the end of the message is initialized */
padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
@@ -262,6 +269,24 @@ int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type,
return 0;
}
+int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type) {
+ size_t size;
+ int r;
+
+ assert_return(m, -EINVAL);
+ assert_return(!m->sealed, -EPERM);
+
+ r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_FLAG);
+ if (r < 0)
+ return r;
+
+ r = add_rtattr(m, type, NULL, 0);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
int r;
@@ -314,6 +339,19 @@ int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, ui
return 0;
}
+int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len) {
+ int r;
+
+ assert_return(m, -EINVAL);
+ assert_return(!m->sealed, -EPERM);
+
+ r = add_rtattr(m, type, data, len);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
int r;
@@ -428,7 +466,7 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type
if (r < 0)
return r;
- m->containers[m->n_containers ++].offset = r;
+ m->containers[m->n_containers++].offset = r;
return 0;
}
@@ -459,7 +497,7 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
if (r < 0)
return r;
- m->containers[m->n_containers ++].offset = r;
+ m->containers[m->n_containers++].offset = r;
return 0;
}
@@ -471,7 +509,7 @@ int sd_netlink_message_close_container(sd_netlink_message *m) {
assert_return(m->n_containers > 0, -EINVAL);
m->containers[m->n_containers].type_system = NULL;
- m->n_containers --;
+ m->n_containers--;
return 0;
}
@@ -483,13 +521,13 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t
assert_return(m, -EINVAL);
assert_return(m->sealed, -EPERM);
assert_return(data, -EINVAL);
- assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
+ assert(m->n_containers < RTNL_CONTAINER_DEPTH);
assert(m->containers[m->n_containers].attributes);
assert(type < m->containers[m->n_containers].n_attributes);
attribute = &m->containers[m->n_containers].attributes[type];
- if(!attribute->offset)
+ if (!attribute->offset)
return -ENODATA;
rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
@@ -696,7 +734,7 @@ static int netlink_container_parse(sd_netlink_message *m,
_cleanup_free_ struct netlink_attribute *attributes = NULL;
attributes = new0(struct netlink_attribute, count);
- if(!attributes)
+ if (!attributes)
return -ENOMEM;
for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
@@ -803,7 +841,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ
else
size = (size_t)r;
- m->n_containers ++;
+ m->n_containers++;
r = netlink_container_parse(m,
&m->containers[m->n_containers],
@@ -811,7 +849,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ
container,
size);
if (r < 0) {
- m->n_containers --;
+ m->n_containers--;
return r;
}
@@ -825,11 +863,10 @@ int sd_netlink_message_exit_container(sd_netlink_message *m) {
assert_return(m->sealed, -EINVAL);
assert_return(m->n_containers > 0, -EINVAL);
- free(m->containers[m->n_containers].attributes);
- m->containers[m->n_containers].attributes = NULL;
+ m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes);
m->containers[m->n_containers].type_system = NULL;
- m->n_containers --;
+ m->n_containers--;
return 0;
}
@@ -875,17 +912,14 @@ int sd_netlink_message_rewind(sd_netlink_message *m) {
if (!m->sealed)
rtnl_message_seal(m);
- for (i = 1; i <= m->n_containers; i++) {
- free(m->containers[i].attributes);
- m->containers[i].attributes = NULL;
- }
+ for (i = 1; i <= m->n_containers; i++)
+ m->containers[i].attributes = mfree(m->containers[i].attributes);
m->n_containers = 0;
- if (m->containers[0].attributes) {
+ if (m->containers[0].attributes)
/* top-level attributes have already been parsed */
return 0;
- }
assert(m->hdr);
diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c
index 84ff7c38c9..c165fa3359 100644
--- a/src/libsystemd/sd-netlink/netlink-socket.c
+++ b/src/libsystemd/sd-netlink/netlink-socket.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -23,16 +21,17 @@
#include <stdbool.h>
#include <unistd.h>
-#include "util.h"
-#include "socket-util.h"
+#include "sd-netlink.h"
+
+#include "alloc-util.h"
#include "formats-util.h"
-#include "refcnt.h"
#include "missing.h"
-
-#include "sd-netlink.h"
-#include "netlink-util.h"
#include "netlink-internal.h"
#include "netlink-types.h"
+#include "netlink-util.h"
+#include "refcnt.h"
+#include "socket-util.h"
+#include "util.h"
int socket_open(int family) {
int fd;
@@ -44,6 +43,65 @@ int socket_open(int family) {
return fd;
}
+static int broadcast_groups_get(sd_netlink *nl) {
+ _cleanup_free_ uint32_t *groups = NULL;
+ socklen_t len = 0, old_len;
+ unsigned i, j;
+ int r;
+
+ assert(nl);
+ assert(nl->fd >= 0);
+
+ r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len);
+ if (r < 0) {
+ if (errno == ENOPROTOOPT) {
+ nl->broadcast_group_dont_leave = true;
+ return 0;
+ } else
+ return -errno;
+ }
+
+ if (len == 0)
+ return 0;
+
+ groups = new0(uint32_t, len);
+ if (!groups)
+ return -ENOMEM;
+
+ old_len = len;
+
+ r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len);
+ if (r < 0)
+ return -errno;
+
+ if (old_len != len)
+ return -EIO;
+
+ r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
+ if (r < 0)
+ return r;
+
+ for (i = 0; i < len; i++) {
+ for (j = 0; j < sizeof(uint32_t) * 8; j++) {
+ uint32_t offset;
+ unsigned group;
+
+ offset = 1U << j;
+
+ if (!(groups[i] & offset))
+ continue;
+
+ group = i * sizeof(uint32_t) * 8 + j + 1;
+
+ r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1));
+ if (r < 0)
+ return r;
+ }
+ }
+
+ return 0;
+}
+
int socket_bind(sd_netlink *nl) {
socklen_t addrlen;
int r, one = 1;
@@ -63,11 +121,32 @@ int socket_bind(sd_netlink *nl) {
if (r < 0)
return -errno;
+ r = broadcast_groups_get(nl);
+ if (r < 0)
+ return r;
+
return 0;
}
+static unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) {
+ assert(nl);
+
+ return PTR_TO_UINT(hashmap_get(nl->broadcast_group_refs, UINT_TO_PTR(group)));
+}
-int socket_join_broadcast_group(sd_netlink *nl, unsigned group) {
+static int broadcast_group_set_ref(sd_netlink *nl, unsigned group, unsigned n_ref) {
+ int r;
+
+ assert(nl);
+
+ r = hashmap_replace(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(n_ref));
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int broadcast_group_join(sd_netlink *nl, unsigned group) {
int r;
assert(nl);
@@ -81,6 +160,79 @@ int socket_join_broadcast_group(sd_netlink *nl, unsigned group) {
return 0;
}
+int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) {
+ unsigned n_ref;
+ int r;
+
+ assert(nl);
+
+ n_ref = broadcast_group_get_ref(nl, group);
+
+ n_ref++;
+
+ r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
+ if (r < 0)
+ return r;
+
+ r = broadcast_group_set_ref(nl, group, n_ref);
+ if (r < 0)
+ return r;
+
+ if (n_ref > 1)
+ /* not yet in the group */
+ return 0;
+
+ r = broadcast_group_join(nl, group);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int broadcast_group_leave(sd_netlink *nl, unsigned group) {
+ int r;
+
+ assert(nl);
+ assert(nl->fd >= 0);
+ assert(group > 0);
+
+ if (nl->broadcast_group_dont_leave)
+ return 0;
+
+ r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group));
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) {
+ unsigned n_ref;
+ int r;
+
+ assert(nl);
+
+ n_ref = broadcast_group_get_ref(nl, group);
+
+ assert(n_ref > 0);
+
+ n_ref--;
+
+ r = broadcast_group_set_ref(nl, group, n_ref);
+ if (r < 0)
+ return r;
+
+ if (n_ref > 0)
+ /* still refs left */
+ return 0;
+
+ r = broadcast_group_leave(nl, group);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
/* returns the number of bytes sent, or a negative error code */
int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
union {
@@ -169,7 +321,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool
* On failure, a negative error code is returned.
*/
int socket_read_message(sd_netlink *rtnl) {
- _cleanup_netlink_message_unref_ sd_netlink_message *first = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *first = NULL;
struct iovec iov = {};
uint32_t group = 0;
bool multi_part = false, done = false;
@@ -222,7 +374,7 @@ int socket_read_message(sd_netlink *rtnl) {
}
for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
- _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLType *nl_type;
if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
@@ -292,14 +444,14 @@ int socket_read_message(sd_netlink *rtnl) {
if (r < 0)
return r;
- rtnl->rqueue[rtnl->rqueue_size ++] = first;
+ rtnl->rqueue[rtnl->rqueue_size++] = first;
first = NULL;
if (multi_part && (i < rtnl->rqueue_partial_size)) {
/* remove the message form the partial read queue */
memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
sizeof(sd_netlink_message*) * (rtnl->rqueue_partial_size - i - 1));
- rtnl->rqueue_partial_size --;
+ rtnl->rqueue_partial_size--;
}
return 1;
@@ -313,7 +465,7 @@ int socket_read_message(sd_netlink *rtnl) {
if (r < 0)
return r;
- rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
+ rtnl->rqueue_partial[rtnl->rqueue_partial_size++] = first;
}
first = NULL;
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
index e880752eec..1c10dd55a7 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -23,21 +21,21 @@
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
+#include <linux/can/netlink.h>
#include <linux/in6.h>
#include <linux/veth.h>
#include <linux/if_bridge.h>
#include <linux/if_addr.h>
#include <linux/if.h>
-
#include <linux/ip.h>
#include <linux/if_link.h>
#include <linux/if_tunnel.h>
#include "macro.h"
-#include "util.h"
-
-#include "netlink-types.h"
#include "missing.h"
+#include "netlink-types.h"
+#include "string-table.h"
+#include "util.h"
/* Maximum ARP IP target defined in kernel */
#define BOND_MAX_ARP_TARGETS 16
@@ -84,29 +82,60 @@ static const NLTypeSystem empty_type_system = {
.types = empty_types,
};
-static const NLType rtnl_link_info_data_veth_types[VETH_INFO_MAX + 1] = {
+static const NLType rtnl_link_info_data_veth_types[] = {
[VETH_INFO_PEER] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
};
-static const NLType rtnl_link_info_data_ipvlan_types[IFLA_IPVLAN_MAX + 1] = {
+static const NLType rtnl_link_info_data_ipvlan_types[] = {
[IFLA_IPVLAN_MODE] = { .type = NETLINK_TYPE_U16 },
};
-static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
+static const NLType rtnl_link_info_data_macvlan_types[] = {
[IFLA_MACVLAN_MODE] = { .type = NETLINK_TYPE_U32 },
[IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
};
-static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
- [IFLA_BRIDGE_FLAGS] = { .type = NETLINK_TYPE_U16 },
- [IFLA_BRIDGE_MODE] = { .type = NETLINK_TYPE_U16 },
-/*
- [IFLA_BRIDGE_VLAN_INFO] = { .type = NETLINK_TYPE_BINARY,
- .len = sizeof(struct bridge_vlan_info), },
-*/
-};
-
-static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
+static const NLType rtnl_link_info_data_bridge_types[] = {
+ [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_VLAN_FILTERING] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_GROUP_FWD_MASK] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_ROOT_PORT] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_ROOT_PATH_COST] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_TOPOLOGY_CHANGE] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_TOPOLOGY_CHANGE_DETECTED] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_HELLO_TIMER] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_TCN_TIMER] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_TOPOLOGY_CHANGE_TIMER] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_GC_TIMER] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_GROUP_ADDR] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_FDB_FLUSH] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_MCAST_ROUTER] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_SNOOPING] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_QUERY_USE_IFADDR] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_QUERIER] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_HASH_ELASTICITY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_MCAST_HASH_MAX] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_MCAST_LAST_MEMBER_CNT] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_MCAST_STARTUP_QUERY_CNT] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_MCAST_LAST_MEMBER_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_MEMBERSHIP_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_QUERIER_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_QUERY_RESPONSE_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_STARTUP_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_NF_CALL_IPTABLES] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_NF_CALL_IP6TABLES] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_NF_CALL_ARPTABLES] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NETLINK_TYPE_U16 },
+};
+
+static const NLType rtnl_link_info_data_vlan_types[] = {
[IFLA_VLAN_ID] = { .type = NETLINK_TYPE_U16 },
/*
[IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) },
@@ -116,24 +145,34 @@ static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
[IFLA_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 },
};
-static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
- [IFLA_VXLAN_ID] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VXLAN_GROUP] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_VXLAN_LINK] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VXLAN_LOCAL] = { .type = NETLINK_TYPE_U32},
- [IFLA_VXLAN_TTL] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_TOS] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_LEARNING] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_AGEING] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VXLAN_LIMIT] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VXLAN_PORT_RANGE] = { .type = NETLINK_TYPE_U32},
- [IFLA_VXLAN_PROXY] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_RSC] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_L2MISS] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_L3MISS] = { .type = NETLINK_TYPE_U8 },
-};
-
-static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = {
+static const NLType rtnl_link_info_data_vxlan_types[] = {
+ [IFLA_VXLAN_ID] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_VXLAN_GROUP] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFLA_VXLAN_LINK] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_VXLAN_LOCAL] = { .type = NETLINK_TYPE_U32},
+ [IFLA_VXLAN_TTL] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_TOS] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_LEARNING] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_AGEING] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_VXLAN_LIMIT] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_VXLAN_PORT_RANGE] = { .type = NETLINK_TYPE_U32},
+ [IFLA_VXLAN_PROXY] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_RSC] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_L2MISS] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_L3MISS] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_PORT] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_VXLAN_GROUP6] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFLA_VXLAN_LOCAL6] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFLA_VXLAN_UDP_CSUM] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_REMCSUM_TX] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_REMCSUM_RX] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_VXLAN_GBP] = { .type = NETLINK_TYPE_FLAG },
+ [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NETLINK_TYPE_FLAG },
+};
+
+static const NLType rtnl_bond_arp_target_types[] = {
[BOND_ARP_TARGETS_0] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_1] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_2] = { .type = NETLINK_TYPE_U32 },
@@ -157,7 +196,7 @@ static const NLTypeSystem rtnl_bond_arp_type_system = {
.types = rtnl_bond_arp_target_types,
};
-static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
+static const NLType rtnl_link_info_data_bond_types[] = {
[IFLA_BOND_MODE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BOND_ACTIVE_SLAVE] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_MIIMON] = { .type = NETLINK_TYPE_U32 },
@@ -183,7 +222,7 @@ static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
[IFLA_BOND_AD_INFO] = { .type = NETLINK_TYPE_NESTED },
};
-static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
+static const NLType rtnl_link_info_data_iptun_types[] = {
[IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 },
[IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
@@ -196,34 +235,40 @@ static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NETLINK_TYPE_U32 },
[IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NETLINK_TYPE_U16 },
[IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NETLINK_TYPE_U16 },
- [IFLA_IPTUN_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16},
- [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16},
- [IFLA_IPTUN_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16},
- [IFLA_IPTUN_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16},
-};
-
-static const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
- [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 },
- [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 },
- [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 },
- [IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 },
- [IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 },
- [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 },
-};
-
-static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
+ [IFLA_IPTUN_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_IPTUN_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_IPTUN_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 },
+};
+
+static const NLType rtnl_link_info_data_ipgre_types[] = {
+ [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_GRE_FLOWINFO] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_GRE_FLAGS] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_GRE_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_GRE_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_GRE_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_GRE_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 },
+};
+
+static const NLType rtnl_link_info_data_ipvti_types[] = {
[IFLA_VTI_LINK] = { .type = NETLINK_TYPE_U32 },
[IFLA_VTI_IKEY] = { .type = NETLINK_TYPE_U32 },
[IFLA_VTI_OKEY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VTI_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_VTI_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFLA_VTI_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFLA_VTI_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
};
-static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
+static const NLType rtnl_link_info_data_ip6tnl_types[] = {
[IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 },
[IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
@@ -231,17 +276,22 @@ static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_FLAGS] = { .type = NETLINK_TYPE_U32 },
[IFLA_IPTUN_PROTO] = { .type = NETLINK_TYPE_U8 },
[IFLA_IPTUN_ENCAP_LIMIT] = { .type = NETLINK_TYPE_U8 },
- [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32},
+ [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLType rtnl_link_info_data_vrf_types[] = {
+ [IFLA_VRF_TABLE] = { .type = NETLINK_TYPE_U32 },
};
/* these strings must match the .kind entries in the kernel */
-static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = {
+static const char* const nl_union_link_info_data_table[] = {
[NL_UNION_LINK_INFO_DATA_BOND] = "bond",
[NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge",
[NL_UNION_LINK_INFO_DATA_VLAN] = "vlan",
[NL_UNION_LINK_INFO_DATA_VETH] = "veth",
[NL_UNION_LINK_INFO_DATA_DUMMY] = "dummy",
[NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan",
+ [NL_UNION_LINK_INFO_DATA_MACVTAP] = "macvtap",
[NL_UNION_LINK_INFO_DATA_IPVLAN] = "ipvlan",
[NL_UNION_LINK_INFO_DATA_VXLAN] = "vxlan",
[NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip",
@@ -253,44 +303,49 @@ static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_
[NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti",
[NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6",
[NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl",
+ [NL_UNION_LINK_INFO_DATA_VRF] = "vrf",
+ [NL_UNION_LINK_INFO_DATA_VCAN] = "vcan",
};
DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
-static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = {
- [NL_UNION_LINK_INFO_DATA_BOND] = { .count = ELEMENTSOF(rtnl_link_info_data_bond_types),
- .types = rtnl_link_info_data_bond_types },
- [NL_UNION_LINK_INFO_DATA_BRIDGE] = { .count = ELEMENTSOF(rtnl_link_info_data_bridge_types),
- .types = rtnl_link_info_data_bridge_types },
- [NL_UNION_LINK_INFO_DATA_VLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_vlan_types),
- .types = rtnl_link_info_data_vlan_types },
- [NL_UNION_LINK_INFO_DATA_VETH] = { .count = ELEMENTSOF(rtnl_link_info_data_veth_types),
- .types = rtnl_link_info_data_veth_types },
- [NL_UNION_LINK_INFO_DATA_MACVLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_macvlan_types),
- .types = rtnl_link_info_data_macvlan_types },
- [NL_UNION_LINK_INFO_DATA_IPVLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvlan_types),
- .types = rtnl_link_info_data_ipvlan_types },
- [NL_UNION_LINK_INFO_DATA_VXLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_vxlan_types),
- .types = rtnl_link_info_data_vxlan_types },
- [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_iptun_types),
- .types = rtnl_link_info_data_iptun_types },
- [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
- .types = rtnl_link_info_data_ipgre_types },
+static const NLTypeSystem rtnl_link_info_data_type_systems[] = {
+ [NL_UNION_LINK_INFO_DATA_BOND] = { .count = ELEMENTSOF(rtnl_link_info_data_bond_types),
+ .types = rtnl_link_info_data_bond_types },
+ [NL_UNION_LINK_INFO_DATA_BRIDGE] = { .count = ELEMENTSOF(rtnl_link_info_data_bridge_types),
+ .types = rtnl_link_info_data_bridge_types },
+ [NL_UNION_LINK_INFO_DATA_VLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_vlan_types),
+ .types = rtnl_link_info_data_vlan_types },
+ [NL_UNION_LINK_INFO_DATA_VETH] = { .count = ELEMENTSOF(rtnl_link_info_data_veth_types),
+ .types = rtnl_link_info_data_veth_types },
+ [NL_UNION_LINK_INFO_DATA_MACVLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_macvlan_types),
+ .types = rtnl_link_info_data_macvlan_types },
+ [NL_UNION_LINK_INFO_DATA_MACVTAP] = { .count = ELEMENTSOF(rtnl_link_info_data_macvlan_types),
+ .types = rtnl_link_info_data_macvlan_types },
+ [NL_UNION_LINK_INFO_DATA_IPVLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvlan_types),
+ .types = rtnl_link_info_data_ipvlan_types },
+ [NL_UNION_LINK_INFO_DATA_VXLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_vxlan_types),
+ .types = rtnl_link_info_data_vxlan_types },
+ [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_iptun_types),
+ .types = rtnl_link_info_data_iptun_types },
+ [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
+ .types = rtnl_link_info_data_ipgre_types },
[NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
- .types = rtnl_link_info_data_ipgre_types },
- [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
- .types = rtnl_link_info_data_ipgre_types },
- [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
- .types = rtnl_link_info_data_ipgre_types },
- [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_iptun_types),
- .types = rtnl_link_info_data_iptun_types },
- [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvti_types),
- .types = rtnl_link_info_data_ipvti_types },
- [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvti_types),
- .types = rtnl_link_info_data_ipvti_types },
- [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types),
- .types = rtnl_link_info_data_ip6tnl_types },
-
+ .types = rtnl_link_info_data_ipgre_types },
+ [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
+ .types = rtnl_link_info_data_ipgre_types },
+ [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
+ .types = rtnl_link_info_data_ipgre_types },
+ [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_iptun_types),
+ .types = rtnl_link_info_data_iptun_types },
+ [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvti_types),
+ .types = rtnl_link_info_data_ipvti_types },
+ [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvti_types),
+ .types = rtnl_link_info_data_ipvti_types },
+ [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types),
+ .types = rtnl_link_info_data_ip6tnl_types },
+ [NL_UNION_LINK_INFO_DATA_VRF] = { .count = ELEMENTSOF(rtnl_link_info_data_vrf_types),
+ .types = rtnl_link_info_data_vrf_types },
};
static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
@@ -301,7 +356,7 @@ static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
.match = IFLA_INFO_KIND,
};
-static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = {
+static const NLType rtnl_link_info_types[] = {
[IFLA_INFO_KIND] = { .type = NETLINK_TYPE_STRING },
[IFLA_INFO_DATA] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
/*
@@ -316,18 +371,21 @@ static const NLTypeSystem rtnl_link_info_type_system = {
.types = rtnl_link_info_types,
};
-static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
+static const struct NLType rtnl_prot_info_bridge_port_types[] = {
[IFLA_BRPORT_STATE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_COST] = { .type = NETLINK_TYPE_U32 },
[IFLA_BRPORT_PRIORITY] = { .type = NETLINK_TYPE_U16 },
[IFLA_BRPORT_MODE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_GUARD] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_PROTECT] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BRPORT_FAST_LEAVE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_LEARNING] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_UNICAST_FLOOD] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BRPORT_PROXYARP] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BRPORT_LEARNING_SYNC] = { .type = NETLINK_TYPE_U8 },
};
-static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
+static const NLTypeSystem rtnl_prot_info_type_systems[] = {
[AF_BRIDGE] = { .count = ELEMENTSOF(rtnl_prot_info_bridge_port_types),
.types = rtnl_prot_info_bridge_port_types },
};
@@ -338,7 +396,7 @@ static const NLTypeSystemUnion rtnl_prot_info_type_system_union = {
.match_type = NL_MATCH_PROTOCOL,
};
-static const struct NLType rtnl_af_spec_inet6_types[IFLA_INET6_MAX + 1] = {
+static const struct NLType rtnl_af_spec_inet6_types[] = {
[IFLA_INET6_FLAGS] = { .type = NETLINK_TYPE_U32 },
/*
IFLA_INET6_CONF,
@@ -356,7 +414,7 @@ static const NLTypeSystem rtnl_af_spec_inet6_type_system = {
.types = rtnl_af_spec_inet6_types,
};
-static const NLType rtnl_af_spec_types[AF_MAX + 1] = {
+static const NLType rtnl_af_spec_types[] = {
[AF_INET6] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_inet6_type_system },
};
@@ -365,10 +423,10 @@ static const NLTypeSystem rtnl_af_spec_type_system = {
.types = rtnl_af_spec_types,
};
-static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
- [IFLA_ADDRESS] = { .type = NETLINK_TYPE_ETHER_ADDR, },
- [IFLA_BROADCAST] = { .type = NETLINK_TYPE_ETHER_ADDR, },
- [IFLA_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1, },
+static const NLType rtnl_link_types[] = {
+ [IFLA_ADDRESS] = { .type = NETLINK_TYPE_ETHER_ADDR },
+ [IFLA_BROADCAST] = { .type = NETLINK_TYPE_ETHER_ADDR },
+ [IFLA_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
[IFLA_MTU] = { .type = NETLINK_TYPE_U32 },
[IFLA_LINK] = { .type = NETLINK_TYPE_U32 },
/*
@@ -424,7 +482,7 @@ static const NLTypeSystem rtnl_link_type_system = {
/* IFA_FLAGS was defined in kernel 3.14, but we still support older
* kernels where IFA_MAX is lower. */
-static const NLType rtnl_address_types[CONST_MAX(IFA_MAX, IFA_FLAGS) + 1] = {
+static const NLType rtnl_address_types[] = {
[IFA_ADDRESS] = { .type = NETLINK_TYPE_IN_ADDR },
[IFA_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
[IFA_LABEL] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
@@ -442,7 +500,7 @@ static const NLTypeSystem rtnl_address_type_system = {
.types = rtnl_address_types,
};
-static const NLType rtnl_route_types[RTA_MAX + 1] = {
+static const NLType rtnl_route_types[] = {
[RTA_DST] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
[RTA_SRC] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
[RTA_IIF] = { .type = NETLINK_TYPE_U32 },
@@ -460,7 +518,11 @@ static const NLType rtnl_route_types[RTA_MAX + 1] = {
RTA_TABLE,
RTA_MARK,
RTA_MFC_STATS,
+ RTA_VIA,
+ RTA_NEWDST,
*/
+ [RTA_PREF] = { .type = NETLINK_TYPE_U8 },
+
};
static const NLTypeSystem rtnl_route_type_system = {
@@ -468,7 +530,7 @@ static const NLTypeSystem rtnl_route_type_system = {
.types = rtnl_route_types,
};
-static const NLType rtnl_neigh_types[NDA_MAX + 1] = {
+static const NLType rtnl_neigh_types[] = {
[NDA_DST] = { .type = NETLINK_TYPE_IN_ADDR },
[NDA_LLADDR] = { .type = NETLINK_TYPE_ETHER_ADDR },
[NDA_CACHEINFO] = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
@@ -484,7 +546,7 @@ static const NLTypeSystem rtnl_neigh_type_system = {
.types = rtnl_neigh_types,
};
-static const NLType rtnl_types[RTM_MAX + 1] = {
+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) },
diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h
index a210163241..42e96173de 100644
--- a/src/libsystemd/sd-netlink/netlink-types.h
+++ b/src/libsystemd/sd-netlink/netlink-types.h
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
#pragma once
/***
@@ -21,6 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "macro.h"
+
enum {
NETLINK_TYPE_UNSPEC,
NETLINK_TYPE_U8, /* NLA_U8 */
@@ -28,6 +28,7 @@ enum {
NETLINK_TYPE_U32, /* NLA_U32 */
NETLINK_TYPE_U64, /* NLA_U64 */
NETLINK_TYPE_STRING, /* NLA_STRING */
+ NETLINK_TYPE_FLAG, /* NLA_FLAG */
NETLINK_TYPE_IN_ADDR,
NETLINK_TYPE_ETHER_ADDR,
NETLINK_TYPE_CACHE_INFO,
@@ -73,6 +74,7 @@ typedef enum NLUnionLinkInfoData {
NL_UNION_LINK_INFO_DATA_VETH,
NL_UNION_LINK_INFO_DATA_DUMMY,
NL_UNION_LINK_INFO_DATA_MACVLAN,
+ NL_UNION_LINK_INFO_DATA_MACVTAP,
NL_UNION_LINK_INFO_DATA_IPVLAN,
NL_UNION_LINK_INFO_DATA_VXLAN,
NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL,
@@ -84,6 +86,8 @@ typedef enum NLUnionLinkInfoData {
NL_UNION_LINK_INFO_DATA_VTI_TUNNEL,
NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL,
NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL,
+ NL_UNION_LINK_INFO_DATA_VRF,
+ NL_UNION_LINK_INFO_DATA_VCAN,
_NL_UNION_LINK_INFO_DATA_MAX,
_NL_UNION_LINK_INFO_DATA_INVALID = -1
} NLUnionLinkInfoData;
diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
index 482ff6b1c2..73b9ac0258 100644
--- a/src/libsystemd/sd-netlink/netlink-util.c
+++ b/src/libsystemd/sd-netlink/netlink-util.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -19,14 +17,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
#include "sd-netlink.h"
-#include "netlink-util.h"
#include "netlink-internal.h"
+#include "netlink-util.h"
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
- _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
int r;
assert(rtnl);
@@ -56,7 +53,7 @@ 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) {
- _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
int r;
assert(rtnl);
diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h
index 9df0aa28bf..f49bf4eaa6 100644
--- a/src/libsystemd/sd-netlink/netlink-util.h
+++ b/src/libsystemd/sd-netlink/netlink-util.h
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
#pragma once
/***
@@ -21,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "sd-netlink.h"
#include "util.h"
-#include "sd-netlink.h"
int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret);
uint32_t rtnl_message_get_serial(sd_netlink_message *m);
@@ -39,9 +37,3 @@ int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias,
int rtnl_log_parse_error(int r);
int rtnl_log_create_error(int r);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_netlink*, sd_netlink_unref);
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_netlink_message*, sd_netlink_message_unref);
-
-#define _cleanup_netlink_unref_ _cleanup_(sd_netlink_unrefp)
-#define _cleanup_netlink_message_unref_ _cleanup_(sd_netlink_message_unrefp)
diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c
index 2f31f4ee69..09240c7b2a 100644
--- a/src/libsystemd/sd-netlink/rtnl-message.c
+++ b/src/libsystemd/sd-netlink/rtnl-message.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -23,16 +21,16 @@
#include <stdbool.h>
#include <unistd.h>
-#include "util.h"
-#include "socket-util.h"
+#include "sd-netlink.h"
+
#include "formats-util.h"
-#include "refcnt.h"
#include "missing.h"
-
-#include "sd-netlink.h"
-#include "netlink-util.h"
#include "netlink-internal.h"
#include "netlink-types.h"
+#include "netlink-util.h"
+#include "refcnt.h"
+#include "socket-util.h"
+#include "util.h"
int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
struct rtmsg *rtm;
@@ -84,6 +82,49 @@ int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope)
return 0;
}
+int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ rtm->rtm_flags = flags;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(flags, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *flags = rtm->rtm_flags;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ rtm->rtm_table = table;
+
+ return 0;
+}
+
int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
struct rtmsg *rtm;
@@ -99,6 +140,80 @@ int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
return 0;
}
+int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ rtm->rtm_family = family;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(protocol, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *protocol = rtm->rtm_protocol;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(scope, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *scope = rtm->rtm_scope;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(tos, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *tos = rtm->rtm_tos;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(table, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *table = rtm->rtm_table;
+
+ return 0;
+}
+
int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
struct rtmsg *rtm;
@@ -315,7 +430,6 @@ int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret,
int r;
assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
- assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
@@ -529,7 +643,7 @@ int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) {
return 0;
}
-int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) {
+int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type) {
struct ifinfomsg *ifi;
assert_return(m, -EINVAL);
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index c413b1c266..43114eb825 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -19,20 +17,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
#include <poll.h>
-
-#include "missing.h"
-#include "macro.h"
-#include "util.h"
-#include "hashmap.h"
+#include <sys/socket.h>
#include "sd-netlink.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "hashmap.h"
+#include "macro.h"
+#include "missing.h"
#include "netlink-internal.h"
#include "netlink-util.h"
+#include "socket-util.h"
+#include "util.h"
static int sd_netlink_new(sd_netlink **ret) {
- _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
assert_return(ret, -EINVAL);
@@ -41,11 +42,8 @@ static int sd_netlink_new(sd_netlink **ret) {
return -ENOMEM;
rtnl->n_ref = REFCNT_INIT;
-
rtnl->fd = -1;
-
rtnl->sockaddr.nl.nl_family = AF_NETLINK;
-
rtnl->original_pid = getpid();
LIST_HEAD_INIT(rtnl->match_callbacks);
@@ -68,7 +66,7 @@ static int sd_netlink_new(sd_netlink **ret) {
}
int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) {
- _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
socklen_t addrlen;
int r;
@@ -84,6 +82,9 @@ int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) {
if (r < 0)
return -errno;
+ if (rtnl->sockaddr.nl.nl_family != AF_NETLINK)
+ return -EINVAL;
+
rtnl->fd = fd;
*ret = rtnl;
@@ -102,11 +103,11 @@ static bool rtnl_pid_changed(sd_netlink *rtnl) {
}
int sd_netlink_open_fd(sd_netlink **ret, int fd) {
- _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
int r;
assert_return(ret, -EINVAL);
- assert_return(fd >= 0, -EINVAL);
+ assert_return(fd >= 0, -EBADF);
r = sd_netlink_new(&rtnl);
if (r < 0)
@@ -115,8 +116,10 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) {
rtnl->fd = fd;
r = socket_bind(rtnl);
- if (r < 0)
+ if (r < 0) {
+ rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */
return r;
+ }
*ret = rtnl;
rtnl = NULL;
@@ -141,7 +144,10 @@ int sd_netlink_open(sd_netlink **ret) {
return 0;
}
-int sd_netlink_inc_rcvbuf(const sd_netlink *const rtnl, const int size) {
+int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) {
+ assert_return(rtnl, -EINVAL);
+ assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
return fd_inc_rcvbuf(rtnl->fd, size);
}
@@ -183,10 +189,11 @@ sd_netlink *sd_netlink_unref(sd_netlink *rtnl) {
sd_event_unref(rtnl->event);
while ((f = rtnl->match_callbacks)) {
- LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
- free(f);
+ sd_netlink_remove_match(rtnl, f->type, f->callback, f->userdata);
}
+ hashmap_free(rtnl->broadcast_group_refs);
+
safe_close(rtnl->fd);
free(rtnl);
}
@@ -275,14 +282,14 @@ static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) {
/* Dispatch a queued message */
*message = rtnl->rqueue[0];
- rtnl->rqueue_size --;
+ rtnl->rqueue_size--;
memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_netlink_message*) * rtnl->rqueue_size);
return 1;
}
static int process_timeout(sd_netlink *rtnl) {
- _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
struct reply_callback *c;
usec_t n;
int r;
@@ -372,7 +379,7 @@ static int process_match(sd_netlink *rtnl, sd_netlink_message *m) {
}
static int process_running(sd_netlink *rtnl, sd_netlink_message **ret) {
- _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
assert(rtnl);
@@ -414,7 +421,7 @@ null_message:
}
int sd_netlink_process(sd_netlink *rtnl, sd_netlink_message **ret) {
- RTNL_DONT_DESTROY(rtnl);
+ NETLINK_DONT_DESTROY(rtnl);
int r;
assert_return(rtnl, -EINVAL);
@@ -619,7 +626,7 @@ int sd_netlink_call(sd_netlink *rtnl,
received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
if (received_serial == serial) {
- _cleanup_netlink_message_unref_ sd_netlink_message *incoming = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *incoming = NULL;
uint16_t type;
incoming = rtnl->rqueue[i];
@@ -770,7 +777,7 @@ static int prepare_callback(sd_event_source *s, void *userdata) {
return 1;
}
-int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int priority) {
+int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) {
int r;
assert_return(rtnl, -EINVAL);
@@ -856,25 +863,32 @@ int sd_netlink_add_match(sd_netlink *rtnl,
switch (type) {
case RTM_NEWLINK:
- case RTM_SETLINK:
- case RTM_GETLINK:
case RTM_DELLINK:
- r = socket_join_broadcast_group(rtnl, RTNLGRP_LINK);
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK);
if (r < 0)
return r;
break;
case RTM_NEWADDR:
- case RTM_GETADDR:
case RTM_DELADDR:
- r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR);
+ if (r < 0)
+ return r;
+
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR);
if (r < 0)
return r;
- r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR);
+ break;
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE);
if (r < 0)
return r;
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE);
+ if (r < 0)
+ return r;
break;
default:
return -EOPNOTSUPP;
@@ -892,23 +906,50 @@ int sd_netlink_remove_match(sd_netlink *rtnl,
sd_netlink_message_handler_t callback,
void *userdata) {
struct match_callback *c;
+ int r;
assert_return(rtnl, -EINVAL);
assert_return(callback, -EINVAL);
assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
- /* we should unsubscribe from the broadcast groups at this point, but it is not so
- trivial for a few reasons: the refcounting is a bit of a mess and not obvious
- how it will look like after we add genetlink support, and it is also not possible
- to query what broadcast groups were subscribed to when we inherit the socket to get
- the initial refcount. The latter could indeed be done for the first 32 broadcast
- groups (which incidentally is all we currently support in .socket units anyway),
- but we better not rely on only ever using 32 groups. */
LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
if (c->callback == callback && c->type == type && c->userdata == userdata) {
LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
free(c);
+ switch (type) {
+ case RTM_NEWLINK:
+ case RTM_DELLINK:
+ r = socket_broadcast_group_unref(rtnl, RTNLGRP_LINK);
+ if (r < 0)
+ return r;
+
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_IFADDR);
+ if (r < 0)
+ return r;
+
+ r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_IFADDR);
+ if (r < 0)
+ return r;
+
+ break;
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_ROUTE);
+ if (r < 0)
+ return r;
+
+ r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_ROUTE);
+ if (r < 0)
+ return r;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
return 1;
}
diff --git a/src/libsystemd/sd-netlink/test-local-addresses.c b/src/libsystemd/sd-netlink/test-local-addresses.c
index 38cbcfbccb..e0e28cc0cc 100644
--- a/src/libsystemd/sd-netlink/test-local-addresses.c
+++ b/src/libsystemd/sd-netlink/test-local-addresses.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -19,9 +17,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "af-list.h"
+#include "alloc-util.h"
#include "in-addr-util.h"
#include "local-addresses.h"
-#include "af-list.h"
static void print_local_addresses(struct local_address *a, unsigned n) {
unsigned i;
@@ -44,9 +43,8 @@ int main(int argc, char *argv[]) {
printf("Local Addresses:\n");
print_local_addresses(a, (unsigned) n);
- free(a);
+ a = mfree(a);
- a = NULL;
n = local_gateways(NULL, 0, AF_UNSPEC, &a);
assert_se(n >= 0);
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index c9cb415ca0..58c2e892f5 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -19,19 +17,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
#include <net/if.h>
+#include <netinet/ether.h>
-#include "util.h"
-#include "macro.h"
#include "sd-netlink.h"
-#include "socket-util.h"
-#include "netlink-util.h"
-#include "event-util.h"
+
+#include "ether-addr-util.h"
+#include "macro.h"
#include "missing.h"
+#include "netlink-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "util.h"
static void test_message_link_bridge(sd_netlink *rtnl) {
- _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
uint32_t cost;
assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0);
@@ -49,7 +49,7 @@ static void test_message_link_bridge(sd_netlink *rtnl) {
}
static void test_link_configure(sd_netlink *rtnl, int ifindex) {
- _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
const char *mac = "98:fe:94:3f:c6:18", *name = "test";
char buffer[ETHER_ADDR_TO_STRING_MAX];
unsigned int mtu = 1450, mtu_out;
@@ -143,7 +143,7 @@ static void test_address_get(sd_netlink *rtnl, int ifindex) {
}
static void test_route(void) {
- _cleanup_netlink_message_unref_ sd_netlink_message *req;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req;
struct in_addr addr, addr_data;
uint32_t index = 2, u32_data;
int r;
@@ -206,9 +206,9 @@ static int link_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata)
}
static void test_event_loop(int ifindex) {
- _cleanup_event_unref_ sd_event *event = NULL;
- _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
- _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+ _cleanup_(sd_event_unrefp) sd_event *event = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
char *ifname;
ifname = strdup("lo2");
@@ -217,7 +217,7 @@ static void test_event_loop(int ifindex) {
assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
- assert_se(sd_netlink_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
+ assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, NULL) >= 0);
assert_se(sd_event_default(&event) >= 0);
@@ -234,7 +234,7 @@ static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata)
int *counter = userdata;
int r;
- (*counter) --;
+ (*counter)--;
r = sd_netlink_message_get_errno(m);
@@ -246,8 +246,8 @@ static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata)
}
static void test_async(int ifindex) {
- _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
- _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL, *r = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
uint32_t serial;
char *ifname;
@@ -258,7 +258,7 @@ static void test_async(int ifindex) {
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
- assert_se(sd_netlink_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
+ assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, &serial) >= 0);
assert_se(sd_netlink_wait(rtnl, 0) >= 0);
assert_se(sd_netlink_process(rtnl, &r) >= 0);
@@ -267,8 +267,8 @@ static void test_async(int ifindex) {
}
static void test_pipe(int ifindex) {
- _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
- _cleanup_netlink_message_unref_ sd_netlink_message *m1 = NULL, *m2 = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m1 = NULL, *m2 = NULL;
int counter = 0;
assert_se(sd_netlink_open(&rtnl) >= 0);
@@ -276,11 +276,11 @@ static void test_pipe(int ifindex) {
assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
- counter ++;
- assert_se(sd_netlink_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
+ counter++;
+ assert_se(sd_netlink_call_async(rtnl, m1, pipe_handler, &counter, 0, NULL) >= 0);
- counter ++;
- assert_se(sd_netlink_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
+ counter++;
+ assert_se(sd_netlink_call_async(rtnl, m2, pipe_handler, &counter, 0, NULL) >= 0);
while (counter > 0) {
assert_se(sd_netlink_wait(rtnl, 0) >= 0);
@@ -291,7 +291,7 @@ static void test_pipe(int ifindex) {
}
static void test_container(void) {
- _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
uint16_t u16_data;
uint32_t u32_data;
const char *string_data;
@@ -326,22 +326,22 @@ static void test_container(void) {
}
static void test_match(void) {
- _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
assert_se(sd_netlink_open(&rtnl) >= 0);
- assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
- assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
+ assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0);
+ assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0);
- assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
- assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
- assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
+ assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 1);
+ assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 1);
+ assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 0);
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
}
static void test_get_addresses(sd_netlink *rtnl) {
- _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
sd_netlink_message *m;
assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0);
@@ -369,7 +369,7 @@ static void test_get_addresses(sd_netlink *rtnl) {
}
static void test_message(void) {
- _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
assert_se(rtnl_message_new_synthetic_error(-ETIMEDOUT, 1, &m) >= 0);
assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT);