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:
@@ -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,
|
||||
|
@@ -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,
|
||||
|
Reference in New Issue
Block a user