linux-platform: add helper function to query FDB table

The function introduced queries the FDB table via netlink socket. It
accepts a list of ifindexes to filter out the FDB content not related to
it. It returns an array of MAC addresses.

To cltarify this function is unusually exposed directly on
nm-linux-platform.h as we don't want this be part of the whole
NMPlatform object or cache. This, is an exception to the rule to
simplify the integration of this functionality on NetworkManager.

In addition, it also doesn't use the async mechanism that is widely used
on netlink communication across nm-linux-platform. Again, the reason is
to simplify its use, as async communication won't provide a benefit to
the use cases we have planned for this, i.e balance-slb RARP announcing.
This commit is contained in:
Fernando Fernandez Mancera
2024-11-07 09:09:50 +01:00
parent a63eec924c
commit 00f47efcb2
2 changed files with 126 additions and 0 deletions

View File

@@ -323,6 +323,10 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1));
#define IFLA_VF_VLAN_INFO_UNSPEC 0
#define IFLA_VF_VLAN_INFO 1
/*****************************************************************************/
#define NDA_CONTROLLER NDA_MASTER
/* valid for TRUST, SPOOFCHK, LINK_STATE, RSS_QUERY_EN */
struct _ifla_vf_setting {
guint32 vf;
@@ -10411,6 +10415,125 @@ link_get_driver_info(NMPlatform *platform,
/*****************************************************************************/
typedef struct {
int ifindexes_len;
int *ifindexes;
GHashTable *out_fdb_addrs;
} FdbData;
static int
parse_fdb_cb(const struct nl_msg *msg, void *arg)
{
struct nlmsghdr *nlh = nlmsg_hdr(msg);
struct ndmsg *ndmsg = NLMSG_DATA(nlh);
int from_ifindex = ndmsg->ndm_ifindex;
bool match = FALSE;
static const struct nla_policy policy[] = {
[NDA_LLADDR] = {.minlen = ETH_ALEN, .maxlen = ETH_ALEN},
[NDA_CONTROLLER] = {.type = NLA_U32},
};
struct nlattr *tb[G_N_ELEMENTS(policy)];
FdbData *data = arg;
int fdb_controller = -1;
if (nlmsg_parse_arr(nlh, sizeof(*ndmsg), tb, policy) < 0)
return NL_SKIP;
if (tb[NDA_CONTROLLER])
fdb_controller = nla_get_u32(tb[NDA_CONTROLLER]);
for (int i = 0; i < data->ifindexes_len; i++) {
int current_ifindex = data->ifindexes[i];
if (NM_IN_SET(current_ifindex, from_ifindex, fdb_controller)) {
match = TRUE;
break;
}
}
if (!match)
return NL_SKIP;
if (tb[NDA_LLADDR]) {
NMEtherAddr *hwaddr = g_new(NMEtherAddr, 1);
memcpy(hwaddr, nla_data(tb[NDA_LLADDR]), ETH_ALEN);
g_hash_table_add(data->out_fdb_addrs, hwaddr);
}
return NL_OK;
}
NMEtherAddr **
nm_linux_platform_get_link_fdb_table(NMPlatform *platform, int *ifindexes, guint ifindexes_len)
{
int nle;
struct nl_sock *sk = NULL;
nm_auto_nlmsg struct nl_msg *msg = NULL;
gs_unref_hashtable GHashTable *fdb_addrs = NULL;
FdbData data;
const struct ndmsg ndm = {
.ndm_family = AF_BRIDGE,
};
gpointer *ret = NULL;
nm_assert(ifindexes);
nm_assert(ifindexes_len >= 1);
fdb_addrs = g_hash_table_new_full((GHashFunc) nm_ether_addr_hash,
(GEqualFunc) nm_ether_addr_equal,
g_free,
NULL);
msg = nlmsg_alloc_new(0, RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP);
if (nlmsg_append_struct(msg, &ndm) < 0)
goto err;
nle = nl_socket_new(&sk, NETLINK_ROUTE, NL_SOCKET_FLAGS_DISABLE_MSG_PEEK, 0, 0);
if (nle < 0) {
_LOGD("get-link-fdb: error opening socket: %s (%d)", nm_strerror(nle), nle);
goto err;
}
nle = nl_send_auto(sk, msg);
if (nle < 0) {
_LOGD("get-link-fdb: failed sending request: %s (%d)", nm_strerror(nle), nle);
goto err;
}
data = ((FdbData) {
.ifindexes_len = ifindexes_len,
.ifindexes = ifindexes,
.out_fdb_addrs = fdb_addrs,
});
do {
nle = nl_recvmsgs(sk,
&((const struct nl_cb) {
.valid_cb = parse_fdb_cb,
.valid_arg = &data,
}));
} while (nle == -EAGAIN);
if (nle < 0) {
_LOGD("get-link-fdb: recv failed: %s (%d)", nm_strerror(nle), nle);
goto err;
}
ret = g_hash_table_get_keys_as_array(fdb_addrs, NULL);
g_hash_table_steal_all(fdb_addrs);
nl_socket_free(sk);
return NM_CAST_ALIGN(NMEtherAddr *, ret);
err:
if (sk)
nl_socket_free(sk);
return NULL;
}
/*****************************************************************************/
static gboolean
ip4_address_add(NMPlatform *platform,
int ifindex,

View File

@@ -25,6 +25,9 @@ GType nm_linux_platform_get_type(void);
struct _NMDedupMultiIndex;
NMEtherAddr **
nm_linux_platform_get_link_fdb_table(NMPlatform *platform, int *ifindexes, guint ifindexes_len);
NMPlatform *nm_linux_platform_new(struct _NMDedupMultiIndex *multi_idx,
gboolean log_with_ptr,
gboolean netns_support,