Merge pull request #10407 from yuwata/netlink-slot
sd-netlink: introduce sd_netlink_slot object and relevant functions
This commit is contained in:
@@ -66,6 +66,8 @@ libsystemd_sources = files('''
|
||||
sd-netlink/local-addresses.h
|
||||
sd-netlink/netlink-internal.h
|
||||
sd-netlink/netlink-message.c
|
||||
sd-netlink/netlink-slot.c
|
||||
sd-netlink/netlink-slot.h
|
||||
sd-netlink/netlink-socket.c
|
||||
sd-netlink/netlink-types.c
|
||||
sd-netlink/netlink-types.h
|
||||
|
||||
@@ -19,21 +19,42 @@
|
||||
|
||||
struct reply_callback {
|
||||
sd_netlink_message_handler_t callback;
|
||||
void *userdata;
|
||||
usec_t timeout;
|
||||
uint64_t serial;
|
||||
unsigned prioq_idx;
|
||||
sd_netlink_destroy_t destroy_callback;
|
||||
};
|
||||
|
||||
struct match_callback {
|
||||
sd_netlink_message_handler_t callback;
|
||||
uint16_t type;
|
||||
void *userdata;
|
||||
|
||||
LIST_FIELDS(struct match_callback, match_callbacks);
|
||||
};
|
||||
|
||||
typedef enum NetlinkSlotType {
|
||||
NETLINK_REPLY_CALLBACK,
|
||||
NETLINK_MATCH_CALLBACK,
|
||||
_NETLINK_SLOT_INVALID = -1,
|
||||
} NetlinkSlotType;
|
||||
|
||||
struct sd_netlink_slot {
|
||||
unsigned n_ref;
|
||||
sd_netlink *netlink;
|
||||
void *userdata;
|
||||
sd_netlink_destroy_t destroy_callback;
|
||||
NetlinkSlotType type:2;
|
||||
|
||||
bool floating:1;
|
||||
char *description;
|
||||
|
||||
LIST_FIELDS(sd_netlink_slot, slots);
|
||||
|
||||
union {
|
||||
struct reply_callback reply_callback;
|
||||
struct match_callback match_callback;
|
||||
};
|
||||
};
|
||||
|
||||
struct sd_netlink {
|
||||
RefCount n_ref;
|
||||
|
||||
@@ -69,6 +90,8 @@ struct sd_netlink {
|
||||
|
||||
LIST_HEAD(struct match_callback, match_callbacks);
|
||||
|
||||
LIST_HEAD(sd_netlink_slot, slots);
|
||||
|
||||
pid_t original_pid;
|
||||
|
||||
sd_event_source *io_event_source;
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "netlink-internal.h"
|
||||
#include "netlink-slot.h"
|
||||
#include "string-util.h"
|
||||
|
||||
int netlink_slot_allocate(
|
||||
sd_netlink *nl,
|
||||
bool floating,
|
||||
NetlinkSlotType type,
|
||||
size_t extra,
|
||||
sd_netlink_destroy_t destroy_callback,
|
||||
void *userdata,
|
||||
const char *description,
|
||||
sd_netlink_slot **ret) {
|
||||
|
||||
_cleanup_free_ sd_netlink_slot *slot = NULL;
|
||||
|
||||
assert(nl);
|
||||
assert(ret);
|
||||
|
||||
slot = malloc0(offsetof(sd_netlink_slot, reply_callback) + extra);
|
||||
if (!slot)
|
||||
return -ENOMEM;
|
||||
|
||||
slot->n_ref = 1;
|
||||
slot->netlink = nl;
|
||||
slot->userdata = userdata;
|
||||
slot->destroy_callback = destroy_callback;
|
||||
slot->type = type;
|
||||
slot->floating = floating;
|
||||
|
||||
if (description) {
|
||||
slot->description = strdup(description);
|
||||
if (!slot->description)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!floating)
|
||||
sd_netlink_ref(nl);
|
||||
|
||||
LIST_PREPEND(slots, nl->slots, slot);
|
||||
|
||||
*ret = TAKE_PTR(slot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void netlink_slot_disconnect(sd_netlink_slot *slot, bool unref) {
|
||||
sd_netlink *nl;
|
||||
|
||||
assert(slot);
|
||||
|
||||
nl = slot->netlink;
|
||||
if (!nl)
|
||||
return;
|
||||
|
||||
switch (slot->type) {
|
||||
|
||||
case NETLINK_REPLY_CALLBACK:
|
||||
(void) hashmap_remove(nl->reply_callbacks, &slot->reply_callback.serial);
|
||||
|
||||
if (slot->reply_callback.timeout != 0)
|
||||
prioq_remove(nl->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
|
||||
|
||||
break;
|
||||
case NETLINK_MATCH_CALLBACK:
|
||||
LIST_REMOVE(match_callbacks, nl->match_callbacks, &slot->match_callback);
|
||||
|
||||
switch (slot->match_callback.type) {
|
||||
case RTM_NEWLINK:
|
||||
case RTM_DELLINK:
|
||||
(void) socket_broadcast_group_unref(nl, RTNLGRP_LINK);
|
||||
|
||||
break;
|
||||
case RTM_NEWADDR:
|
||||
case RTM_DELADDR:
|
||||
(void) socket_broadcast_group_unref(nl, RTNLGRP_IPV4_IFADDR);
|
||||
(void) socket_broadcast_group_unref(nl, RTNLGRP_IPV6_IFADDR);
|
||||
|
||||
break;
|
||||
case RTM_NEWROUTE:
|
||||
case RTM_DELROUTE:
|
||||
(void) socket_broadcast_group_unref(nl, RTNLGRP_IPV4_ROUTE);
|
||||
(void) socket_broadcast_group_unref(nl, RTNLGRP_IPV6_ROUTE);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
assert_not_reached("Wut? Unknown slot type?");
|
||||
}
|
||||
|
||||
slot->type = _NETLINK_SLOT_INVALID;
|
||||
slot->netlink = NULL;
|
||||
LIST_REMOVE(slots, nl->slots, slot);
|
||||
|
||||
if (!slot->floating)
|
||||
sd_netlink_unref(nl);
|
||||
else if (unref)
|
||||
sd_netlink_slot_unref(slot);
|
||||
}
|
||||
|
||||
static sd_netlink_slot* netlink_slot_free(sd_netlink_slot *slot) {
|
||||
assert(slot);
|
||||
|
||||
netlink_slot_disconnect(slot, false);
|
||||
|
||||
if (slot->destroy_callback)
|
||||
slot->destroy_callback(slot->userdata);
|
||||
|
||||
free(slot->description);
|
||||
return mfree(slot);
|
||||
}
|
||||
|
||||
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_netlink_slot, sd_netlink_slot, netlink_slot_free);
|
||||
|
||||
sd_netlink *sd_netlink_slot_get_netlink(sd_netlink_slot *slot) {
|
||||
assert_return(slot, NULL);
|
||||
|
||||
return slot->netlink;
|
||||
}
|
||||
|
||||
void *sd_netlink_slot_get_userdata(sd_netlink_slot *slot) {
|
||||
assert_return(slot, NULL);
|
||||
|
||||
return slot->userdata;
|
||||
}
|
||||
|
||||
void *sd_netlink_slot_set_userdata(sd_netlink_slot *slot, void *userdata) {
|
||||
void *ret;
|
||||
|
||||
assert_return(slot, NULL);
|
||||
|
||||
ret = slot->userdata;
|
||||
slot->userdata = userdata;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sd_netlink_slot_get_destroy_callback(sd_netlink_slot *slot, sd_netlink_destroy_t *callback) {
|
||||
assert_return(slot, -EINVAL);
|
||||
|
||||
if (callback)
|
||||
*callback = slot->destroy_callback;
|
||||
|
||||
return !!slot->destroy_callback;
|
||||
}
|
||||
|
||||
int sd_netlink_slot_set_destroy_callback(sd_netlink_slot *slot, sd_netlink_destroy_t callback) {
|
||||
assert_return(slot, -EINVAL);
|
||||
|
||||
slot->destroy_callback = callback;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_slot_get_floating(sd_netlink_slot *slot) {
|
||||
assert_return(slot, -EINVAL);
|
||||
|
||||
return slot->floating;
|
||||
}
|
||||
|
||||
int sd_netlink_slot_set_floating(sd_netlink_slot *slot, int b) {
|
||||
assert_return(slot, -EINVAL);
|
||||
|
||||
if (slot->floating == !!b)
|
||||
return 0;
|
||||
|
||||
if (!slot->netlink) /* Already disconnected */
|
||||
return -ESTALE;
|
||||
|
||||
slot->floating = b;
|
||||
|
||||
if (b) {
|
||||
sd_netlink_slot_ref(slot);
|
||||
sd_netlink_unref(slot->netlink);
|
||||
} else {
|
||||
sd_netlink_ref(slot->netlink);
|
||||
sd_netlink_slot_unref(slot);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sd_netlink_slot_get_description(sd_netlink_slot *slot, const char **description) {
|
||||
assert_return(slot, -EINVAL);
|
||||
|
||||
if (description)
|
||||
*description = slot->description;
|
||||
|
||||
return !!slot->description;
|
||||
}
|
||||
|
||||
int sd_netlink_slot_set_description(sd_netlink_slot *slot, const char *description) {
|
||||
assert_return(slot, -EINVAL);
|
||||
|
||||
return free_and_strdup(&slot->description, description);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
int netlink_slot_allocate(
|
||||
sd_netlink *nl,
|
||||
bool floating,
|
||||
NetlinkSlotType type,
|
||||
size_t extra,
|
||||
sd_netlink_destroy_t destroy_callback,
|
||||
void *userdata,
|
||||
const char *description,
|
||||
sd_netlink_slot **ret);
|
||||
void netlink_slot_disconnect(sd_netlink_slot *slot, bool unref);
|
||||
@@ -11,9 +11,11 @@
|
||||
#include "macro.h"
|
||||
#include "missing.h"
|
||||
#include "netlink-internal.h"
|
||||
#include "netlink-slot.h"
|
||||
#include "netlink-util.h"
|
||||
#include "process-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
static int sd_netlink_new(sd_netlink **ret) {
|
||||
@@ -148,8 +150,7 @@ int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) {
|
||||
}
|
||||
|
||||
static sd_netlink *netlink_free(sd_netlink *rtnl) {
|
||||
struct reply_callback *c;
|
||||
struct match_callback *f;
|
||||
sd_netlink_slot *s;
|
||||
unsigned i;
|
||||
|
||||
assert(rtnl);
|
||||
@@ -164,10 +165,9 @@ static sd_netlink *netlink_free(sd_netlink *rtnl) {
|
||||
|
||||
free(rtnl->rbuffer);
|
||||
|
||||
while ((c = hashmap_steal_first(rtnl->reply_callbacks))) {
|
||||
if (c->destroy_callback)
|
||||
c->destroy_callback(c->userdata);
|
||||
free(c);
|
||||
while ((s = rtnl->slots)) {
|
||||
assert(s->floating);
|
||||
netlink_slot_disconnect(s, true);
|
||||
}
|
||||
hashmap_free(rtnl->reply_callbacks);
|
||||
prioq_free(rtnl->reply_callbacks_prioq);
|
||||
@@ -176,9 +176,6 @@ static sd_netlink *netlink_free(sd_netlink *rtnl) {
|
||||
sd_event_source_unref(rtnl->time_event_source);
|
||||
sd_event_unref(rtnl->event);
|
||||
|
||||
while ((f = rtnl->match_callbacks))
|
||||
sd_netlink_remove_match(rtnl, f->type, f->callback, f->userdata);
|
||||
|
||||
hashmap_free(rtnl->broadcast_group_refs);
|
||||
|
||||
safe_close(rtnl->fd);
|
||||
@@ -281,6 +278,7 @@ static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) {
|
||||
static int process_timeout(sd_netlink *rtnl) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
struct reply_callback *c;
|
||||
sd_netlink_slot *slot;
|
||||
usec_t n;
|
||||
int r;
|
||||
|
||||
@@ -299,22 +297,27 @@ static int process_timeout(sd_netlink *rtnl) {
|
||||
return r;
|
||||
|
||||
assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
|
||||
c->timeout = 0;
|
||||
hashmap_remove(rtnl->reply_callbacks, &c->serial);
|
||||
|
||||
r = c->callback(rtnl, m, c->userdata);
|
||||
slot = container_of(c, sd_netlink_slot, reply_callback);
|
||||
|
||||
r = c->callback(rtnl, m, slot->userdata);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "sd-netlink: timedout callback failed: %m");
|
||||
log_debug_errno(r, "sd-netlink: timedout callback %s%s%sfailed: %m",
|
||||
slot->description ? "'" : "",
|
||||
strempty(slot->description),
|
||||
slot->description ? "' " : "");
|
||||
|
||||
if (c->destroy_callback)
|
||||
c->destroy_callback(c->userdata);
|
||||
|
||||
free(c);
|
||||
if (slot->floating)
|
||||
netlink_slot_disconnect(slot, true);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) {
|
||||
_cleanup_free_ struct reply_callback *c = NULL;
|
||||
struct reply_callback *c;
|
||||
sd_netlink_slot *slot;
|
||||
uint64_t serial;
|
||||
uint16_t type;
|
||||
int r;
|
||||
@@ -327,28 +330,36 @@ static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) {
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
if (c->timeout != 0)
|
||||
if (c->timeout != 0) {
|
||||
prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
|
||||
c->timeout = 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_get_type(m, &type);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
return r;
|
||||
|
||||
if (type == NLMSG_DONE)
|
||||
m = NULL;
|
||||
|
||||
r = c->callback(rtnl, m, c->userdata);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "sd-netlink: callback failed: %m");
|
||||
slot = container_of(c, sd_netlink_slot, reply_callback);
|
||||
|
||||
if (c->destroy_callback)
|
||||
c->destroy_callback(c->userdata);
|
||||
r = c->callback(rtnl, m, slot->userdata);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "sd-netlink: reply callback %s%s%sfailed: %m",
|
||||
slot->description ? "'" : "",
|
||||
strempty(slot->description),
|
||||
slot->description ? "' " : "");
|
||||
|
||||
if (slot->floating)
|
||||
netlink_slot_disconnect(slot, true);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int process_match(sd_netlink *rtnl, sd_netlink_message *m) {
|
||||
struct match_callback *c;
|
||||
sd_netlink_slot *slot;
|
||||
uint16_t type;
|
||||
int r;
|
||||
|
||||
@@ -361,10 +372,15 @@ static int process_match(sd_netlink *rtnl, sd_netlink_message *m) {
|
||||
|
||||
LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
|
||||
if (type == c->type) {
|
||||
r = c->callback(rtnl, m, c->userdata);
|
||||
slot = container_of(c, sd_netlink_slot, match_callback);
|
||||
|
||||
r = c->callback(rtnl, m, slot->userdata);
|
||||
if (r != 0) {
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "sd-netlink: match callback failed: %m");
|
||||
log_debug_errno(r, "sd-netlink: match callback %s%s%sfailed: %m",
|
||||
slot->description ? "'" : "",
|
||||
strempty(slot->description),
|
||||
slot->description ? "' " : "");
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -508,13 +524,14 @@ static int timeout_compare(const void *a, const void *b) {
|
||||
|
||||
int sd_netlink_call_async(
|
||||
sd_netlink *nl,
|
||||
sd_netlink_slot **ret_slot,
|
||||
sd_netlink_message *m,
|
||||
sd_netlink_message_handler_t callback,
|
||||
sd_netlink_destroy_t destroy_callback,
|
||||
void *userdata,
|
||||
uint64_t usec,
|
||||
uint32_t *serial) {
|
||||
_cleanup_free_ struct reply_callback *c = NULL;
|
||||
const char *description) {
|
||||
_cleanup_free_ sd_netlink_slot *slot = NULL;
|
||||
uint32_t s;
|
||||
int r, k;
|
||||
|
||||
@@ -533,65 +550,39 @@ int sd_netlink_call_async(
|
||||
return r;
|
||||
}
|
||||
|
||||
c = new(struct reply_callback, 1);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
r = netlink_slot_allocate(nl, !ret_slot, NETLINK_REPLY_CALLBACK, sizeof(struct reply_callback), destroy_callback, userdata, description, &slot);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*c = (struct reply_callback) {
|
||||
.callback = callback,
|
||||
.userdata = userdata,
|
||||
.timeout = calc_elapse(usec),
|
||||
.destroy_callback = destroy_callback,
|
||||
};
|
||||
slot->reply_callback.callback = callback;
|
||||
slot->reply_callback.timeout = calc_elapse(usec);
|
||||
|
||||
k = sd_netlink_send(nl, m, &s);
|
||||
if (k < 0)
|
||||
return k;
|
||||
|
||||
c->serial = s;
|
||||
slot->reply_callback.serial = s;
|
||||
|
||||
r = hashmap_put(nl->reply_callbacks, &c->serial, c);
|
||||
r = hashmap_put(nl->reply_callbacks, &slot->reply_callback.serial, &slot->reply_callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (c->timeout != 0) {
|
||||
r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
|
||||
if (slot->reply_callback.timeout != 0) {
|
||||
r = prioq_put(nl->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
|
||||
if (r < 0) {
|
||||
(void) hashmap_remove(nl->reply_callbacks, &c->serial);
|
||||
(void) hashmap_remove(nl->reply_callbacks, &slot->reply_callback.serial);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (serial)
|
||||
*serial = s;
|
||||
if (ret_slot)
|
||||
*ret_slot = slot;
|
||||
|
||||
TAKE_PTR(c);
|
||||
TAKE_PTR(slot);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
int sd_netlink_call_async_cancel(sd_netlink *nl, uint32_t serial) {
|
||||
struct reply_callback *c;
|
||||
uint64_t s = serial;
|
||||
|
||||
assert_return(nl, -EINVAL);
|
||||
assert_return(serial != 0, -EINVAL);
|
||||
assert_return(!rtnl_pid_changed(nl), -ECHILD);
|
||||
|
||||
c = hashmap_remove(nl->reply_callbacks, &s);
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
if (c->timeout != 0)
|
||||
prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
|
||||
|
||||
if (c->destroy_callback)
|
||||
c->destroy_callback(c->userdata);
|
||||
|
||||
free(c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sd_netlink_call(sd_netlink *rtnl,
|
||||
sd_netlink_message *message,
|
||||
uint64_t usec,
|
||||
@@ -834,26 +825,27 @@ int sd_netlink_detach_event(sd_netlink *rtnl) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_add_match(sd_netlink *rtnl,
|
||||
uint16_t type,
|
||||
sd_netlink_message_handler_t callback,
|
||||
void *userdata) {
|
||||
_cleanup_free_ struct match_callback *c = NULL;
|
||||
int sd_netlink_add_match(
|
||||
sd_netlink *rtnl,
|
||||
sd_netlink_slot **ret_slot,
|
||||
uint16_t type,
|
||||
sd_netlink_message_handler_t callback,
|
||||
sd_netlink_destroy_t destroy_callback,
|
||||
void *userdata,
|
||||
const char *description) {
|
||||
_cleanup_free_ sd_netlink_slot *slot = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(rtnl, -EINVAL);
|
||||
assert_return(callback, -EINVAL);
|
||||
assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
|
||||
|
||||
c = new(struct match_callback, 1);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
r = netlink_slot_allocate(rtnl, !ret_slot, NETLINK_MATCH_CALLBACK, sizeof(struct match_callback), destroy_callback, userdata, description, &slot);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*c = (struct match_callback) {
|
||||
.callback = callback,
|
||||
.type = type,
|
||||
.userdata = userdata,
|
||||
};
|
||||
slot->match_callback.callback = callback;
|
||||
slot->match_callback.type = type;
|
||||
|
||||
switch (type) {
|
||||
case RTM_NEWLINK:
|
||||
@@ -898,64 +890,12 @@ int sd_netlink_add_match(sd_netlink *rtnl,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
|
||||
LIST_PREPEND(match_callbacks, rtnl->match_callbacks, &slot->match_callback);
|
||||
|
||||
c = NULL;
|
||||
if (ret_slot)
|
||||
*ret_slot = slot;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_remove_match(sd_netlink *rtnl,
|
||||
uint16_t type,
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
TAKE_PTR(slot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -201,7 +201,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, NULL, ifname, 0, NULL) >= 0);
|
||||
assert_se(sd_netlink_call_async(rtnl, NULL, m, link_handler, NULL, ifname, 0, NULL) >= 0);
|
||||
|
||||
assert_se(sd_event_default(&event) >= 0);
|
||||
|
||||
@@ -214,10 +214,15 @@ static void test_event_loop(int ifindex) {
|
||||
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
|
||||
}
|
||||
|
||||
static void test_async_destroy(void *userdata) {
|
||||
}
|
||||
|
||||
static void test_async(int ifindex) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
|
||||
uint32_t serial;
|
||||
_cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL;
|
||||
sd_netlink_destroy_t destroy_callback;
|
||||
const char *description;
|
||||
char *ifname;
|
||||
|
||||
ifname = strdup("lo");
|
||||
@@ -227,7 +232,54 @@ 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, NULL, ifname, 0, &serial) >= 0);
|
||||
assert_se(sd_netlink_call_async(rtnl, &slot, m, link_handler, test_async_destroy, ifname, 0, "hogehoge") >= 0);
|
||||
|
||||
assert_se(sd_netlink_slot_get_netlink(slot) == rtnl);
|
||||
assert_se(sd_netlink_slot_get_userdata(slot) == ifname);
|
||||
assert_se(sd_netlink_slot_get_destroy_callback(slot, &destroy_callback) == 1);
|
||||
assert_se(destroy_callback == test_async_destroy);
|
||||
assert_se(sd_netlink_slot_get_floating(slot) == 0);
|
||||
assert_se(sd_netlink_slot_get_description(slot, &description) == 1);
|
||||
assert_se(streq(description, "hogehoge"));
|
||||
|
||||
assert_se(sd_netlink_wait(rtnl, 0) >= 0);
|
||||
assert_se(sd_netlink_process(rtnl, &r) >= 0);
|
||||
|
||||
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
|
||||
}
|
||||
|
||||
static void test_slot_set(int ifindex) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
|
||||
_cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL;
|
||||
sd_netlink_destroy_t destroy_callback;
|
||||
const char *description;
|
||||
char *ifname;
|
||||
|
||||
ifname = strdup("lo");
|
||||
assert_se(ifname);
|
||||
|
||||
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, &slot, m, link_handler, NULL, NULL, 0, NULL) >= 0);
|
||||
|
||||
assert_se(sd_netlink_slot_get_netlink(slot) == rtnl);
|
||||
assert_se(!sd_netlink_slot_get_userdata(slot));
|
||||
assert_se(!sd_netlink_slot_set_userdata(slot, ifname));
|
||||
assert_se(sd_netlink_slot_get_userdata(slot) == ifname);
|
||||
assert_se(sd_netlink_slot_get_destroy_callback(slot, NULL) == 0);
|
||||
assert_se(sd_netlink_slot_set_destroy_callback(slot, test_async_destroy) >= 0);
|
||||
assert_se(sd_netlink_slot_get_destroy_callback(slot, &destroy_callback) == 1);
|
||||
assert_se(destroy_callback == test_async_destroy);
|
||||
assert_se(sd_netlink_slot_get_floating(slot) == 0);
|
||||
assert_se(sd_netlink_slot_set_floating(slot, 1) == 1);
|
||||
assert_se(sd_netlink_slot_get_floating(slot) == 1);
|
||||
assert_se(sd_netlink_slot_get_description(slot, NULL) == 0);
|
||||
assert_se(sd_netlink_slot_set_description(slot, "hogehoge") >= 0);
|
||||
assert_se(sd_netlink_slot_get_description(slot, &description) == 1);
|
||||
assert_se(streq(description, "hogehoge"));
|
||||
|
||||
assert_se(sd_netlink_wait(rtnl, 0) >= 0);
|
||||
assert_se(sd_netlink_process(rtnl, &r) >= 0);
|
||||
@@ -279,7 +331,7 @@ static void test_async_destroy_callback(int ifindex) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
|
||||
_cleanup_(test_async_object_unrefp) struct test_async_object *t = NULL;
|
||||
uint32_t serial;
|
||||
_cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL;
|
||||
char *ifname;
|
||||
|
||||
assert_se(t = new(struct test_async_object, 1));
|
||||
@@ -293,7 +345,7 @@ static void test_async_destroy_callback(int ifindex) {
|
||||
|
||||
/* destroy callback is called after processing message */
|
||||
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
|
||||
assert_se(sd_netlink_call_async(rtnl, m, link_handler2, test_async_object_destroy, t, 0, &serial) >= 0);
|
||||
assert_se(sd_netlink_call_async(rtnl, NULL, m, link_handler2, test_async_object_destroy, t, 0, NULL) >= 0);
|
||||
|
||||
assert_se(t->n_ref == 1);
|
||||
assert_se(test_async_object_ref(t));
|
||||
@@ -305,22 +357,22 @@ static void test_async_destroy_callback(int ifindex) {
|
||||
|
||||
assert_se(!sd_netlink_message_unref(m));
|
||||
|
||||
/* destroy callback is called when asynchronous call is cancelled */
|
||||
/* destroy callback is called when asynchronous call is cancelled, that is, slot is freed. */
|
||||
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
|
||||
assert_se(sd_netlink_call_async(rtnl, m, link_handler2, test_async_object_destroy, t, 0, &serial) >= 0);
|
||||
assert_se(sd_netlink_call_async(rtnl, &slot, m, link_handler2, test_async_object_destroy, t, 0, NULL) >= 0);
|
||||
|
||||
assert_se(t->n_ref == 1);
|
||||
assert_se(test_async_object_ref(t));
|
||||
assert_se(t->n_ref == 2);
|
||||
|
||||
assert_se(sd_netlink_call_async_cancel(rtnl, serial) >= 0);
|
||||
assert_se(!(slot = sd_netlink_slot_unref(slot)));
|
||||
assert_se(t->n_ref == 1);
|
||||
|
||||
assert_se(!sd_netlink_message_unref(m));
|
||||
|
||||
/* destroy callback is also called by sd_netlink_unref() */
|
||||
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
|
||||
assert_se(sd_netlink_call_async(rtnl, m, link_handler2, test_async_object_destroy, t, 0, &serial) >= 0);
|
||||
assert_se(sd_netlink_call_async(rtnl, NULL, m, link_handler2, test_async_object_destroy, t, 0, NULL) >= 0);
|
||||
|
||||
assert_se(t->n_ref == 1);
|
||||
assert_se(test_async_object_ref(t));
|
||||
@@ -356,10 +408,10 @@ static void test_pipe(int ifindex) {
|
||||
assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
|
||||
|
||||
counter++;
|
||||
assert_se(sd_netlink_call_async(rtnl, m1, pipe_handler, NULL, &counter, 0, NULL) >= 0);
|
||||
assert_se(sd_netlink_call_async(rtnl, NULL, m1, pipe_handler, NULL, &counter, 0, NULL) >= 0);
|
||||
|
||||
counter++;
|
||||
assert_se(sd_netlink_call_async(rtnl, m2, pipe_handler, NULL, &counter, 0, NULL) >= 0);
|
||||
assert_se(sd_netlink_call_async(rtnl, NULL, m2, pipe_handler, NULL, &counter, 0, NULL) >= 0);
|
||||
|
||||
while (counter > 0) {
|
||||
assert_se(sd_netlink_wait(rtnl, 0) >= 0);
|
||||
@@ -405,16 +457,17 @@ static void test_container(sd_netlink *rtnl) {
|
||||
}
|
||||
|
||||
static void test_match(void) {
|
||||
_cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *s1 = NULL, *s2 = 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, &s1, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0);
|
||||
assert_se(sd_netlink_add_match(rtnl, &s2, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0);
|
||||
assert_se(sd_netlink_add_match(rtnl, NULL, RTM_NEWLINK, link_handler, NULL, NULL, 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(!(s1 = sd_netlink_slot_unref(s1)));
|
||||
assert_se(!(s2 = sd_netlink_slot_unref(s2)));
|
||||
|
||||
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
|
||||
}
|
||||
@@ -476,6 +529,7 @@ int main(void) {
|
||||
assert_se(if_loopback > 0);
|
||||
|
||||
test_async(if_loopback);
|
||||
test_slot_set(if_loopback);
|
||||
test_async_destroy_callback(if_loopback);
|
||||
test_pipe(if_loopback);
|
||||
test_event_loop(if_loopback);
|
||||
|
||||
Reference in New Issue
Block a user