diff options
Diffstat (limited to 'src/libsystemd/sd-netlink')
l--------- | src/libsystemd/sd-netlink/Makefile | 1 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/local-addresses.c | 276 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/local-addresses.h | 37 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-types.h | 94 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-util.c | 173 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-util.h | 47 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/sd-netlink.c | 1060 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/test-local-addresses.c | 58 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/test-netlink.c | 443 |
9 files changed, 0 insertions, 2189 deletions
diff --git a/src/libsystemd/sd-netlink/Makefile b/src/libsystemd/sd-netlink/Makefile deleted file mode 120000 index 94aaae2c4..000000000 --- a/src/libsystemd/sd-netlink/Makefile +++ /dev/null @@ -1 +0,0 @@ -../../Makefile
\ No newline at end of file diff --git a/src/libsystemd/sd-netlink/local-addresses.c b/src/libsystemd/sd-netlink/local-addresses.c deleted file mode 100644 index e2f637f7f..000000000 --- a/src/libsystemd/sd-netlink/local-addresses.c +++ /dev/null @@ -1,276 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2008-2011 Lennart Poettering - Copyright 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include "sd-netlink.h" -#include "netlink-util.h" -#include "macro.h" -#include "local-addresses.h" - -static int address_compare(const void *_a, const void *_b) { - const struct local_address *a = _a, *b = _b; - - /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */ - - if (a->family == AF_INET && b->family == AF_INET6) - return -1; - if (a->family == AF_INET6 && b->family == AF_INET) - return 1; - - if (a->scope < b->scope) - return -1; - if (a->scope > b->scope) - return 1; - - if (a->metric < b->metric) - return -1; - if (a->metric > b->metric) - return 1; - - if (a->ifindex < b->ifindex) - return -1; - if (a->ifindex > b->ifindex) - return 1; - - return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family)); -} - -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_free_ struct local_address *list = NULL; - size_t n_list = 0, n_allocated = 0; - sd_netlink_message *m; - int r; - - assert(ret); - - if (context) - rtnl = sd_netlink_ref(context); - else { - r = sd_netlink_open(&rtnl); - if (r < 0) - return r; - } - - r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, af); - if (r < 0) - return r; - - r = sd_netlink_call(rtnl, req, 0, &reply); - if (r < 0) - return r; - - for (m = reply; m; m = sd_netlink_message_next(m)) { - struct local_address *a; - unsigned char flags; - uint16_t type; - int ifi, family; - - r = sd_netlink_message_get_errno(m); - if (r < 0) - return r; - - r = sd_netlink_message_get_type(m, &type); - if (r < 0) - return r; - if (type != RTM_NEWADDR) - continue; - - r = sd_rtnl_message_addr_get_ifindex(m, &ifi); - if (r < 0) - return r; - if (ifindex > 0 && ifi != ifindex) - continue; - - r = sd_rtnl_message_addr_get_family(m, &family); - if (r < 0) - return r; - if (af != AF_UNSPEC && af != family) - continue; - - r = sd_rtnl_message_addr_get_flags(m, &flags); - if (r < 0) - return r; - if (flags & IFA_F_DEPRECATED) - continue; - - if (!GREEDY_REALLOC0(list, n_allocated, n_list+1)) - return -ENOMEM; - - a = list + n_list; - - r = sd_rtnl_message_addr_get_scope(m, &a->scope); - if (r < 0) - return r; - - if (ifindex == 0 && (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE)) - continue; - - switch (family) { - - case AF_INET: - r = sd_netlink_message_read_in_addr(m, IFA_LOCAL, &a->address.in); - if (r < 0) { - r = sd_netlink_message_read_in_addr(m, IFA_ADDRESS, &a->address.in); - if (r < 0) - continue; - } - break; - - case AF_INET6: - r = sd_netlink_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6); - if (r < 0) { - r = sd_netlink_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6); - if (r < 0) - continue; - } - break; - - default: - continue; - } - - a->ifindex = ifi; - a->family = family; - - n_list++; - }; - - if (n_list > 0) - qsort(list, n_list, sizeof(struct local_address), address_compare); - - *ret = list; - list = NULL; - - return (int) n_list; -} - -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_free_ struct local_address *list = NULL; - sd_netlink_message *m = NULL; - size_t n_list = 0, n_allocated = 0; - int r; - - assert(ret); - - if (context) - rtnl = sd_netlink_ref(context); - else { - r = sd_netlink_open(&rtnl); - if (r < 0) - return r; - } - - r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC); - if (r < 0) - return r; - - r = sd_netlink_message_request_dump(req, true); - if (r < 0) - return r; - - r = sd_netlink_call(rtnl, req, 0, &reply); - if (r < 0) - return r; - - for (m = reply; m; m = sd_netlink_message_next(m)) { - struct local_address *a; - uint16_t type; - unsigned char dst_len, src_len; - uint32_t ifi; - int family; - - r = sd_netlink_message_get_errno(m); - if (r < 0) - return r; - - r = sd_netlink_message_get_type(m, &type); - if (r < 0) - return r; - if (type != RTM_NEWROUTE) - continue; - - /* We only care for default routes */ - r = sd_rtnl_message_route_get_dst_prefixlen(m, &dst_len); - if (r < 0) - return r; - if (dst_len != 0) - continue; - - r = sd_rtnl_message_route_get_src_prefixlen(m, &src_len); - if (r < 0) - return r; - if (src_len != 0) - continue; - - r = sd_netlink_message_read_u32(m, RTA_OIF, &ifi); - if (r < 0) - return r; - if (ifindex > 0 && (int) ifi != ifindex) - continue; - - r = sd_rtnl_message_route_get_family(m, &family); - if (r < 0) - return r; - if (af != AF_UNSPEC && af != family) - continue; - - if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1)) - return -ENOMEM; - - a = list + n_list; - - switch (family) { - case AF_INET: - r = sd_netlink_message_read_in_addr(m, RTA_GATEWAY, &a->address.in); - if (r < 0) - continue; - - break; - case AF_INET6: - r = sd_netlink_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6); - if (r < 0) - continue; - - break; - default: - continue; - } - - sd_netlink_message_read_u32(m, RTA_PRIORITY, &a->metric); - - a->ifindex = ifi; - a->family = family; - - n_list++; - } - - if (n_list > 0) - qsort(list, n_list, sizeof(struct local_address), address_compare); - - *ret = list; - list = NULL; - - return (int) n_list; -} diff --git a/src/libsystemd/sd-netlink/local-addresses.h b/src/libsystemd/sd-netlink/local-addresses.h deleted file mode 100644 index 5d0f11a2c..000000000 --- a/src/libsystemd/sd-netlink/local-addresses.h +++ /dev/null @@ -1,37 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2008-2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - - -#include "sd-netlink.h" -#include "in-addr-util.h" - -struct local_address { - int family, ifindex; - unsigned char scope; - uint32_t metric; - union in_addr_union address; -}; - -int local_addresses(sd_netlink *rtnl, int ifindex, int af, struct local_address **ret); - -int local_gateways(sd_netlink *rtnl, int ifindex, int af, struct local_address **ret); diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h deleted file mode 100644 index bf7c64154..000000000 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ /dev/null @@ -1,94 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen <teg@jklm.no> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -enum { - NETLINK_TYPE_UNSPEC, - NETLINK_TYPE_U8, /* NLA_U8 */ - NETLINK_TYPE_U16, /* NLA_U16 */ - 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, - NETLINK_TYPE_NESTED, /* NLA_NESTED */ - NETLINK_TYPE_UNION, -}; - -typedef enum NLMatchType { - NL_MATCH_SIBLING, - NL_MATCH_PROTOCOL, -} NLMatchType; - -typedef struct NLTypeSystemUnion NLTypeSystemUnion; -typedef struct NLTypeSystem NLTypeSystem; -typedef struct NLType NLType; - -struct NLTypeSystemUnion { - int num; - NLMatchType match_type; - uint16_t match; - int (*lookup)(const char *); - const NLTypeSystem *type_systems; -}; - -extern const NLTypeSystem type_system_root; - -uint16_t type_get_type(const NLType *type); -size_t type_get_size(const NLType *type); -void type_get_type_system(const NLType *type, const NLTypeSystem **ret); -void type_get_type_system_union(const NLType *type, const NLTypeSystemUnion **ret); - -uint16_t type_system_get_count(const NLTypeSystem *type_system); -int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type); -int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type); -int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type); -int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key); -int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol); - -typedef enum NLUnionLinkInfoData { - NL_UNION_LINK_INFO_DATA_BOND, - NL_UNION_LINK_INFO_DATA_BRIDGE, - NL_UNION_LINK_INFO_DATA_VLAN, - 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, - NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL, - NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL, - NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL, - NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL, - NL_UNION_LINK_INFO_DATA_SIT_TUNNEL, - 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_MAX, - _NL_UNION_LINK_INFO_DATA_INVALID = -1 -} NLUnionLinkInfoData; - -const char *nl_union_link_info_data_to_string(NLUnionLinkInfoData p) _const_; -NLUnionLinkInfoData nl_union_link_info_data_from_string(const char *p) _pure_; diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c deleted file mode 100644 index 482ff6b1c..000000000 --- a/src/libsystemd/sd-netlink/netlink-util.c +++ /dev/null @@ -1,173 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2013 Tom Gundersen <teg@jklm.no> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - - -#include "sd-netlink.h" - -#include "netlink-util.h" -#include "netlink-internal.h" - -int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) { - _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL; - int r; - - assert(rtnl); - assert(ifindex > 0); - assert(name); - - if (!*rtnl) { - r = sd_netlink_open(rtnl); - if (r < 0) - return r; - } - - r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex); - if (r < 0) - return r; - - r = sd_netlink_message_append_string(message, IFLA_IFNAME, name); - if (r < 0) - return r; - - r = sd_netlink_call(*rtnl, message, 0, NULL); - if (r < 0) - return r; - - return 0; -} - -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; - int r; - - assert(rtnl); - assert(ifindex > 0); - - if (!alias && !mac && mtu == 0) - return 0; - - if (!*rtnl) { - r = sd_netlink_open(rtnl); - if (r < 0) - return r; - } - - r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex); - if (r < 0) - return r; - - if (alias) { - r = sd_netlink_message_append_string(message, IFLA_IFALIAS, alias); - if (r < 0) - return r; - } - - if (mac) { - r = sd_netlink_message_append_ether_addr(message, IFLA_ADDRESS, mac); - if (r < 0) - return r; - } - - if (mtu > 0) { - r = sd_netlink_message_append_u32(message, IFLA_MTU, mtu); - if (r < 0) - return r; - } - - r = sd_netlink_call(*rtnl, message, 0, NULL); - if (r < 0) - return r; - - return 0; -} - -int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret) { - struct nlmsgerr *err; - int r; - - assert(error <= 0); - - r = message_new(NULL, ret, NLMSG_ERROR); - if (r < 0) - return r; - - (*ret)->hdr->nlmsg_seq = serial; - - err = NLMSG_DATA((*ret)->hdr); - - err->error = error; - - return 0; -} - -bool rtnl_message_type_is_neigh(uint16_t type) { - switch (type) { - case RTM_NEWNEIGH: - case RTM_GETNEIGH: - case RTM_DELNEIGH: - return true; - default: - return false; - } -} - -bool rtnl_message_type_is_route(uint16_t type) { - switch (type) { - case RTM_NEWROUTE: - case RTM_GETROUTE: - case RTM_DELROUTE: - return true; - default: - return false; - } -} - -bool rtnl_message_type_is_link(uint16_t type) { - switch (type) { - case RTM_NEWLINK: - case RTM_SETLINK: - case RTM_GETLINK: - case RTM_DELLINK: - return true; - default: - return false; - } -} - -bool rtnl_message_type_is_addr(uint16_t type) { - switch (type) { - case RTM_NEWADDR: - case RTM_GETADDR: - case RTM_DELADDR: - return true; - default: - return false; - } -} - -int rtnl_log_parse_error(int r) { - return log_error_errno(r, "Failed to parse netlink message: %m"); -} - -int rtnl_log_create_error(int r) { - return log_error_errno(r, "Failed to create netlink message: %m"); -} diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h deleted file mode 100644 index 9df0aa28b..000000000 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ /dev/null @@ -1,47 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2013 Tom Gundersen <teg@jklm.no> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - - -#include "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); -void rtnl_message_seal(sd_netlink_message *m); - -bool rtnl_message_type_is_link(uint16_t type); -bool rtnl_message_type_is_addr(uint16_t type); -bool rtnl_message_type_is_route(uint16_t type); -bool rtnl_message_type_is_neigh(uint16_t type); - -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); - -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/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c deleted file mode 100644 index 60ce4dfc4..000000000 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ /dev/null @@ -1,1060 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2013 Tom Gundersen <teg@jklm.no> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <sys/socket.h> -#include <poll.h> - -#include "missing.h" -#include "macro.h" -#include "util.h" -#include "hashmap.h" - -#include "sd-netlink.h" -#include "netlink-internal.h" -#include "netlink-util.h" - -static int sd_netlink_new(sd_netlink **ret) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - - assert_return(ret, -EINVAL); - - rtnl = new0(sd_netlink, 1); - if (!rtnl) - 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); - - /* We guarantee that wqueue always has space for at least - * one entry */ - if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1)) - return -ENOMEM; - - /* We guarantee that the read buffer has at least space for - * a message header */ - if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated, - sizeof(struct nlmsghdr), sizeof(uint8_t))) - return -ENOMEM; - - /* Change notification responses have sequence 0, so we must - * start our request sequence numbers at 1, or we may confuse our - * responses with notifications from the kernel */ - rtnl->serial = 1; - - *ret = rtnl; - rtnl = NULL; - - return 0; -} - -int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - socklen_t addrlen; - int r; - - assert_return(ret, -EINVAL); - - r = sd_netlink_new(&rtnl); - if (r < 0) - return r; - - addrlen = sizeof(rtnl->sockaddr); - - r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen); - if (r < 0) - return -errno; - - rtnl->fd = fd; - - *ret = rtnl; - rtnl = NULL; - - return 0; -} - -static bool rtnl_pid_changed(sd_netlink *rtnl) { - assert(rtnl); - - /* We don't support people creating an rtnl connection and - * keeping it around over a fork(). Let's complain. */ - - return rtnl->original_pid != getpid(); -} - -int sd_netlink_open_fd(sd_netlink **ret, int fd) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - socklen_t addrlen; - int r, one = 1; - - assert_return(ret, -EINVAL); - assert_return(fd >= 0, -EINVAL); - - r = sd_netlink_new(&rtnl); - if (r < 0) - return r; - - r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); - if (r < 0) - return -errno; - - r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one)); - if (r < 0) - return -errno; - - addrlen = sizeof(rtnl->sockaddr); - - r = bind(fd, &rtnl->sockaddr.sa, addrlen); - /* ignore EINVAL to allow opening an already bound socket */ - if (r < 0 && errno != EINVAL) - return -errno; - - r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen); - if (r < 0) - return -errno; - - rtnl->fd = fd; - - *ret = rtnl; - rtnl = NULL; - - return 0; -} - -int sd_netlink_open(sd_netlink **ret) { - _cleanup_close_ int fd = -1; - int r; - - fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE); - if (fd < 0) - return -errno; - - r = sd_netlink_open_fd(ret, fd); - if (r < 0) - return r; - - fd = -1; - - return 0; -} - -static int rtnl_join_broadcast_group(sd_netlink *rtnl, unsigned group) { - int r; - - assert(rtnl); - assert(rtnl->fd >= 0); - assert(group > 0); - - r = setsockopt(rtnl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)); - if (r < 0) - return -errno; - - return 0; -} - -int sd_netlink_inc_rcvbuf(const sd_netlink *const rtnl, const int size) { - return fd_inc_rcvbuf(rtnl->fd, size); -} - -sd_netlink *sd_netlink_ref(sd_netlink *rtnl) { - assert_return(rtnl, NULL); - assert_return(!rtnl_pid_changed(rtnl), NULL); - - if (rtnl) - assert_se(REFCNT_INC(rtnl->n_ref) >= 2); - - return rtnl; -} - -sd_netlink *sd_netlink_unref(sd_netlink *rtnl) { - if (!rtnl) - return NULL; - - assert_return(!rtnl_pid_changed(rtnl), NULL); - - if (REFCNT_DEC(rtnl->n_ref) == 0) { - struct match_callback *f; - unsigned i; - - for (i = 0; i < rtnl->rqueue_size; i++) - sd_netlink_message_unref(rtnl->rqueue[i]); - free(rtnl->rqueue); - - for (i = 0; i < rtnl->rqueue_partial_size; i++) - sd_netlink_message_unref(rtnl->rqueue_partial[i]); - free(rtnl->rqueue_partial); - - for (i = 0; i < rtnl->wqueue_size; i++) - sd_netlink_message_unref(rtnl->wqueue[i]); - free(rtnl->wqueue); - - free(rtnl->rbuffer); - - hashmap_free_free(rtnl->reply_callbacks); - prioq_free(rtnl->reply_callbacks_prioq); - - sd_event_source_unref(rtnl->io_event_source); - sd_event_source_unref(rtnl->time_event_source); - sd_event_source_unref(rtnl->exit_event_source); - sd_event_unref(rtnl->event); - - while ((f = rtnl->match_callbacks)) { - LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f); - free(f); - } - - safe_close(rtnl->fd); - free(rtnl); - } - - return NULL; -} - -static void rtnl_seal_message(sd_netlink *rtnl, sd_netlink_message *m) { - assert(rtnl); - assert(!rtnl_pid_changed(rtnl)); - assert(m); - assert(m->hdr); - - /* don't use seq == 0, as that is used for broadcasts, so we - would get confused by replies to such messages */ - m->hdr->nlmsg_seq = rtnl->serial++ ? : rtnl->serial++; - - rtnl_message_seal(m); - - return; -} - -int sd_netlink_send(sd_netlink *nl, - sd_netlink_message *message, - uint32_t *serial) { - int r; - - assert_return(nl, -EINVAL); - assert_return(!rtnl_pid_changed(nl), -ECHILD); - assert_return(message, -EINVAL); - assert_return(!message->sealed, -EPERM); - - rtnl_seal_message(nl, message); - - if (nl->wqueue_size <= 0) { - /* send directly */ - r = socket_write_message(nl, message); - if (r < 0) - return r; - else if (r == 0) { - /* nothing was sent, so let's put it on - * the queue */ - nl->wqueue[0] = sd_netlink_message_ref(message); - nl->wqueue_size = 1; - } - } else { - /* append to queue */ - if (nl->wqueue_size >= RTNL_WQUEUE_MAX) { - log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX); - return -ENOBUFS; - } - - if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1)) - return -ENOMEM; - - nl->wqueue[nl->wqueue_size ++] = sd_netlink_message_ref(message); - } - - if (serial) - *serial = rtnl_message_get_serial(message); - - return 1; -} - -int rtnl_rqueue_make_room(sd_netlink *rtnl) { - assert(rtnl); - - if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) { - log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX); - return -ENOBUFS; - } - - if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1)) - return -ENOMEM; - - return 0; -} - -int rtnl_rqueue_partial_make_room(sd_netlink *rtnl) { - assert(rtnl); - - if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) { - log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX); - return -ENOBUFS; - } - - if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated, - rtnl->rqueue_partial_size + 1)) - return -ENOMEM; - - return 0; -} - -static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) { - int r; - - assert(rtnl); - assert(message); - - if (rtnl->rqueue_size <= 0) { - /* Try to read a new message */ - r = socket_read_message(rtnl); - if (r <= 0) - return r; - } - - /* Dispatch a queued message */ - *message = rtnl->rqueue[0]; - rtnl->rqueue_size --; - memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_netlink_message*) * rtnl->rqueue_size); - - return 1; -} - -static int dispatch_wqueue(sd_netlink *rtnl) { - int r, ret = 0; - - assert(rtnl); - - while (rtnl->wqueue_size > 0) { - r = socket_write_message(rtnl, rtnl->wqueue[0]); - if (r < 0) - return r; - else if (r == 0) - /* Didn't do anything this time */ - return ret; - else { - /* see equivalent in sd-bus.c */ - sd_netlink_message_unref(rtnl->wqueue[0]); - rtnl->wqueue_size --; - memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_netlink_message*) * rtnl->wqueue_size); - - ret = 1; - } - } - - return ret; -} - -static int process_timeout(sd_netlink *rtnl) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; - struct reply_callback *c; - usec_t n; - int r; - - assert(rtnl); - - c = prioq_peek(rtnl->reply_callbacks_prioq); - if (!c) - return 0; - - n = now(CLOCK_MONOTONIC); - if (c->timeout > n) - return 0; - - r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m); - if (r < 0) - return r; - - assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c); - hashmap_remove(rtnl->reply_callbacks, &c->serial); - - r = c->callback(rtnl, m, c->userdata); - if (r < 0) - log_debug_errno(r, "sd-netlink: timedout callback failed: %m"); - - free(c); - - return 1; -} - -static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) { - _cleanup_free_ struct reply_callback *c = NULL; - uint64_t serial; - uint16_t type; - int r; - - assert(rtnl); - assert(m); - - serial = rtnl_message_get_serial(m); - c = hashmap_remove(rtnl->reply_callbacks, &serial); - if (!c) - return 0; - - if (c->timeout != 0) - prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx); - - r = sd_netlink_message_get_type(m, &type); - if (r < 0) - return 0; - - 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"); - - return 1; -} - -static int process_match(sd_netlink *rtnl, sd_netlink_message *m) { - struct match_callback *c; - uint16_t type; - int r; - - assert(rtnl); - assert(m); - - r = sd_netlink_message_get_type(m, &type); - if (r < 0) - return r; - - LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) { - if (type == c->type) { - r = c->callback(rtnl, m, c->userdata); - if (r != 0) { - if (r < 0) - log_debug_errno(r, "sd-netlink: match callback failed: %m"); - - break; - } - } - } - - return 1; -} - -static int process_running(sd_netlink *rtnl, sd_netlink_message **ret) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; - int r; - - assert(rtnl); - - r = process_timeout(rtnl); - if (r != 0) - goto null_message; - - r = dispatch_wqueue(rtnl); - if (r != 0) - goto null_message; - - r = dispatch_rqueue(rtnl, &m); - if (r < 0) - return r; - if (!m) - goto null_message; - - if (sd_netlink_message_is_broadcast(m)) { - r = process_match(rtnl, m); - if (r != 0) - goto null_message; - } else { - r = process_reply(rtnl, m); - if (r != 0) - goto null_message; - } - - if (ret) { - *ret = m; - m = NULL; - - return 1; - } - - return 1; - -null_message: - if (r >= 0 && ret) - *ret = NULL; - - return r; -} - -int sd_netlink_process(sd_netlink *rtnl, sd_netlink_message **ret) { - RTNL_DONT_DESTROY(rtnl); - int r; - - assert_return(rtnl, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); - assert_return(!rtnl->processing, -EBUSY); - - rtnl->processing = true; - r = process_running(rtnl, ret); - rtnl->processing = false; - - return r; -} - -static usec_t calc_elapse(uint64_t usec) { - if (usec == (uint64_t) -1) - return 0; - - if (usec == 0) - usec = RTNL_DEFAULT_TIMEOUT; - - return now(CLOCK_MONOTONIC) + usec; -} - -static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) { - struct pollfd p[1] = {}; - struct timespec ts; - usec_t m = USEC_INFINITY; - int r, e; - - assert(rtnl); - - e = sd_netlink_get_events(rtnl); - if (e < 0) - return e; - - if (need_more) - /* Caller wants more data, and doesn't care about - * what's been read or any other timeouts. */ - e |= POLLIN; - else { - usec_t until; - /* Caller wants to process if there is something to - * process, but doesn't care otherwise */ - - r = sd_netlink_get_timeout(rtnl, &until); - if (r < 0) - return r; - if (r > 0) { - usec_t nw; - nw = now(CLOCK_MONOTONIC); - m = until > nw ? until - nw : 0; - } - } - - if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m)) - m = timeout_usec; - - p[0].fd = rtnl->fd; - p[0].events = e; - - r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL); - if (r < 0) - return -errno; - - return r > 0 ? 1 : 0; -} - -int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) { - assert_return(nl, -EINVAL); - assert_return(!rtnl_pid_changed(nl), -ECHILD); - - if (nl->rqueue_size > 0) - return 0; - - return rtnl_poll(nl, false, timeout_usec); -} - -static int timeout_compare(const void *a, const void *b) { - const struct reply_callback *x = a, *y = b; - - if (x->timeout != 0 && y->timeout == 0) - return -1; - - if (x->timeout == 0 && y->timeout != 0) - return 1; - - if (x->timeout < y->timeout) - return -1; - - if (x->timeout > y->timeout) - return 1; - - return 0; -} - -int sd_netlink_call_async(sd_netlink *nl, - sd_netlink_message *m, - sd_netlink_message_handler_t callback, - void *userdata, - uint64_t usec, - uint32_t *serial) { - struct reply_callback *c; - uint32_t s; - int r, k; - - assert_return(nl, -EINVAL); - assert_return(m, -EINVAL); - assert_return(callback, -EINVAL); - assert_return(!rtnl_pid_changed(nl), -ECHILD); - - r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops); - if (r < 0) - return r; - - if (usec != (uint64_t) -1) { - r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare); - if (r < 0) - return r; - } - - c = new0(struct reply_callback, 1); - if (!c) - return -ENOMEM; - - c->callback = callback; - c->userdata = userdata; - c->timeout = calc_elapse(usec); - - k = sd_netlink_send(nl, m, &s); - if (k < 0) { - free(c); - return k; - } - - c->serial = s; - - r = hashmap_put(nl->reply_callbacks, &c->serial, c); - if (r < 0) { - free(c); - return r; - } - - if (c->timeout != 0) { - r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx); - if (r > 0) { - c->timeout = 0; - sd_netlink_call_async_cancel(nl, c->serial); - return r; - } - } - - if (serial) - *serial = s; - - 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); - - free(c); - return 1; -} - -int sd_netlink_call(sd_netlink *rtnl, - sd_netlink_message *message, - uint64_t usec, - sd_netlink_message **ret) { - usec_t timeout; - uint32_t serial; - int r; - - assert_return(rtnl, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); - assert_return(message, -EINVAL); - - r = sd_netlink_send(rtnl, message, &serial); - if (r < 0) - return r; - - timeout = calc_elapse(usec); - - for (;;) { - usec_t left; - unsigned i; - - for (i = 0; i < rtnl->rqueue_size; i++) { - uint32_t received_serial; - - received_serial = rtnl_message_get_serial(rtnl->rqueue[i]); - - if (received_serial == serial) { - _cleanup_netlink_message_unref_ sd_netlink_message *incoming = NULL; - uint16_t type; - - incoming = rtnl->rqueue[i]; - - /* found a match, remove from rqueue and return it */ - memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1, - sizeof(sd_netlink_message*) * (rtnl->rqueue_size - i - 1)); - rtnl->rqueue_size--; - - r = sd_netlink_message_get_errno(incoming); - if (r < 0) - return r; - - r = sd_netlink_message_get_type(incoming, &type); - if (r < 0) - return r; - - if (type == NLMSG_DONE) { - *ret = NULL; - return 0; - } - - if (ret) { - *ret = incoming; - incoming = NULL; - } - - return 1; - } - } - - r = socket_read_message(rtnl); - if (r < 0) - return r; - if (r > 0) - /* received message, so try to process straight away */ - continue; - - if (timeout > 0) { - usec_t n; - - n = now(CLOCK_MONOTONIC); - if (n >= timeout) - return -ETIMEDOUT; - - left = timeout - n; - } else - left = (uint64_t) -1; - - r = rtnl_poll(rtnl, true, left); - if (r < 0) - return r; - else if (r == 0) - return -ETIMEDOUT; - - r = dispatch_wqueue(rtnl); - if (r < 0) - return r; - } -} - -int sd_netlink_flush(sd_netlink *rtnl) { - int r; - - assert_return(rtnl, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); - - if (rtnl->wqueue_size <= 0) - return 0; - - for (;;) { - r = dispatch_wqueue(rtnl); - if (r < 0) - return r; - - if (rtnl->wqueue_size <= 0) - return 0; - - r = rtnl_poll(rtnl, false, (uint64_t) -1); - if (r < 0) - return r; - } -} - -int sd_netlink_get_events(sd_netlink *rtnl) { - int flags = 0; - - assert_return(rtnl, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); - - if (rtnl->rqueue_size <= 0) - flags |= POLLIN; - if (rtnl->wqueue_size > 0) - flags |= POLLOUT; - - return flags; -} - -int sd_netlink_get_timeout(sd_netlink *rtnl, uint64_t *timeout_usec) { - struct reply_callback *c; - - assert_return(rtnl, -EINVAL); - assert_return(timeout_usec, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); - - if (rtnl->rqueue_size > 0) { - *timeout_usec = 0; - return 1; - } - - c = prioq_peek(rtnl->reply_callbacks_prioq); - if (!c) { - *timeout_usec = (uint64_t) -1; - return 0; - } - - *timeout_usec = c->timeout; - - return 1; -} - -static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - sd_netlink *rtnl = userdata; - int r; - - assert(rtnl); - - r = sd_netlink_process(rtnl, NULL); - if (r < 0) - return r; - - return 1; -} - -static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) { - sd_netlink *rtnl = userdata; - int r; - - assert(rtnl); - - r = sd_netlink_process(rtnl, NULL); - if (r < 0) - return r; - - return 1; -} - -static int prepare_callback(sd_event_source *s, void *userdata) { - sd_netlink *rtnl = userdata; - int r, e; - usec_t until; - - assert(s); - assert(rtnl); - - e = sd_netlink_get_events(rtnl); - if (e < 0) - return e; - - r = sd_event_source_set_io_events(rtnl->io_event_source, e); - if (r < 0) - return r; - - r = sd_netlink_get_timeout(rtnl, &until); - if (r < 0) - return r; - if (r > 0) { - int j; - - j = sd_event_source_set_time(rtnl->time_event_source, until); - if (j < 0) - return j; - } - - r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0); - if (r < 0) - return r; - - return 1; -} - -static int exit_callback(sd_event_source *event, void *userdata) { - sd_netlink *rtnl = userdata; - - assert(event); - - sd_netlink_flush(rtnl); - - return 1; -} - -int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int priority) { - int r; - - assert_return(rtnl, -EINVAL); - assert_return(!rtnl->event, -EBUSY); - - assert(!rtnl->io_event_source); - assert(!rtnl->time_event_source); - - if (event) - rtnl->event = sd_event_ref(event); - else { - r = sd_event_default(&rtnl->event); - if (r < 0) - return r; - } - - r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl); - if (r < 0) - goto fail; - - r = sd_event_source_set_priority(rtnl->io_event_source, priority); - if (r < 0) - goto fail; - - r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message"); - if (r < 0) - goto fail; - - r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback); - if (r < 0) - goto fail; - - r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl); - if (r < 0) - goto fail; - - r = sd_event_source_set_priority(rtnl->time_event_source, priority); - if (r < 0) - goto fail; - - r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer"); - if (r < 0) - goto fail; - - r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl); - if (r < 0) - goto fail; - - r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit"); - if (r < 0) - goto fail; - - return 0; - -fail: - sd_netlink_detach_event(rtnl); - return r; -} - -int sd_netlink_detach_event(sd_netlink *rtnl) { - assert_return(rtnl, -EINVAL); - assert_return(rtnl->event, -ENXIO); - - if (rtnl->io_event_source) - rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source); - - if (rtnl->time_event_source) - rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source); - - if (rtnl->exit_event_source) - rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source); - - if (rtnl->event) - rtnl->event = sd_event_unref(rtnl->event); - - 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 r; - - assert_return(rtnl, -EINVAL); - assert_return(callback, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); - - c = new0(struct match_callback, 1); - if (!c) - return -ENOMEM; - - c->callback = callback; - c->type = type; - c->userdata = userdata; - - switch (type) { - case RTM_NEWLINK: - case RTM_SETLINK: - case RTM_GETLINK: - case RTM_DELLINK: - r = rtnl_join_broadcast_group(rtnl, RTNLGRP_LINK); - if (r < 0) - return r; - - break; - case RTM_NEWADDR: - case RTM_GETADDR: - case RTM_DELADDR: - r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR); - if (r < 0) - return r; - - r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR); - if (r < 0) - return r; - - break; - default: - return -EOPNOTSUPP; - } - - LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c); - - c = NULL; - - 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; - - 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); - - return 1; - } - - return 0; -} diff --git a/src/libsystemd/sd-netlink/test-local-addresses.c b/src/libsystemd/sd-netlink/test-local-addresses.c deleted file mode 100644 index 38cbcfbcc..000000000 --- a/src/libsystemd/sd-netlink/test-local-addresses.c +++ /dev/null @@ -1,58 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include "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; - - for (i = 0; i < n; i++) { - _cleanup_free_ char *b = NULL; - - assert_se(in_addr_to_string(a[i].family, &a[i].address, &b) >= 0); - printf("%s if%i scope=%i metric=%u address=%s\n", af_to_name(a[i].family), a[i].ifindex, a[i].scope, a[i].metric, b); - } -} - -int main(int argc, char *argv[]) { - struct local_address *a; - int n; - - a = NULL; - n = local_addresses(NULL, 0, AF_UNSPEC, &a); - assert_se(n >= 0); - - printf("Local Addresses:\n"); - print_local_addresses(a, (unsigned) n); - free(a); - - a = NULL; - n = local_gateways(NULL, 0, AF_UNSPEC, &a); - assert_se(n >= 0); - - printf("Local Gateways:\n"); - print_local_addresses(a, (unsigned) n); - free(a); - - return 0; -} diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c deleted file mode 100644 index 60a4601e7..000000000 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ /dev/null @@ -1,443 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2013 Tom Gundersen <teg@jklm.no> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <netinet/ether.h> -#include <net/if.h> - -#include "util.h" -#include "macro.h" -#include "sd-netlink.h" -#include "socket-util.h" -#include "netlink-util.h" -#include "event-util.h" -#include "missing.h" - -static void test_message_link_bridge(sd_netlink *rtnl) { - _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL; - uint32_t cost; - - assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0); - assert_se(sd_rtnl_message_link_set_family(message, PF_BRIDGE) >= 0); - assert_se(sd_netlink_message_open_container(message, IFLA_PROTINFO) >= 0); - assert_se(sd_netlink_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0); - assert_se(sd_netlink_message_close_container(message) >= 0); - - assert_se(sd_netlink_message_rewind(message) >= 0); - - assert_se(sd_netlink_message_enter_container(message, IFLA_PROTINFO) >= 0); - assert_se(sd_netlink_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0); - assert_se(cost == 10); - assert_se(sd_netlink_message_exit_container(message) >= 0); -} - -static void test_link_configure(sd_netlink *rtnl, int ifindex) { - _cleanup_netlink_message_unref_ 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; - const char *name_out; - struct ether_addr mac_out; - - /* we'd really like to test NEWLINK, but let's not mess with the running kernel */ - assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0); - assert_se(sd_netlink_message_append_string(message, IFLA_IFNAME, name) >= 0); - assert_se(sd_netlink_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0); - assert_se(sd_netlink_message_append_u32(message, IFLA_MTU, mtu) >= 0); - - assert_se(sd_netlink_call(rtnl, message, 0, NULL) == 1); - assert_se(sd_netlink_message_rewind(message) >= 0); - - assert_se(sd_netlink_message_read_string(message, IFLA_IFNAME, &name_out) >= 0); - assert_se(streq(name, name_out)); - - assert_se(sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &mac_out) >= 0); - assert_se(streq(mac, ether_addr_to_string(&mac_out, buffer))); - - assert_se(sd_netlink_message_read_u32(message, IFLA_MTU, &mtu_out) >= 0); - assert_se(mtu == mtu_out); -} - -static void test_link_get(sd_netlink *rtnl, int ifindex) { - sd_netlink_message *m; - sd_netlink_message *r; - unsigned int mtu = 1500; - const char *str_data; - uint8_t u8_data; - uint32_t u32_data; - struct ether_addr eth_data; - - assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); - assert_se(m); - - /* u8 test cases */ - assert_se(sd_netlink_message_append_u8(m, IFLA_CARRIER, 0) >= 0); - assert_se(sd_netlink_message_append_u8(m, IFLA_OPERSTATE, 0) >= 0); - assert_se(sd_netlink_message_append_u8(m, IFLA_LINKMODE, 0) >= 0); - - /* u32 test cases */ - assert_se(sd_netlink_message_append_u32(m, IFLA_MTU, mtu) >= 0); - assert_se(sd_netlink_message_append_u32(m, IFLA_GROUP, 0) >= 0); - assert_se(sd_netlink_message_append_u32(m, IFLA_TXQLEN, 0) >= 0); - assert_se(sd_netlink_message_append_u32(m, IFLA_NUM_TX_QUEUES, 0) >= 0); - assert_se(sd_netlink_message_append_u32(m, IFLA_NUM_RX_QUEUES, 0) >= 0); - - assert_se(sd_netlink_call(rtnl, m, -1, &r) == 1); - - assert_se(sd_netlink_message_read_string(r, IFLA_IFNAME, &str_data) == 0); - - assert_se(sd_netlink_message_read_u8(r, IFLA_CARRIER, &u8_data) == 0); - assert_se(sd_netlink_message_read_u8(r, IFLA_OPERSTATE, &u8_data) == 0); - assert_se(sd_netlink_message_read_u8(r, IFLA_LINKMODE, &u8_data) == 0); - - assert_se(sd_netlink_message_read_u32(r, IFLA_MTU, &u32_data) == 0); - assert_se(sd_netlink_message_read_u32(r, IFLA_GROUP, &u32_data) == 0); - assert_se(sd_netlink_message_read_u32(r, IFLA_TXQLEN, &u32_data) == 0); - assert_se(sd_netlink_message_read_u32(r, IFLA_NUM_TX_QUEUES, &u32_data) == 0); - assert_se(sd_netlink_message_read_u32(r, IFLA_NUM_RX_QUEUES, &u32_data) == 0); - - assert_se(sd_netlink_message_read_ether_addr(r, IFLA_ADDRESS, ð_data) == 0); - - assert_se(sd_netlink_flush(rtnl) >= 0); - assert_se((m = sd_netlink_message_unref(m)) == NULL); - assert_se((r = sd_netlink_message_unref(r)) == NULL); -} - - -static void test_address_get(sd_netlink *rtnl, int ifindex) { - sd_netlink_message *m; - sd_netlink_message *r; - struct in_addr in_data; - struct ifa_cacheinfo cache; - const char *label; - - assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0); - assert_se(m); - - assert_se(sd_netlink_call(rtnl, m, -1, &r) == 1); - - assert_se(sd_netlink_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0); - assert_se(sd_netlink_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0); - assert_se(sd_netlink_message_read_string(r, IFA_LABEL, &label) == 0); - assert_se(sd_netlink_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0); - - assert_se(sd_netlink_flush(rtnl) >= 0); - assert_se((m = sd_netlink_message_unref(m)) == NULL); - assert_se((r = sd_netlink_message_unref(r)) == NULL); - -} - -static void test_route(void) { - _cleanup_netlink_message_unref_ sd_netlink_message *req; - struct in_addr addr, addr_data; - uint32_t index = 2, u32_data; - int r; - - r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC); - if (r < 0) { - log_error_errno(r, "Could not create RTM_NEWROUTE message: %m"); - return; - } - - addr.s_addr = htonl(INADDR_LOOPBACK); - - r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &addr); - if (r < 0) { - log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m"); - return; - } - - r = sd_netlink_message_append_u32(req, RTA_OIF, index); - if (r < 0) { - log_error_errno(r, "Could not append RTA_OIF attribute: %m"); - return; - } - - assert_se(sd_netlink_message_rewind(req) >= 0); - - assert_se(sd_netlink_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0); - assert_se(addr_data.s_addr == addr.s_addr); - - assert_se(sd_netlink_message_read_u32(req, RTA_OIF, &u32_data) >= 0); - assert_se(u32_data == index); - - assert_se((req = sd_netlink_message_unref(req)) == NULL); -} - -static void test_multiple(void) { - sd_netlink *rtnl1, *rtnl2; - - assert_se(sd_netlink_open(&rtnl1) >= 0); - assert_se(sd_netlink_open(&rtnl2) >= 0); - - rtnl1 = sd_netlink_unref(rtnl1); - rtnl2 = sd_netlink_unref(rtnl2); -} - -static int link_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { - char *ifname = userdata; - const char *data; - - assert_se(rtnl); - assert_se(m); - - log_info("got link info about %s", ifname); - free(ifname); - - assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &data) >= 0); - assert_se(streq(data, "lo")); - - return 1; -} - -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; - char *ifname; - - ifname = strdup("lo2"); - 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, m, &link_handler, ifname, 0, NULL) >= 0); - - assert_se(sd_event_default(&event) >= 0); - - assert_se(sd_netlink_attach_event(rtnl, event, 0) >= 0); - - assert_se(sd_event_run(event, 0) >= 0); - - assert_se(sd_netlink_detach_event(rtnl) >= 0); - - assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); -} - -static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { - int *counter = userdata; - int r; - - (*counter) --; - - r = sd_netlink_message_get_errno(m); - - log_info_errno(r, "%d left in pipe. got reply: %m", *counter); - - assert_se(r >= 0); - - return 1; -} - -static void test_async(int ifindex) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL, *r = NULL; - uint32_t serial; - 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, m, &link_handler, ifname, 0, &serial) >= 0); - - 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_pipe(int ifindex) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - _cleanup_netlink_message_unref_ sd_netlink_message *m1 = NULL, *m2 = NULL; - int counter = 0; - - assert_se(sd_netlink_open(&rtnl) >= 0); - - 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, m2, &pipe_handler, &counter, 0, NULL) >= 0); - - while (counter > 0) { - assert_se(sd_netlink_wait(rtnl, 0) >= 0); - assert_se(sd_netlink_process(rtnl, NULL) >= 0); - } - - assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); -} - -static void test_container(void) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; - uint16_t u16_data; - uint32_t u32_data; - const char *string_data; - - assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0); - - assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0); - assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "vlan") >= 0); - assert_se(sd_netlink_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0); - assert_se(sd_netlink_message_close_container(m) >= 0); - assert_se(sd_netlink_message_append_string(m, IFLA_INFO_KIND, "vlan") >= 0); - assert_se(sd_netlink_message_close_container(m) >= 0); - assert_se(sd_netlink_message_close_container(m) == -EINVAL); - - assert_se(sd_netlink_message_rewind(m) >= 0); - - assert_se(sd_netlink_message_enter_container(m, IFLA_LINKINFO) >= 0); - assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0); - assert_se(streq("vlan", string_data)); - - assert_se(sd_netlink_message_enter_container(m, IFLA_INFO_DATA) >= 0); - assert_se(sd_netlink_message_read_u16(m, IFLA_VLAN_ID, &u16_data) >= 0); - assert_se(sd_netlink_message_exit_container(m) >= 0); - - assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0); - assert_se(streq("vlan", string_data)); - assert_se(sd_netlink_message_exit_container(m) >= 0); - - assert_se(sd_netlink_message_read_u32(m, IFLA_LINKINFO, &u32_data) < 0); - - assert_se(sd_netlink_message_exit_container(m) == -EINVAL); -} - -static void test_match(void) { - _cleanup_netlink_unref_ 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_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; - sd_netlink_message *m; - - assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0); - - assert_se(sd_netlink_call(rtnl, req, 0, &reply) >= 0); - - for (m = reply; m; m = sd_netlink_message_next(m)) { - uint16_t type; - unsigned char scope, flags; - int family, ifindex; - - assert_se(sd_netlink_message_get_type(m, &type) >= 0); - assert_se(type == RTM_NEWADDR); - - assert_se(sd_rtnl_message_addr_get_ifindex(m, &ifindex) >= 0); - assert_se(sd_rtnl_message_addr_get_family(m, &family) >= 0); - assert_se(sd_rtnl_message_addr_get_scope(m, &scope) >= 0); - assert_se(sd_rtnl_message_addr_get_flags(m, &flags) >= 0); - - assert_se(ifindex > 0); - assert_se(family == AF_INET || family == AF_INET6); - - log_info("got IPv%u address on ifindex %i", family == AF_INET ? 4: 6, ifindex); - } -} - -static void test_message(void) { - _cleanup_netlink_message_unref_ 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); -} - -int main(void) { - sd_netlink *rtnl; - sd_netlink_message *m; - sd_netlink_message *r; - const char *string_data; - int if_loopback; - uint16_t type; - - test_message(); - - test_match(); - - test_multiple(); - - test_route(); - - test_container(); - - assert_se(sd_netlink_open(&rtnl) >= 0); - assert_se(rtnl); - - if_loopback = (int) if_nametoindex("lo"); - assert_se(if_loopback > 0); - - test_async(if_loopback); - - test_pipe(if_loopback); - - test_event_loop(if_loopback); - - test_link_configure(rtnl, if_loopback); - - test_get_addresses(rtnl); - - test_message_link_bridge(rtnl); - - assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0); - assert_se(m); - - assert_se(sd_netlink_message_get_type(m, &type) >= 0); - assert_se(type == RTM_GETLINK); - - assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &string_data) == -EPERM); - - assert_se(sd_netlink_call(rtnl, m, 0, &r) == 1); - assert_se(sd_netlink_message_get_type(r, &type) >= 0); - assert_se(type == RTM_NEWLINK); - - assert_se((r = sd_netlink_message_unref(r)) == NULL); - - assert_se(sd_netlink_call(rtnl, m, -1, &r) == -EPERM); - assert_se((m = sd_netlink_message_unref(m)) == NULL); - assert_se((r = sd_netlink_message_unref(r)) == NULL); - - test_link_get(rtnl, if_loopback); - test_address_get(rtnl, if_loopback); - - assert_se(sd_netlink_flush(rtnl) >= 0); - assert_se((m = sd_netlink_message_unref(m)) == NULL); - assert_se((r = sd_netlink_message_unref(r)) == NULL); - assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); - - return EXIT_SUCCESS; -} |