summaryrefslogtreecommitdiffstats
path: root/src/libsystemd/sd-netlink
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd/sd-netlink')
-rw-r--r--src/libsystemd/sd-netlink/netlink-message-rtnl.c41
-rw-r--r--src/libsystemd/sd-netlink/netlink-message.c29
-rw-r--r--src/libsystemd/sd-netlink/netlink-types-genl.c1
-rw-r--r--src/libsystemd/sd-netlink/netlink-types-rtnl.c13
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.c421
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.h56
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c8
-rw-r--r--src/libsystemd/sd-netlink/test-netlink.c14
8 files changed, 299 insertions, 284 deletions
diff --git a/src/libsystemd/sd-netlink/netlink-message-rtnl.c b/src/libsystemd/sd-netlink/netlink-message-rtnl.c
index 008e802..fb11c7e 100644
--- a/src/libsystemd/sd-netlink/netlink-message-rtnl.c
+++ b/src/libsystemd/sd-netlink/netlink-message-rtnl.c
@@ -56,6 +56,10 @@ static bool rtnl_message_type_is_mdb(uint16_t type) {
return IN_SET(type, RTM_NEWMDB, RTM_DELMDB, RTM_GETMDB);
}
+static bool rtnl_message_type_is_nsid(uint16_t type) {
+ return IN_SET(type, RTM_NEWNSID, RTM_DELNSID, RTM_GETNSID);
+}
+
int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
struct rtmsg *rtm;
@@ -92,6 +96,20 @@ int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char
return 0;
}
+int sd_rtnl_message_route_set_tos(sd_netlink_message *m, unsigned char tos) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ rtm->rtm_tos = tos;
+
+ return 0;
+}
+
int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope) {
struct rtmsg *rtm;
@@ -336,7 +354,7 @@ int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret,
return r;
if (nlmsg_type == RTM_NEWNEXTHOP)
- (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
+ (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
nhm = NLMSG_DATA((*ret)->hdr);
@@ -1202,3 +1220,24 @@ int sd_rtnl_message_new_mdb(
return 0;
}
+
+int sd_rtnl_message_new_nsid(
+ sd_netlink *rtnl,
+ sd_netlink_message **ret,
+ uint16_t nlmsg_type) {
+
+ struct rtgenmsg *rt;
+ int r;
+
+ assert_return(rtnl_message_type_is_nsid(nlmsg_type), -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = message_new(rtnl, ret, nlmsg_type);
+ if (r < 0)
+ return r;
+
+ rt = NLMSG_DATA((*ret)->hdr);
+ rt->rtgen_family = AF_UNSPEC;
+
+ return 0;
+}
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index 000a50e..49d000d 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -17,9 +17,6 @@
#define GET_CONTAINER(m, i) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset))
-#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
-#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
-
int message_new_empty(sd_netlink *nl, sd_netlink_message **ret) {
sd_netlink_message *m;
@@ -789,32 +786,6 @@ int sd_netlink_message_read_data(sd_netlink_message *m, uint16_t attr_type, size
if (ret_data) {
void *data;
- data = memdup(attr_data, r);
- if (!data)
- return -ENOMEM;
-
- *ret_data = data;
- }
-
- if (ret_size)
- *ret_size = r;
-
- return r;
-}
-
-int sd_netlink_message_read_data_suffix0(sd_netlink_message *m, uint16_t attr_type, size_t *ret_size, void **ret_data) {
- void *attr_data;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
- if (r < 0)
- return r;
-
- if (ret_data) {
- void *data;
-
data = memdup_suffix0(attr_data, r);
if (!data)
return -ENOMEM;
diff --git a/src/libsystemd/sd-netlink/netlink-types-genl.c b/src/libsystemd/sd-netlink/netlink-types-genl.c
index 6fe9adc..226ac86 100644
--- a/src/libsystemd/sd-netlink/netlink-types-genl.c
+++ b/src/libsystemd/sd-netlink/netlink-types-genl.c
@@ -199,6 +199,7 @@ static const NLAPolicy genl_nl80211_policies[] = {
[NL80211_ATTR_SSID] = BUILD_POLICY_WITH_SIZE(BINARY, IEEE80211_MAX_SSID_LEN),
[NL80211_ATTR_STATUS_CODE] = BUILD_POLICY(U16),
[NL80211_ATTR_4ADDR] = BUILD_POLICY(U8),
+ [NL80211_ATTR_NETNS_FD] = BUILD_POLICY(U32),
};
/***************** genl wireguard type systems *****************/
diff --git a/src/libsystemd/sd-netlink/netlink-types-rtnl.c b/src/libsystemd/sd-netlink/netlink-types-rtnl.c
index 0153456..e39a75c 100644
--- a/src/libsystemd/sd-netlink/netlink-types-rtnl.c
+++ b/src/libsystemd/sd-netlink/netlink-types-rtnl.c
@@ -17,6 +17,7 @@
#include <linux/if_tunnel.h>
#include <linux/ip.h>
#include <linux/l2tp.h>
+#include <linux/net_namespace.h>
#include <linux/netlink.h>
#include <linux/nexthop.h>
#include <linux/nl80211.h>
@@ -123,6 +124,7 @@ static const NLAPolicy rtnl_link_info_data_bond_policies[] = {
[IFLA_BOND_AD_ACTOR_SYSTEM] = BUILD_POLICY_WITH_SIZE(ETHER_ADDR, ETH_ALEN),
[IFLA_BOND_TLB_DYNAMIC_LB] = BUILD_POLICY(U8),
[IFLA_BOND_PEER_NOTIF_DELAY] = BUILD_POLICY(U32),
+ [IFLA_BOND_MISSED_MAX] = BUILD_POLICY(U8),
};
static const NLAPolicy rtnl_link_info_data_bridge_policies[] = {
@@ -306,6 +308,7 @@ static const NLAPolicy rtnl_link_info_data_macvlan_policies[] = {
[IFLA_MACVLAN_MACADDR_COUNT] = BUILD_POLICY(U32),
[IFLA_MACVLAN_BC_QUEUE_LEN] = BUILD_POLICY(U32),
[IFLA_MACVLAN_BC_QUEUE_LEN_USED] = BUILD_POLICY(U32),
+ [IFLA_MACVLAN_BC_CUTOFF] = BUILD_POLICY(S32),
};
static const NLAPolicy rtnl_link_info_data_tun_policies[] = {
@@ -1185,6 +1188,13 @@ static const NLAPolicy rtnl_mdb_policies[] = {
DEFINE_POLICY_SET(rtnl_mdb);
+static const NLAPolicy rtnl_nsid_policies[] = {
+ [NETNSA_FD] = BUILD_POLICY(S32),
+ [NETNSA_NSID] = BUILD_POLICY(U32),
+};
+
+DEFINE_POLICY_SET(rtnl_nsid);
+
static const NLAPolicy rtnl_policies[] = {
[RTM_NEWLINK] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_link, sizeof(struct ifinfomsg)),
[RTM_DELLINK] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_link, sizeof(struct ifinfomsg)),
@@ -1220,6 +1230,9 @@ static const NLAPolicy rtnl_policies[] = {
[RTM_NEWMDB] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_mdb, sizeof(struct br_port_msg)),
[RTM_DELMDB] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_mdb, sizeof(struct br_port_msg)),
[RTM_GETMDB] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_mdb, sizeof(struct br_port_msg)),
+ [RTM_NEWNSID] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_nsid, sizeof(struct rtgenmsg)),
+ [RTM_DELNSID] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_nsid, sizeof(struct rtgenmsg)),
+ [RTM_GETNSID] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_nsid, sizeof(struct rtgenmsg)),
};
DEFINE_POLICY_SET(rtnl);
diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
index 832159a..9061609 100644
--- a/src/libsystemd/sd-netlink/netlink-util.c
+++ b/src/libsystemd/sd-netlink/netlink-util.c
@@ -11,6 +11,154 @@
#include "process-util.h"
#include "strv.h"
+static int parse_newlink_message(
+ sd_netlink_message *message,
+ char **ret_name,
+ char ***ret_altnames) {
+
+ _cleanup_strv_free_ char **altnames = NULL;
+ int r, ifindex;
+
+ assert(message);
+
+ uint16_t type;
+ r = sd_netlink_message_get_type(message, &type);
+ if (r < 0)
+ return r;
+ if (type != RTM_NEWLINK)
+ return -EPROTO;
+
+ r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
+ if (r < 0)
+ return r;
+ if (ifindex <= 0)
+ return -EPROTO;
+
+ if (ret_altnames) {
+ r = sd_netlink_message_read_strv(message, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &altnames);
+ if (r < 0 && r != -ENODATA)
+ return r;
+ }
+
+ if (ret_name) {
+ r = sd_netlink_message_read_string_strdup(message, IFLA_IFNAME, ret_name);
+ if (r < 0)
+ return r;
+ }
+
+ if (ret_altnames)
+ *ret_altnames = TAKE_PTR(altnames);
+
+ return ifindex;
+}
+
+int rtnl_get_ifname_full(sd_netlink **rtnl, int ifindex, char **ret_name, char ***ret_altnames) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *our_rtnl = NULL;
+ int r;
+
+ assert(ifindex > 0);
+
+ /* This is similar to if_indextoname(), but also optionally provides alternative names. */
+
+ if (!rtnl)
+ rtnl = &our_rtnl;
+ if (!*rtnl) {
+ r = sd_netlink_open(rtnl);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(*rtnl, message, 0, &reply);
+ if (r < 0)
+ return r;
+
+ return parse_newlink_message(reply, ret_name, ret_altnames);
+}
+
+int rtnl_resolve_ifname_full(
+ sd_netlink **rtnl,
+ ResolveInterfaceNameFlag flags,
+ const char *name,
+ char **ret_name,
+ char ***ret_altnames) {
+
+ _cleanup_(sd_netlink_unrefp) sd_netlink *our_rtnl = NULL;
+ int r;
+
+ assert(name);
+ assert(flags > 0);
+
+ /* This is similar to if_nametoindex(), but also resolves alternative names and decimal formatted
+ * ifindex too. Returns ifindex, and optionally provides the main interface name and alternative
+ * names.*/
+
+ if (!rtnl)
+ rtnl = &our_rtnl;
+ if (!*rtnl) {
+ r = sd_netlink_open(rtnl);
+ if (r < 0)
+ return r;
+ }
+
+ /* First, use IFLA_IFNAME */
+ if (FLAGS_SET(flags, RESOLVE_IFNAME_MAIN) && ifname_valid(name)) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
+
+ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, 0);
+ 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, &reply);
+ if (r >= 0)
+ return parse_newlink_message(reply, ret_name, ret_altnames);
+ if (r != -ENODEV)
+ return r;
+ }
+
+ /* Next, try IFLA_ALT_IFNAME */
+ if (FLAGS_SET(flags, RESOLVE_IFNAME_ALTERNATIVE) &&
+ ifname_valid_full(name, IFNAME_VALID_ALTERNATIVE)) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
+
+ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(message, IFLA_ALT_IFNAME, name);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(*rtnl, message, 0, &reply);
+ if (r >= 0)
+ return parse_newlink_message(reply, ret_name, ret_altnames);
+ /* The kernels older than 76c9ac0ee878f6693d398d3a95ccaf85e1f597a6 (v5.5) return -EINVAL. */
+ if (!IN_SET(r, -ENODEV, -EINVAL))
+ return r;
+ }
+
+ /* Finally, assume the string is a decimal formatted ifindex. */
+ if (FLAGS_SET(flags, RESOLVE_IFNAME_NUMERIC)) {
+ int ifindex;
+
+ ifindex = parse_ifindex(name);
+ if (ifindex <= 0)
+ return -ENODEV;
+
+ return rtnl_get_ifname_full(rtnl, ifindex, ret_name, ret_altnames);
+ }
+
+ return -ENODEV;
+}
+
static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
int r;
@@ -20,6 +168,13 @@ static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
assert(name);
/* Assign the requested 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;
@@ -31,6 +186,37 @@ static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
return sd_netlink_call(*rtnl, message, 0, NULL);
}
+int rtnl_rename_link(sd_netlink **rtnl, const char *orig_name, const char *new_name) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *our_rtnl = NULL;
+ int r, ifindex;
+
+ assert(orig_name);
+ assert(new_name);
+
+ /* This does not check alternative names. Callers must check the requested name is not used as an
+ * alternative name. */
+
+ if (streq(orig_name, new_name))
+ return 0;
+
+ if (!ifname_valid(new_name))
+ return -EINVAL;
+
+ if (!rtnl)
+ rtnl = &our_rtnl;
+ if (!*rtnl) {
+ r = sd_netlink_open(rtnl);
+ if (r < 0)
+ return r;
+ }
+
+ ifindex = rtnl_resolve_ifname(rtnl, orig_name);
+ if (ifindex < 0)
+ return ifindex;
+
+ return set_link_name(rtnl, ifindex, new_name);
+}
+
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const *alternative_names) {
_cleanup_strv_free_ char **original_altnames = NULL, **new_altnames = NULL;
bool altname_deleted = false;
@@ -204,38 +390,6 @@ int rtnl_set_link_properties(
return 0;
}
-int rtnl_get_link_alternative_names(sd_netlink **rtnl, int ifindex, char ***ret) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
- _cleanup_strv_free_ char **names = NULL;
- int r;
-
- assert(rtnl);
- assert(ifindex > 0);
- assert(ret);
-
- if (!*rtnl) {
- r = sd_netlink_open(rtnl);
- if (r < 0)
- return r;
- }
-
- r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, ifindex);
- if (r < 0)
- return r;
-
- r = sd_netlink_call(*rtnl, message, 0, &reply);
- if (r < 0)
- return r;
-
- r = sd_netlink_message_read_strv(reply, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &names);
- if (r < 0 && r != -ENODATA)
- return r;
-
- *ret = TAKE_PTR(names);
-
- return 0;
-}
-
static int rtnl_update_link_alternative_names(
sd_netlink **rtnl,
uint16_t nlmsg_type,
@@ -336,92 +490,6 @@ int rtnl_set_link_alternative_names_by_ifname(
return 0;
}
-int rtnl_resolve_link_alternative_name(sd_netlink **rtnl, const char *name, char **ret) {
- _cleanup_(sd_netlink_unrefp) sd_netlink *our_rtnl = NULL;
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
- int r, ifindex;
-
- assert(name);
-
- /* This returns ifindex and the main interface name. */
-
- if (!ifname_valid_full(name, IFNAME_VALID_ALTERNATIVE))
- return -EINVAL;
-
- if (!rtnl)
- rtnl = &our_rtnl;
- if (!*rtnl) {
- r = sd_netlink_open(rtnl);
- if (r < 0)
- return r;
- }
-
- r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, 0);
- if (r < 0)
- return r;
-
- r = sd_netlink_message_append_string(message, IFLA_ALT_IFNAME, name);
- if (r < 0)
- return r;
-
- r = sd_netlink_call(*rtnl, message, 0, &reply);
- if (r == -EINVAL)
- return -ENODEV; /* The device doesn't exist */
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
- if (r < 0)
- return r;
- assert(ifindex > 0);
-
- if (ret) {
- r = sd_netlink_message_read_string_strdup(reply, IFLA_IFNAME, ret);
- if (r < 0)
- return r;
- }
-
- return ifindex;
-}
-
-int rtnl_resolve_ifname(sd_netlink **rtnl, const char *name) {
- int r;
-
- /* Like if_nametoindex, but resolves "alternative names" too. */
-
- assert(name);
-
- r = if_nametoindex(name);
- if (r > 0)
- return r;
-
- return rtnl_resolve_link_alternative_name(rtnl, name, NULL);
-}
-
-int rtnl_resolve_interface(sd_netlink **rtnl, const char *name) {
- int r;
-
- /* Like rtnl_resolve_ifname, but resolves interface numbers too. */
-
- assert(name);
-
- r = parse_ifindex(name);
- if (r > 0)
- return r;
- assert(r < 0);
-
- return rtnl_resolve_ifname(rtnl, name);
-}
-
-int rtnl_resolve_interface_or_warn(sd_netlink **rtnl, const char *name) {
- int r;
-
- r = rtnl_resolve_interface(rtnl, name);
- if (r < 0)
- return log_error_errno(r, "Failed to resolve interface \"%s\": %m", name);
- return r;
-}
-
int rtnl_get_link_info(
sd_netlink **rtnl,
int ifindex,
@@ -441,7 +509,7 @@ int rtnl_get_link_info(
assert(rtnl);
assert(ifindex > 0);
- if (!ret_iftype && !ret_flags)
+ if (!ret_iftype && !ret_flags && !ret_kind && !ret_hw_addr && !ret_permanent_hw_addr)
return 0;
if (!*rtnl) {
@@ -575,121 +643,6 @@ int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void
return 0;
}
-MultipathRoute *multipath_route_free(MultipathRoute *m) {
- if (!m)
- return NULL;
-
- free(m->ifname);
-
- return mfree(m);
-}
-
-int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret) {
- _cleanup_(multipath_route_freep) MultipathRoute *n = NULL;
- _cleanup_free_ char *ifname = NULL;
-
- assert(m);
- assert(ret);
-
- if (m->ifname) {
- ifname = strdup(m->ifname);
- if (!ifname)
- return -ENOMEM;
- }
-
- n = new(MultipathRoute, 1);
- if (!n)
- return -ENOMEM;
-
- *n = (MultipathRoute) {
- .gateway = m->gateway,
- .weight = m->weight,
- .ifindex = m->ifindex,
- .ifname = TAKE_PTR(ifname),
- };
-
- *ret = TAKE_PTR(n);
-
- return 0;
-}
-
-int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, OrderedSet **ret) {
- _cleanup_ordered_set_free_free_ OrderedSet *set = NULL;
- int r;
-
- assert(rtnh);
- assert(IN_SET(family, AF_INET, AF_INET6));
-
- if (size < sizeof(struct rtnexthop))
- return -EBADMSG;
-
- for (; size >= sizeof(struct rtnexthop); ) {
- _cleanup_(multipath_route_freep) MultipathRoute *m = NULL;
-
- if (NLMSG_ALIGN(rtnh->rtnh_len) > size)
- return -EBADMSG;
-
- if (rtnh->rtnh_len < sizeof(struct rtnexthop))
- return -EBADMSG;
-
- m = new(MultipathRoute, 1);
- if (!m)
- return -ENOMEM;
-
- *m = (MultipathRoute) {
- .ifindex = rtnh->rtnh_ifindex,
- .weight = rtnh->rtnh_hops,
- };
-
- if (rtnh->rtnh_len > sizeof(struct rtnexthop)) {
- size_t len = rtnh->rtnh_len - sizeof(struct rtnexthop);
-
- for (struct rtattr *attr = RTNH_DATA(rtnh); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
- if (attr->rta_type == RTA_GATEWAY) {
- if (attr->rta_len != RTA_LENGTH(FAMILY_ADDRESS_SIZE(family)))
- return -EBADMSG;
-
- m->gateway.family = family;
- memcpy(&m->gateway.address, RTA_DATA(attr), FAMILY_ADDRESS_SIZE(family));
- break;
- } else if (attr->rta_type == RTA_VIA) {
- uint16_t gw_family;
-
- if (family != AF_INET)
- return -EINVAL;
-
- if (attr->rta_len < RTA_LENGTH(sizeof(uint16_t)))
- return -EBADMSG;
-
- gw_family = *(uint16_t *) RTA_DATA(attr);
-
- if (gw_family != AF_INET6)
- return -EBADMSG;
-
- if (attr->rta_len != RTA_LENGTH(FAMILY_ADDRESS_SIZE(gw_family) + sizeof(gw_family)))
- return -EBADMSG;
-
- memcpy(&m->gateway, RTA_DATA(attr), FAMILY_ADDRESS_SIZE(gw_family) + sizeof(gw_family));
- break;
- }
- }
- }
-
- r = ordered_set_ensure_put(&set, NULL, m);
- if (r < 0)
- return r;
-
- TAKE_PTR(m);
-
- size -= NLMSG_ALIGN(rtnh->rtnh_len);
- rtnh = RTNH_NEXT(rtnh);
- }
-
- if (ret)
- *ret = TAKE_PTR(set);
- return 0;
-}
-
bool netlink_pid_changed(sd_netlink *nl) {
/* We don't support people creating an nl connection and
* keeping it around over a fork(). Let's complain. */
diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h
index 369f5d5..4ba64f0 100644
--- a/src/libsystemd/sd-netlink/netlink-util.h
+++ b/src/libsystemd/sd-netlink/netlink-util.h
@@ -10,24 +10,32 @@
#include "ordered-set.h"
#include "socket-util.h"
+#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
+#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
+
/* See struct rtvia in rtnetlink.h */
typedef struct RouteVia {
uint16_t family;
union in_addr_union address;
} _packed_ RouteVia;
-typedef struct MultipathRoute {
- RouteVia gateway;
- uint32_t weight;
- int ifindex;
- char *ifname;
-} MultipathRoute;
+int rtnl_get_ifname_full(sd_netlink **rtnl, int ifindex, char **ret_name, char ***ret_altnames);
-MultipathRoute *multipath_route_free(MultipathRoute *m);
-DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free);
+typedef enum ResolveInterfaceNameFlag {
+ RESOLVE_IFNAME_MAIN = 1 << 0, /* resolve main interface name */
+ RESOLVE_IFNAME_ALTERNATIVE = 1 << 1, /* resolve alternative name */
+ RESOLVE_IFNAME_NUMERIC = 1 << 2, /* resolve decimal formatted ifindex */
+ _RESOLVE_IFNAME_ALL = RESOLVE_IFNAME_MAIN | RESOLVE_IFNAME_ALTERNATIVE | RESOLVE_IFNAME_NUMERIC,
+} ResolveInterfaceNameFlag;
-int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret);
+int rtnl_resolve_ifname_full(
+ sd_netlink **rtnl,
+ ResolveInterfaceNameFlag flags,
+ const char *name,
+ char **ret_name,
+ char ***ret_altnames);
+int rtnl_rename_link(sd_netlink **rtnl, const char *orig_name, const char *new_name);
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const* alternative_names);
static inline int rtnl_append_link_alternative_names(sd_netlink **rtnl, int ifindex, char* const *alternative_names) {
return rtnl_set_link_name(rtnl, ifindex, NULL, alternative_names);
@@ -43,14 +51,32 @@ int rtnl_set_link_properties(
uint32_t mtu,
uint32_t gso_max_size,
size_t gso_max_segments);
-int rtnl_get_link_alternative_names(sd_netlink **rtnl, int ifindex, char ***ret);
+static inline int rtnl_get_link_alternative_names(sd_netlink **rtnl, int ifindex, char ***ret) {
+ return rtnl_get_ifname_full(rtnl, ifindex, NULL, ret);
+}
int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char* const *alternative_names);
int rtnl_set_link_alternative_names_by_ifname(sd_netlink **rtnl, const char *ifname, char* const *alternative_names);
int rtnl_delete_link_alternative_names(sd_netlink **rtnl, int ifindex, char* const *alternative_names);
-int rtnl_resolve_link_alternative_name(sd_netlink **rtnl, const char *name, char **ret);
-int rtnl_resolve_ifname(sd_netlink **rtnl, const char *name);
-int rtnl_resolve_interface(sd_netlink **rtnl, const char *name);
-int rtnl_resolve_interface_or_warn(sd_netlink **rtnl, const char *name);
+static inline int rtnl_resolve_link_alternative_name(sd_netlink **rtnl, const char *name, char **ret) {
+ return rtnl_resolve_ifname_full(rtnl, RESOLVE_IFNAME_ALTERNATIVE, name, ret, NULL);
+}
+static inline int rtnl_resolve_ifname(sd_netlink **rtnl, const char *name) {
+ return rtnl_resolve_ifname_full(rtnl, RESOLVE_IFNAME_MAIN | RESOLVE_IFNAME_ALTERNATIVE, name, NULL, NULL);
+}
+static inline int rtnl_resolve_interface(sd_netlink **rtnl, const char *name) {
+ return rtnl_resolve_ifname_full(rtnl, _RESOLVE_IFNAME_ALL, name, NULL, NULL);
+}
+static inline int rtnl_resolve_interface_or_warn(sd_netlink **rtnl, const char *name) {
+ int r;
+
+ assert(name);
+
+ r = rtnl_resolve_interface(rtnl, name);
+ if (r < 0)
+ return log_error_errno(r, "Failed to resolve interface \"%s\": %m", name);
+ return r;
+}
+
int rtnl_get_link_info(
sd_netlink **rtnl,
int ifindex,
@@ -103,8 +129,6 @@ int netlink_message_read_in_addr_union(sd_netlink_message *m, unsigned short typ
void rtattr_append_attribute_internal(struct rtattr *rta, unsigned short type, const void *data, size_t data_length);
int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void *data, size_t data_length);
-int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, OrderedSet **ret);
-
void netlink_seal_message(sd_netlink *nl, sd_netlink_message *m);
size_t netlink_get_reply_callback_count(sd_netlink *nl);
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index b6730b7..b347ee6 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -176,7 +176,7 @@ static int dispatch_rqueue(sd_netlink *nl, sd_netlink_message **ret) {
assert(nl);
assert(ret);
- if (ordered_set_size(nl->rqueue) <= 0) {
+ if (ordered_set_isempty(nl->rqueue)) {
/* Try to read a new message */
r = socket_read_message(nl);
if (r == -ENOBUFS) /* FIXME: ignore buffer overruns for now */
@@ -443,7 +443,7 @@ int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {
assert_return(nl, -EINVAL);
assert_return(!netlink_pid_changed(nl), -ECHILD);
- if (ordered_set_size(nl->rqueue) > 0)
+ if (!ordered_set_isempty(nl->rqueue))
return 0;
r = netlink_poll(nl, false, timeout_usec);
@@ -623,7 +623,7 @@ int sd_netlink_get_events(sd_netlink *nl) {
assert_return(nl, -EINVAL);
assert_return(!netlink_pid_changed(nl), -ECHILD);
- return ordered_set_size(nl->rqueue) == 0 ? POLLIN : 0;
+ return ordered_set_isempty(nl->rqueue) ? POLLIN : 0;
}
int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *timeout_usec) {
@@ -633,7 +633,7 @@ int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *timeout_usec) {
assert_return(timeout_usec, -EINVAL);
assert_return(!netlink_pid_changed(nl), -ECHILD);
- if (ordered_set_size(nl->rqueue) > 0) {
+ if (!ordered_set_isempty(nl->rqueue)) {
*timeout_usec = 0;
return 1;
}
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index 13aedc4..cf19c48 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/* Make sure the net/if.h header is included before any linux/ one */
#include <net/if.h>
#include <netinet/ether.h>
#include <netinet/in.h>
@@ -681,6 +682,19 @@ TEST(rtnl_set_link_name) {
_cleanup_free_ char *resolved = NULL;
assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-additional-name", &resolved) == ifindex);
assert_se(streq_ptr(resolved, "test-shortname"));
+ resolved = mfree(resolved);
+
+ assert_se(rtnl_rename_link(&rtnl, "test-shortname", "test-shortname") >= 0);
+ assert_se(rtnl_rename_link(&rtnl, "test-shortname", "test-shortname2") >= 0);
+ assert_se(rtnl_rename_link(NULL, "test-shortname2", "test-shortname3") >= 0);
+
+ assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-additional-name", &resolved) == ifindex);
+ assert_se(streq_ptr(resolved, "test-shortname3"));
+ resolved = mfree(resolved);
+
+ assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-shortname3", &resolved) == ifindex);
+ assert_se(streq_ptr(resolved, "test-shortname3"));
+ resolved = mfree(resolved);
}
DEFINE_TEST_MAIN(LOG_DEBUG);