diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-06-30 01:11:07 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-08-29 18:10:47 +0900 |
commit | 3f60e4488c5d52d01af07523cae6fa2f325014c9 (patch) | |
tree | b9fce20b3c0eedf2d817def7b76887e439fcc390 | |
parent | ef90beb1c5c4041db8c33e28cea236567d40d1fd (diff) | |
download | systemd-3f60e4488c5d52d01af07523cae6fa2f325014c9.tar.gz |
sd-netlink: split sd_netlink_add_match() into two parts
This also makes netlink_slot_disconnect() correctly unref multicast
groups.
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-internal.h | 13 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-slot.c | 24 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/sd-netlink.c | 121 |
3 files changed, 87 insertions, 71 deletions
diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 2594885fe6..9025286add 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -25,6 +25,8 @@ struct reply_callback { struct match_callback { sd_netlink_message_handler_t callback; + uint32_t *groups; + size_t n_groups; uint16_t type; LIST_FIELDS(struct match_callback, match_callbacks); @@ -151,6 +153,17 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m); int socket_writev_message(sd_netlink *nl, sd_netlink_message **m, size_t msgcount); int socket_read_message(sd_netlink *nl); +int netlink_add_match_internal( + sd_netlink *nl, + sd_netlink_slot **ret_slot, + const uint32_t *groups, + size_t n_groups, + uint16_t type, + sd_netlink_message_handler_t callback, + sd_netlink_destroy_t destroy_callback, + void *userdata, + const char *description); + /* Make sure callbacks don't destroy the netlink connection */ #define NETLINK_DONT_DESTROY(nl) \ _cleanup_(sd_netlink_unrefp) _unused_ sd_netlink *_dont_destroy_##nl = sd_netlink_ref(nl) diff --git a/src/libsystemd/sd-netlink/netlink-slot.c b/src/libsystemd/sd-netlink/netlink-slot.c index 76b4ccaa96..34f527d07f 100644 --- a/src/libsystemd/sd-netlink/netlink-slot.c +++ b/src/libsystemd/sd-netlink/netlink-slot.c @@ -70,25 +70,11 @@ void netlink_slot_disconnect(sd_netlink_slot *slot, bool unref) { 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; - } + for (size_t i = 0; i < slot->match_callback.n_groups; i++) + (void) socket_broadcast_group_unref(nl, slot->match_callback.groups[i]); + + slot->match_callback.n_groups = 0; + slot->match_callback.groups = mfree(slot->match_callback.groups); break; default: diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 2305333575..8ea3b2f1a0 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -895,9 +895,11 @@ int sd_netlink_detach_event(sd_netlink *nl) { return 0; } -int sd_netlink_add_match( - sd_netlink *rtnl, +int netlink_add_match_internal( + sd_netlink *nl, sd_netlink_slot **ret_slot, + const uint32_t *groups, + size_t n_groups, uint16_t type, sd_netlink_message_handler_t callback, sd_netlink_destroy_t destroy_callback, @@ -907,83 +909,98 @@ int sd_netlink_add_match( _cleanup_free_ sd_netlink_slot *slot = NULL; int r; - assert_return(rtnl, -EINVAL); - assert_return(callback, -EINVAL); - assert_return(!netlink_pid_changed(rtnl), -ECHILD); + assert(groups); + assert(n_groups > 0); + + for (size_t i = 0; i < n_groups; i++) { + r = socket_broadcast_group_ref(nl, groups[i]); + if (r < 0) + return r; + } - r = netlink_slot_allocate(rtnl, !ret_slot, NETLINK_MATCH_CALLBACK, sizeof(struct match_callback), userdata, description, &slot); + r = netlink_slot_allocate(nl, !ret_slot, NETLINK_MATCH_CALLBACK, sizeof(struct match_callback), + userdata, description, &slot); if (r < 0) return r; + slot->match_callback.groups = newdup(uint32_t, groups, n_groups); + if (!slot->match_callback.groups) + return -ENOMEM; + + slot->match_callback.n_groups = n_groups; slot->match_callback.callback = callback; slot->match_callback.type = type; + LIST_PREPEND(match_callbacks, nl->match_callbacks, &slot->match_callback); + + /* Set this at last. Otherwise, some failures in above call the destroy callback but some do not. */ + slot->destroy_callback = destroy_callback; + + if (ret_slot) + *ret_slot = slot; + + TAKE_PTR(slot); + return 0; +} + +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) { + + static const uint32_t + address_groups[] = { RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, }, + link_groups[] = { RTNLGRP_LINK, }, + neighbor_groups[] = { RTNLGRP_NEIGH, }, + nexthop_groups[] = { RTNLGRP_NEXTHOP, }, + route_groups[] = { RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, }, + rule_groups[] = { RTNLGRP_IPV4_RULE, RTNLGRP_IPV6_RULE, }; + const uint32_t *groups; + size_t n_groups; + + assert_return(rtnl, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!netlink_pid_changed(rtnl), -ECHILD); + switch (type) { case RTM_NEWLINK: case RTM_DELLINK: - r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK); - if (r < 0) - return r; - + groups = link_groups; + n_groups = ELEMENTSOF(link_groups); break; case RTM_NEWADDR: case RTM_DELADDR: - 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; - + groups = address_groups; + n_groups = ELEMENTSOF(address_groups); break; case RTM_NEWNEIGH: case RTM_DELNEIGH: - r = socket_broadcast_group_ref(rtnl, RTNLGRP_NEIGH); - if (r < 0) - return r; - + groups = neighbor_groups; + n_groups = ELEMENTSOF(neighbor_groups); 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; + groups = route_groups; + n_groups = ELEMENTSOF(route_groups); break; case RTM_NEWRULE: case RTM_DELRULE: - r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_RULE); - if (r < 0) - return r; - - r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_RULE); - if (r < 0) - return r; + groups = rule_groups; + n_groups = ELEMENTSOF(rule_groups); break; case RTM_NEWNEXTHOP: case RTM_DELNEXTHOP: - r = socket_broadcast_group_ref(rtnl, RTNLGRP_NEXTHOP); - if (r < 0) - return r; - break; - + groups = nexthop_groups; + n_groups = ELEMENTSOF(nexthop_groups); + break; default: return -EOPNOTSUPP; } - LIST_PREPEND(match_callbacks, rtnl->match_callbacks, &slot->match_callback); - - /* Set this at last. Otherwise, some failures in above call the destroy callback but some do not. */ - slot->destroy_callback = destroy_callback; - - if (ret_slot) - *ret_slot = slot; - - TAKE_PTR(slot); - - return 0; + return netlink_add_match_internal(rtnl, ret_slot, groups, n_groups, type, callback, + destroy_callback, userdata, description); } |