Skip to content

Commit bc4c48e

Browse files
committed
Merge branch 'mdb-get'
Ido Schimmel says: ==================== Add MDB get support This patchset adds MDB get support, allowing user space to request a single MDB entry to be retrieved instead of dumping the entire MDB. Support is added in both the bridge and VXLAN drivers. Patches #1-gregkh#6 are small preparations in both drivers. Patches gregkh#7-gregkh#8 add the required uAPI attributes for the new functionality and the MDB get net device operation (NDO), respectively. Patches gregkh#9-gregkh#10 implement the MDB get NDO in both drivers. Patch gregkh#11 registers a handler for RTM_GETMDB messages in rtnetlink core. The handler derives the net device from the ifindex specified in the ancillary header and invokes its MDB get NDO. Patches gregkh#12-gregkh#13 add selftests by converting tests that use MDB dump with grep to the new MDB get functionality. iproute2 changes can be found here [1]. v2: * Patch gregkh#7: Add a comment to describe attributes structure. * Patch gregkh#9: Add a comment above spin_lock_bh(). [1] https://github.com/idosch/iproute2/tree/submit/mdb_get_v1 ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents eff8313 + 0514dd0 commit bc4c48e

File tree

13 files changed

+608
-199
lines changed

13 files changed

+608
-199
lines changed

drivers/net/vxlan/vxlan_core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3226,6 +3226,7 @@ static const struct net_device_ops vxlan_netdev_ether_ops = {
32263226
.ndo_mdb_add = vxlan_mdb_add,
32273227
.ndo_mdb_del = vxlan_mdb_del,
32283228
.ndo_mdb_dump = vxlan_mdb_dump,
3229+
.ndo_mdb_get = vxlan_mdb_get,
32293230
.ndo_fill_metadata_dst = vxlan_fill_metadata_dst,
32303231
};
32313232

drivers/net/vxlan/vxlan_mdb.c

Lines changed: 173 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -370,12 +370,10 @@ static bool vxlan_mdb_is_valid_source(const struct nlattr *attr, __be16 proto,
370370
return true;
371371
}
372372

373-
static void vxlan_mdb_config_group_set(struct vxlan_mdb_config *cfg,
374-
const struct br_mdb_entry *entry,
375-
const struct nlattr *source_attr)
373+
static void vxlan_mdb_group_set(struct vxlan_mdb_entry_key *group,
374+
const struct br_mdb_entry *entry,
375+
const struct nlattr *source_attr)
376376
{
377-
struct vxlan_mdb_entry_key *group = &cfg->group;
378-
379377
switch (entry->addr.proto) {
380378
case htons(ETH_P_IP):
381379
group->dst.sa.sa_family = AF_INET;
@@ -503,7 +501,7 @@ static int vxlan_mdb_config_attrs_init(struct vxlan_mdb_config *cfg,
503501
entry->addr.proto, extack))
504502
return -EINVAL;
505503

506-
vxlan_mdb_config_group_set(cfg, entry, mdbe_attrs[MDBE_ATTR_SOURCE]);
504+
vxlan_mdb_group_set(&cfg->group, entry, mdbe_attrs[MDBE_ATTR_SOURCE]);
507505

508506
/* rtnetlink code only validates that IPv4 group address is
509507
* multicast.
@@ -927,23 +925,20 @@ vxlan_mdb_nlmsg_src_list_size(const struct vxlan_mdb_entry_key *group,
927925
return nlmsg_size;
928926
}
929927

930-
static size_t vxlan_mdb_nlmsg_size(const struct vxlan_dev *vxlan,
931-
const struct vxlan_mdb_entry *mdb_entry,
932-
const struct vxlan_mdb_remote *remote)
928+
static size_t
929+
vxlan_mdb_nlmsg_remote_size(const struct vxlan_dev *vxlan,
930+
const struct vxlan_mdb_entry *mdb_entry,
931+
const struct vxlan_mdb_remote *remote)
933932
{
934933
const struct vxlan_mdb_entry_key *group = &mdb_entry->key;
935934
struct vxlan_rdst *rd = rtnl_dereference(remote->rd);
936935
size_t nlmsg_size;
937936

938-
nlmsg_size = NLMSG_ALIGN(sizeof(struct br_port_msg)) +
939-
/* MDBA_MDB */
940-
nla_total_size(0) +
941-
/* MDBA_MDB_ENTRY */
942-
nla_total_size(0) +
943937
/* MDBA_MDB_ENTRY_INFO */
944-
nla_total_size(sizeof(struct br_mdb_entry)) +
938+
nlmsg_size = nla_total_size(sizeof(struct br_mdb_entry)) +
945939
/* MDBA_MDB_EATTR_TIMER */
946940
nla_total_size(sizeof(u32));
941+
947942
/* MDBA_MDB_EATTR_SOURCE */
948943
if (vxlan_mdb_is_sg(group))
949944
nlmsg_size += nla_total_size(vxlan_addr_size(&group->dst));
@@ -971,6 +966,19 @@ static size_t vxlan_mdb_nlmsg_size(const struct vxlan_dev *vxlan,
971966
return nlmsg_size;
972967
}
973968

969+
static size_t vxlan_mdb_nlmsg_size(const struct vxlan_dev *vxlan,
970+
const struct vxlan_mdb_entry *mdb_entry,
971+
const struct vxlan_mdb_remote *remote)
972+
{
973+
return NLMSG_ALIGN(sizeof(struct br_port_msg)) +
974+
/* MDBA_MDB */
975+
nla_total_size(0) +
976+
/* MDBA_MDB_ENTRY */
977+
nla_total_size(0) +
978+
/* Remote entry */
979+
vxlan_mdb_nlmsg_remote_size(vxlan, mdb_entry, remote);
980+
}
981+
974982
static int vxlan_mdb_nlmsg_fill(const struct vxlan_dev *vxlan,
975983
struct sk_buff *skb,
976984
const struct vxlan_mdb_entry *mdb_entry,
@@ -1298,6 +1306,156 @@ int vxlan_mdb_del(struct net_device *dev, struct nlattr *tb[],
12981306
return err;
12991307
}
13001308

1309+
static const struct nla_policy vxlan_mdbe_attrs_get_pol[MDBE_ATTR_MAX + 1] = {
1310+
[MDBE_ATTR_SOURCE] = NLA_POLICY_RANGE(NLA_BINARY,
1311+
sizeof(struct in_addr),
1312+
sizeof(struct in6_addr)),
1313+
[MDBE_ATTR_SRC_VNI] = NLA_POLICY_FULL_RANGE(NLA_U32, &vni_range),
1314+
};
1315+
1316+
static int vxlan_mdb_get_parse(struct net_device *dev, struct nlattr *tb[],
1317+
struct vxlan_mdb_entry_key *group,
1318+
struct netlink_ext_ack *extack)
1319+
{
1320+
struct br_mdb_entry *entry = nla_data(tb[MDBA_GET_ENTRY]);
1321+
struct nlattr *mdbe_attrs[MDBE_ATTR_MAX + 1];
1322+
struct vxlan_dev *vxlan = netdev_priv(dev);
1323+
int err;
1324+
1325+
memset(group, 0, sizeof(*group));
1326+
group->vni = vxlan->default_dst.remote_vni;
1327+
1328+
if (!tb[MDBA_GET_ENTRY_ATTRS]) {
1329+
vxlan_mdb_group_set(group, entry, NULL);
1330+
return 0;
1331+
}
1332+
1333+
err = nla_parse_nested(mdbe_attrs, MDBE_ATTR_MAX,
1334+
tb[MDBA_GET_ENTRY_ATTRS],
1335+
vxlan_mdbe_attrs_get_pol, extack);
1336+
if (err)
1337+
return err;
1338+
1339+
if (mdbe_attrs[MDBE_ATTR_SOURCE] &&
1340+
!vxlan_mdb_is_valid_source(mdbe_attrs[MDBE_ATTR_SOURCE],
1341+
entry->addr.proto, extack))
1342+
return -EINVAL;
1343+
1344+
vxlan_mdb_group_set(group, entry, mdbe_attrs[MDBE_ATTR_SOURCE]);
1345+
1346+
if (mdbe_attrs[MDBE_ATTR_SRC_VNI])
1347+
group->vni =
1348+
cpu_to_be32(nla_get_u32(mdbe_attrs[MDBE_ATTR_SRC_VNI]));
1349+
1350+
return 0;
1351+
}
1352+
1353+
static struct sk_buff *
1354+
vxlan_mdb_get_reply_alloc(const struct vxlan_dev *vxlan,
1355+
const struct vxlan_mdb_entry *mdb_entry)
1356+
{
1357+
struct vxlan_mdb_remote *remote;
1358+
size_t nlmsg_size;
1359+
1360+
nlmsg_size = NLMSG_ALIGN(sizeof(struct br_port_msg)) +
1361+
/* MDBA_MDB */
1362+
nla_total_size(0) +
1363+
/* MDBA_MDB_ENTRY */
1364+
nla_total_size(0);
1365+
1366+
list_for_each_entry(remote, &mdb_entry->remotes, list)
1367+
nlmsg_size += vxlan_mdb_nlmsg_remote_size(vxlan, mdb_entry,
1368+
remote);
1369+
1370+
return nlmsg_new(nlmsg_size, GFP_KERNEL);
1371+
}
1372+
1373+
static int
1374+
vxlan_mdb_get_reply_fill(const struct vxlan_dev *vxlan,
1375+
struct sk_buff *skb,
1376+
const struct vxlan_mdb_entry *mdb_entry,
1377+
u32 portid, u32 seq)
1378+
{
1379+
struct nlattr *mdb_nest, *mdb_entry_nest;
1380+
struct vxlan_mdb_remote *remote;
1381+
struct br_port_msg *bpm;
1382+
struct nlmsghdr *nlh;
1383+
int err;
1384+
1385+
nlh = nlmsg_put(skb, portid, seq, RTM_NEWMDB, sizeof(*bpm), 0);
1386+
if (!nlh)
1387+
return -EMSGSIZE;
1388+
1389+
bpm = nlmsg_data(nlh);
1390+
memset(bpm, 0, sizeof(*bpm));
1391+
bpm->family = AF_BRIDGE;
1392+
bpm->ifindex = vxlan->dev->ifindex;
1393+
mdb_nest = nla_nest_start_noflag(skb, MDBA_MDB);
1394+
if (!mdb_nest) {
1395+
err = -EMSGSIZE;
1396+
goto cancel;
1397+
}
1398+
mdb_entry_nest = nla_nest_start_noflag(skb, MDBA_MDB_ENTRY);
1399+
if (!mdb_entry_nest) {
1400+
err = -EMSGSIZE;
1401+
goto cancel;
1402+
}
1403+
1404+
list_for_each_entry(remote, &mdb_entry->remotes, list) {
1405+
err = vxlan_mdb_entry_info_fill(vxlan, skb, mdb_entry, remote);
1406+
if (err)
1407+
goto cancel;
1408+
}
1409+
1410+
nla_nest_end(skb, mdb_entry_nest);
1411+
nla_nest_end(skb, mdb_nest);
1412+
nlmsg_end(skb, nlh);
1413+
1414+
return 0;
1415+
1416+
cancel:
1417+
nlmsg_cancel(skb, nlh);
1418+
return err;
1419+
}
1420+
1421+
int vxlan_mdb_get(struct net_device *dev, struct nlattr *tb[], u32 portid,
1422+
u32 seq, struct netlink_ext_ack *extack)
1423+
{
1424+
struct vxlan_dev *vxlan = netdev_priv(dev);
1425+
struct vxlan_mdb_entry *mdb_entry;
1426+
struct vxlan_mdb_entry_key group;
1427+
struct sk_buff *skb;
1428+
int err;
1429+
1430+
ASSERT_RTNL();
1431+
1432+
err = vxlan_mdb_get_parse(dev, tb, &group, extack);
1433+
if (err)
1434+
return err;
1435+
1436+
mdb_entry = vxlan_mdb_entry_lookup(vxlan, &group);
1437+
if (!mdb_entry) {
1438+
NL_SET_ERR_MSG_MOD(extack, "MDB entry not found");
1439+
return -ENOENT;
1440+
}
1441+
1442+
skb = vxlan_mdb_get_reply_alloc(vxlan, mdb_entry);
1443+
if (!skb)
1444+
return -ENOMEM;
1445+
1446+
err = vxlan_mdb_get_reply_fill(vxlan, skb, mdb_entry, portid, seq);
1447+
if (err) {
1448+
NL_SET_ERR_MSG_MOD(extack, "Failed to fill MDB get reply");
1449+
goto free;
1450+
}
1451+
1452+
return rtnl_unicast(skb, dev_net(dev), portid);
1453+
1454+
free:
1455+
kfree_skb(skb);
1456+
return err;
1457+
}
1458+
13011459
struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
13021460
struct sk_buff *skb,
13031461
__be32 src_vni)

drivers/net/vxlan/vxlan_private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ int vxlan_mdb_add(struct net_device *dev, struct nlattr *tb[], u16 nlmsg_flags,
235235
struct netlink_ext_ack *extack);
236236
int vxlan_mdb_del(struct net_device *dev, struct nlattr *tb[],
237237
struct netlink_ext_ack *extack);
238+
int vxlan_mdb_get(struct net_device *dev, struct nlattr *tb[], u32 portid,
239+
u32 seq, struct netlink_ext_ack *extack);
238240
struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
239241
struct sk_buff *skb,
240242
__be32 src_vni);

include/linux/netdevice.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,6 +1609,10 @@ struct net_device_ops {
16091609
int (*ndo_mdb_dump)(struct net_device *dev,
16101610
struct sk_buff *skb,
16111611
struct netlink_callback *cb);
1612+
int (*ndo_mdb_get)(struct net_device *dev,
1613+
struct nlattr *tb[], u32 portid,
1614+
u32 seq,
1615+
struct netlink_ext_ack *extack);
16121616
int (*ndo_bridge_setlink)(struct net_device *dev,
16131617
struct nlmsghdr *nlh,
16141618
u16 flags,

include/uapi/linux/if_bridge.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,24 @@ enum {
723723
};
724724
#define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1)
725725

726+
/* [MDBA_GET_ENTRY] = {
727+
* struct br_mdb_entry
728+
* [MDBA_GET_ENTRY_ATTRS] = {
729+
* [MDBE_ATTR_SOURCE]
730+
* struct in_addr / struct in6_addr
731+
* [MDBE_ATTR_SRC_VNI]
732+
* u32
733+
* }
734+
* }
735+
*/
736+
enum {
737+
MDBA_GET_ENTRY_UNSPEC,
738+
MDBA_GET_ENTRY,
739+
MDBA_GET_ENTRY_ATTRS,
740+
__MDBA_GET_ENTRY_MAX,
741+
};
742+
#define MDBA_GET_ENTRY_MAX (__MDBA_GET_ENTRY_MAX - 1)
743+
726744
/* [MDBA_SET_ENTRY_ATTRS] = {
727745
* [MDBE_ATTR_xxx]
728746
* ...

net/bridge/br_device.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
9292
goto out;
9393
}
9494

95-
mdst = br_mdb_get(brmctx, skb, vid);
95+
mdst = br_mdb_entry_skb_get(brmctx, skb, vid);
9696
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
9797
br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst))
9898
br_multicast_flood(mdst, skb, brmctx, false, true);
@@ -472,6 +472,7 @@ static const struct net_device_ops br_netdev_ops = {
472472
.ndo_mdb_add = br_mdb_add,
473473
.ndo_mdb_del = br_mdb_del,
474474
.ndo_mdb_dump = br_mdb_dump,
475+
.ndo_mdb_get = br_mdb_get,
475476
.ndo_bridge_getlink = br_getlink,
476477
.ndo_bridge_setlink = br_setlink,
477478
.ndo_bridge_dellink = br_dellink,

net/bridge/br_input.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
175175

176176
switch (pkt_type) {
177177
case BR_PKT_MULTICAST:
178-
mdst = br_mdb_get(brmctx, skb, vid);
178+
mdst = br_mdb_entry_skb_get(brmctx, skb, vid);
179179
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
180180
br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) {
181181
if ((mdst && mdst->host_joined) ||

0 commit comments

Comments
 (0)