Skip to content

Commit

Permalink
net: bridge: mcast: add support for src list and filter mode dumping
Browse files Browse the repository at this point in the history
Support per port group src list (address and timer) and filter mode
dumping. Protected by either multicast_lock or rcu.

v3: add IPv6 support
v2: require RCU or multicast_lock to traverse src groups

Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Nikolay Aleksandrov authored and Jakub Kicinski committed Sep 7, 2020
1 parent 8b67177 commit 5205e91
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 2 deletions.
21 changes: 21 additions & 0 deletions include/uapi/linux/if_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -455,10 +455,31 @@ enum {
enum {
MDBA_MDB_EATTR_UNSPEC,
MDBA_MDB_EATTR_TIMER,
MDBA_MDB_EATTR_SRC_LIST,
MDBA_MDB_EATTR_GROUP_MODE,
__MDBA_MDB_EATTR_MAX
};
#define MDBA_MDB_EATTR_MAX (__MDBA_MDB_EATTR_MAX - 1)

/* per mdb entry source */
enum {
MDBA_MDB_SRCLIST_UNSPEC,
MDBA_MDB_SRCLIST_ENTRY,
__MDBA_MDB_SRCLIST_MAX
};
#define MDBA_MDB_SRCLIST_MAX (__MDBA_MDB_SRCLIST_MAX - 1)

/* per mdb entry per source attributes
* these are embedded in MDBA_MDB_SRCLIST_ENTRY
*/
enum {
MDBA_MDB_SRCATTR_UNSPEC,
MDBA_MDB_SRCATTR_ADDRESS,
MDBA_MDB_SRCATTR_TIMER,
__MDBA_MDB_SRCATTR_MAX
};
#define MDBA_MDB_SRCATTR_MAX (__MDBA_MDB_SRCATTR_MAX - 1)

/* multicast router types */
enum {
MDB_RTR_TYPE_DISABLED,
Expand Down
85 changes: 83 additions & 2 deletions net/bridge/br_mdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,67 @@ static void __mdb_entry_to_br_ip(struct br_mdb_entry *entry, struct br_ip *ip)
#endif
}

static int __mdb_fill_srcs(struct sk_buff *skb,
struct net_bridge_port_group *p)
{
struct net_bridge_group_src *ent;
struct nlattr *nest, *nest_ent;

if (hlist_empty(&p->src_list))
return 0;

nest = nla_nest_start(skb, MDBA_MDB_EATTR_SRC_LIST);
if (!nest)
return -EMSGSIZE;

hlist_for_each_entry_rcu(ent, &p->src_list, node,
lockdep_is_held(&p->port->br->multicast_lock)) {
nest_ent = nla_nest_start(skb, MDBA_MDB_SRCLIST_ENTRY);
if (!nest_ent)
goto out_cancel_err;
switch (ent->addr.proto) {
case htons(ETH_P_IP):
if (nla_put_in_addr(skb, MDBA_MDB_SRCATTR_ADDRESS,
ent->addr.u.ip4)) {
nla_nest_cancel(skb, nest_ent);
goto out_cancel_err;
}
break;
#if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6):
if (nla_put_in6_addr(skb, MDBA_MDB_SRCATTR_ADDRESS,
&ent->addr.u.ip6)) {
nla_nest_cancel(skb, nest_ent);
goto out_cancel_err;
}
break;
#endif
default:
nla_nest_cancel(skb, nest_ent);
continue;
}
if (nla_put_u32(skb, MDBA_MDB_SRCATTR_TIMER,
br_timer_value(&ent->timer))) {
nla_nest_cancel(skb, nest_ent);
goto out_cancel_err;
}
nla_nest_end(skb, nest_ent);
}

nla_nest_end(skb, nest);

return 0;

out_cancel_err:
nla_nest_cancel(skb, nest);
return -EMSGSIZE;
}

static int __mdb_fill_info(struct sk_buff *skb,
struct net_bridge_mdb_entry *mp,
struct net_bridge_port_group *p)
{
bool dump_srcs_mode = false;
struct timer_list *mtimer;
struct nlattr *nest_ent;
struct br_mdb_entry e;
Expand Down Expand Up @@ -119,6 +176,23 @@ static int __mdb_fill_info(struct sk_buff *skb,
nla_nest_cancel(skb, nest_ent);
return -EMSGSIZE;
}
switch (mp->addr.proto) {
case htons(ETH_P_IP):
dump_srcs_mode = !!(p && mp->br->multicast_igmp_version == 3);
break;
#if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6):
dump_srcs_mode = !!(p && mp->br->multicast_mld_version == 2);
break;
#endif
}
if (dump_srcs_mode &&
(__mdb_fill_srcs(skb, p) ||
nla_put_u8(skb, MDBA_MDB_EATTR_GROUP_MODE, p->filter_mode))) {
nla_nest_cancel(skb, nest_ent);
return -EMSGSIZE;
}

nla_nest_end(skb, nest_ent);

return 0;
Expand All @@ -127,7 +201,7 @@ static int __mdb_fill_info(struct sk_buff *skb,
static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
struct net_device *dev)
{
int idx = 0, s_idx = cb->args[1], err = 0;
int idx = 0, s_idx = cb->args[1], err = 0, pidx = 0, s_pidx = cb->args[2];
struct net_bridge *br = netdev_priv(dev);
struct net_bridge_mdb_entry *mp;
struct nlattr *nest, *nest2;
Expand All @@ -152,7 +226,7 @@ static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
break;
}

if (mp->host_joined) {
if (!s_pidx && mp->host_joined) {
err = __mdb_fill_info(skb, mp, NULL);
if (err) {
nla_nest_cancel(skb, nest2);
Expand All @@ -164,20 +238,27 @@ static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
pp = &p->next) {
if (!p->port)
continue;
if (pidx < s_pidx)
goto skip_pg;

err = __mdb_fill_info(skb, mp, p);
if (err) {
nla_nest_cancel(skb, nest2);
goto out;
}
skip_pg:
pidx++;
}
pidx = 0;
s_pidx = 0;
nla_nest_end(skb, nest2);
skip:
idx++;
}

out:
cb->args[1] = idx;
cb->args[2] = pidx;
nla_nest_end(skb, nest);
return err;
}
Expand Down

0 comments on commit 5205e91

Please sign in to comment.