sd-netlink: unify network interface name getter and resolvers

This makes rtnl_resolve_interface() always check the existence of the
resolved interface, which previously did not when a decimal formatted
ifindex is provided, e.g. "1" or "42".
This commit is contained in:
Yu Watanabe
2024-01-30 20:37:04 +09:00
parent 9561f24282
commit 4e235561d6
3 changed files with 198 additions and 134 deletions
+148 -118
View File
@@ -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;
@@ -242,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,
@@ -374,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,
+39 -5
View File
@@ -19,6 +19,22 @@ typedef struct RouteVia {
union in_addr_union address;
} _packed_ RouteVia;
int rtnl_get_ifname_full(sd_netlink **rtnl, int ifindex, char **ret_name, char ***ret_altnames);
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 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) {
@@ -35,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,