Commit e9c130ad authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bridge-global-mcast'



Nikolay Aleksandrov says:

====================
net: bridge: vlan: add global mcast options

This is the first follow-up set after the support for per-vlan multicast
contexts which extends global vlan options to support bridge's multicast
config per-vlan, it enables user-space to change and dump the already
existing bridge vlan multicast context options. The global option patches
(01 - 09 and 12-13) follow a similar pattern of changing current mcast
functions to take multicast context instead of a port/bridge directly.
Option equality checks have been added for dumping vlan range compression.
The last 2 patches extend the mcast router dump support so it can be
re-used when dumping vlan config.

patches 01 - 09: add support for various mcast options
patches 10 - 11: prepare for per-vlan querier control
patches 12 - 13: add support for querier control and router control
patches 14 - 15: add support for dumping per-vlan router ports

Next patch-sets:
 - per-port/vlan router option config
 - iproute2 support for all new vlan options
 - selftests
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6899192f dc002875
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -549,6 +549,20 @@ enum {
	BRIDGE_VLANDB_GOPTS_ID,
	BRIDGE_VLANDB_GOPTS_RANGE,
	BRIDGE_VLANDB_GOPTS_MCAST_SNOOPING,
	BRIDGE_VLANDB_GOPTS_MCAST_IGMP_VERSION,
	BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION,
	BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_CNT,
	BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_CNT,
	BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_INTVL,
	BRIDGE_VLANDB_GOPTS_PAD,
	BRIDGE_VLANDB_GOPTS_MCAST_MEMBERSHIP_INTVL,
	BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL,
	BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL,
	BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL,
	BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL,
	BRIDGE_VLANDB_GOPTS_MCAST_QUERIER,
	BRIDGE_VLANDB_GOPTS_MCAST_ROUTER,
	BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS,
	__BRIDGE_VLANDB_GOPTS_MAX
};
#define BRIDGE_VLANDB_GOPTS_MAX (__BRIDGE_VLANDB_GOPTS_MAX - 1)
+32 −28
Original line number Diff line number Diff line
@@ -16,57 +16,59 @@

#include "br_private.h"

static bool br_rports_have_mc_router(struct net_bridge_mcast *brmctx)
{
#if IS_ENABLED(CONFIG_IPV6)
	return !hlist_empty(&brmctx->ip4_mc_router_list) ||
	       !hlist_empty(&brmctx->ip6_mc_router_list);
#else
	return !hlist_empty(&brmctx->ip4_mc_router_list);
#endif
}

static bool
br_ip4_rports_get_timer(struct net_bridge_port *port, unsigned long *timer)
br_ip4_rports_get_timer(struct net_bridge_mcast_port *pmctx,
			unsigned long *timer)
{
	*timer = br_timer_value(&port->multicast_ctx.ip4_mc_router_timer);
	return !hlist_unhashed(&port->multicast_ctx.ip4_rlist);
	*timer = br_timer_value(&pmctx->ip4_mc_router_timer);
	return !hlist_unhashed(&pmctx->ip4_rlist);
}

static bool
br_ip6_rports_get_timer(struct net_bridge_port *port, unsigned long *timer)
br_ip6_rports_get_timer(struct net_bridge_mcast_port *pmctx,
			unsigned long *timer)
{
#if IS_ENABLED(CONFIG_IPV6)
	*timer = br_timer_value(&port->multicast_ctx.ip6_mc_router_timer);
	return !hlist_unhashed(&port->multicast_ctx.ip6_rlist);
	*timer = br_timer_value(&pmctx->ip6_mc_router_timer);
	return !hlist_unhashed(&pmctx->ip6_rlist);
#else
	*timer = 0;
	return false;
#endif
}

static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
			       struct net_device *dev)
int br_rports_fill_info(struct sk_buff *skb,
			const struct net_bridge_mcast *brmctx)
{
	struct net_bridge *br = netdev_priv(dev);
	u16 vid = brmctx->vlan ? brmctx->vlan->vid : 0;
	bool have_ip4_mc_rtr, have_ip6_mc_rtr;
	unsigned long ip4_timer, ip6_timer;
	struct nlattr *nest, *port_nest;
	struct net_bridge_port *p;

	if (!br->multicast_ctx.multicast_router)
		return 0;

	if (!br_rports_have_mc_router(&br->multicast_ctx))
	if (!brmctx->multicast_router || !br_rports_have_mc_router(brmctx))
		return 0;

	nest = nla_nest_start_noflag(skb, MDBA_ROUTER);
	if (nest == NULL)
		return -EMSGSIZE;

	list_for_each_entry_rcu(p, &br->port_list, list) {
		have_ip4_mc_rtr = br_ip4_rports_get_timer(p, &ip4_timer);
		have_ip6_mc_rtr = br_ip6_rports_get_timer(p, &ip6_timer);
	list_for_each_entry_rcu(p, &brmctx->br->port_list, list) {
		struct net_bridge_mcast_port *pmctx;

		if (vid) {
			struct net_bridge_vlan *v;

			v = br_vlan_find(nbp_vlan_group(p), vid);
			if (!v)
				continue;
			pmctx = &v->port_mcast_ctx;
		} else {
			pmctx = &p->multicast_ctx;
		}

		have_ip4_mc_rtr = br_ip4_rports_get_timer(pmctx, &ip4_timer);
		have_ip6_mc_rtr = br_ip6_rports_get_timer(pmctx, &ip6_timer);

		if (!have_ip4_mc_rtr && !have_ip6_mc_rtr)
			continue;
@@ -85,7 +87,8 @@ static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
				 ip4_timer)) ||
		    (have_ip6_mc_rtr &&
		     nla_put_u32(skb, MDBA_ROUTER_PATTR_INET6_TIMER,
				 ip6_timer))) {
				 ip6_timer)) ||
		    (vid && nla_put_u16(skb, MDBA_ROUTER_PATTR_VID, vid))) {
			nla_nest_cancel(skb, port_nest);
			goto fail;
		}
@@ -390,6 +393,7 @@ static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb)

	for_each_netdev_rcu(net, dev) {
		if (dev->priv_flags & IFF_EBRIDGE) {
			struct net_bridge *br = netdev_priv(dev);
			struct br_port_msg *bpm;

			if (idx < s_idx)
@@ -406,7 +410,7 @@ static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
			bpm->ifindex = dev->ifindex;
			if (br_mdb_fill_info(skb, cb, dev) < 0)
				goto out;
			if (br_rports_fill_info(skb, cb, dev) < 0)
			if (br_rports_fill_info(skb, &br->multicast_ctx) < 0)
				goto out;

			cb->args[1] = 0;
+38 −33
Original line number Diff line number Diff line
@@ -1628,7 +1628,8 @@ static void __br_multicast_send_query(struct net_bridge_mcast *brmctx,
	struct sk_buff *skb;
	u8 igmp_type;

	if (!br_multicast_ctx_should_use(brmctx, pmctx))
	if (!br_multicast_ctx_should_use(brmctx, pmctx) ||
	    !br_multicast_ctx_matches_vlan_snooping(brmctx))
		return;

again_under_lmqt:
@@ -1668,7 +1669,7 @@ static void br_multicast_send_query(struct net_bridge_mcast *brmctx,

	if (!br_multicast_ctx_should_use(brmctx, pmctx) ||
	    !br_opt_get(brmctx->br, BROPT_MULTICAST_ENABLED) ||
	    !br_opt_get(brmctx->br, BROPT_MULTICAST_QUERIER))
	    !brmctx->multicast_querier)
		return;

	memset(&br_group.dst, 0, sizeof(br_group.dst));
@@ -1747,14 +1748,16 @@ static void br_multicast_port_group_rexmit(struct timer_list *t)

	spin_lock(&br->multicast_lock);
	if (!netif_running(br->dev) || hlist_unhashed(&pg->mglist) ||
	    !br_opt_get(br, BROPT_MULTICAST_ENABLED) ||
	    !br_opt_get(br, BROPT_MULTICAST_QUERIER))
	    !br_opt_get(br, BROPT_MULTICAST_ENABLED))
		goto out;

	pmctx = br_multicast_pg_to_port_ctx(pg);
	if (!pmctx)
		goto out;
	brmctx = br_multicast_port_ctx_get_global(pmctx);
	if (!brmctx->multicast_querier)
		goto out;

	if (pg->key.addr.proto == htons(ETH_P_IP))
		other_query = &brmctx->ip4_other_query;
#if IS_ENABLED(CONFIG_IPV6)
@@ -1974,8 +1977,7 @@ static void __grp_src_query_marked_and_rexmit(struct net_bridge_mcast *brmctx,
		if (ent->flags & BR_SGRP_F_SEND) {
			ent->flags &= ~BR_SGRP_F_SEND;
			if (ent->timer.expires > lmqt) {
				if (br_opt_get(brmctx->br,
					       BROPT_MULTICAST_QUERIER) &&
				if (brmctx->multicast_querier &&
				    other_query &&
				    !timer_pending(&other_query->timer))
					ent->src_query_rexmit_cnt = lmqc;
@@ -1984,7 +1986,7 @@ static void __grp_src_query_marked_and_rexmit(struct net_bridge_mcast *brmctx,
		}
	}

	if (!br_opt_get(brmctx->br, BROPT_MULTICAST_QUERIER) ||
	if (!brmctx->multicast_querier ||
	    !other_query || timer_pending(&other_query->timer))
		return;

@@ -2015,7 +2017,7 @@ static void __grp_send_query_and_rexmit(struct net_bridge_mcast *brmctx,
		other_query = &brmctx->ip6_other_query;
#endif

	if (br_opt_get(brmctx->br, BROPT_MULTICAST_QUERIER) &&
	if (brmctx->multicast_querier &&
	    other_query && !timer_pending(&other_query->timer)) {
		lmi = now + brmctx->multicast_last_member_interval;
		pg->grp_query_rexmit_cnt = brmctx->multicast_last_member_count - 1;
@@ -3316,7 +3318,7 @@ br_multicast_leave_group(struct net_bridge_mcast *brmctx,
	if (timer_pending(&other_query->timer))
		goto out;

	if (br_opt_get(brmctx->br, BROPT_MULTICAST_QUERIER)) {
	if (brmctx->multicast_querier) {
		__br_multicast_send_query(brmctx, pmctx, NULL, NULL, &mp->addr,
					  false, 0, NULL);

@@ -3874,10 +3876,10 @@ void br_multicast_open(struct net_bridge *br)
					__br_multicast_open(&vlan->br_mcast_ctx);
			}
		}
	}

	} else {
		__br_multicast_open(&br->multicast_ctx);
	}
}

static void __br_multicast_stop(struct net_bridge_mcast *brmctx)
{
@@ -4027,10 +4029,10 @@ void br_multicast_stop(struct net_bridge *br)
					__br_multicast_stop(&vlan->br_mcast_ctx);
			}
		}
	}

	} else {
		__br_multicast_stop(&br->multicast_ctx);
	}
}

void br_multicast_dev_del(struct net_bridge *br)
{
@@ -4051,17 +4053,16 @@ void br_multicast_dev_del(struct net_bridge *br)
	rcu_barrier();
}

int br_multicast_set_router(struct net_bridge *br, unsigned long val)
int br_multicast_set_router(struct net_bridge_mcast *brmctx, unsigned long val)
{
	struct net_bridge_mcast *brmctx = &br->multicast_ctx;
	int err = -EINVAL;

	spin_lock_bh(&br->multicast_lock);
	spin_lock_bh(&brmctx->br->multicast_lock);

	switch (val) {
	case MDB_RTR_TYPE_DISABLED:
	case MDB_RTR_TYPE_PERM:
		br_mc_router_state_change(br, val == MDB_RTR_TYPE_PERM);
		br_mc_router_state_change(brmctx->br, val == MDB_RTR_TYPE_PERM);
		del_timer(&brmctx->ip4_mc_router_timer);
#if IS_ENABLED(CONFIG_IPV6)
		del_timer(&brmctx->ip6_mc_router_timer);
@@ -4071,13 +4072,13 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val)
		break;
	case MDB_RTR_TYPE_TEMP_QUERY:
		if (brmctx->multicast_router != MDB_RTR_TYPE_TEMP_QUERY)
			br_mc_router_state_change(br, false);
			br_mc_router_state_change(brmctx->br, false);
		brmctx->multicast_router = val;
		err = 0;
		break;
	}

	spin_unlock_bh(&br->multicast_lock);
	spin_unlock_bh(&brmctx->br->multicast_lock);

	return err;
}
@@ -4174,6 +4175,9 @@ static void br_multicast_start_querier(struct net_bridge_mcast *brmctx,
{
	struct net_bridge_port *port;

	if (!br_multicast_ctx_matches_vlan_snooping(brmctx))
		return;

	__br_multicast_open_query(brmctx->br, query);

	rcu_read_lock();
@@ -4292,18 +4296,17 @@ bool br_multicast_router(const struct net_device *dev)
}
EXPORT_SYMBOL_GPL(br_multicast_router);

int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
int br_multicast_set_querier(struct net_bridge_mcast *brmctx, unsigned long val)
{
	struct net_bridge_mcast *brmctx = &br->multicast_ctx;
	unsigned long max_delay;

	val = !!val;

	spin_lock_bh(&br->multicast_lock);
	if (br_opt_get(br, BROPT_MULTICAST_QUERIER) == val)
	spin_lock_bh(&brmctx->br->multicast_lock);
	if (brmctx->multicast_querier == val)
		goto unlock;

	br_opt_toggle(br, BROPT_MULTICAST_QUERIER, !!val);
	WRITE_ONCE(brmctx->multicast_querier, val);
	if (!val)
		goto unlock;

@@ -4322,12 +4325,13 @@ int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
#endif

unlock:
	spin_unlock_bh(&br->multicast_lock);
	spin_unlock_bh(&brmctx->br->multicast_lock);

	return 0;
}

int br_multicast_set_igmp_version(struct net_bridge *br, unsigned long val)
int br_multicast_set_igmp_version(struct net_bridge_mcast *brmctx,
				  unsigned long val)
{
	/* Currently we support only version 2 and 3 */
	switch (val) {
@@ -4338,15 +4342,16 @@ int br_multicast_set_igmp_version(struct net_bridge *br, unsigned long val)
		return -EINVAL;
	}

	spin_lock_bh(&br->multicast_lock);
	br->multicast_ctx.multicast_igmp_version = val;
	spin_unlock_bh(&br->multicast_lock);
	spin_lock_bh(&brmctx->br->multicast_lock);
	brmctx->multicast_igmp_version = val;
	spin_unlock_bh(&brmctx->br->multicast_lock);

	return 0;
}

#if IS_ENABLED(CONFIG_IPV6)
int br_multicast_set_mld_version(struct net_bridge *br, unsigned long val)
int br_multicast_set_mld_version(struct net_bridge_mcast *brmctx,
				 unsigned long val)
{
	/* Currently we support version 1 and 2 */
	switch (val) {
@@ -4357,9 +4362,9 @@ int br_multicast_set_mld_version(struct net_bridge *br, unsigned long val)
		return -EINVAL;
	}

	spin_lock_bh(&br->multicast_lock);
	br->multicast_ctx.multicast_mld_version = val;
	spin_unlock_bh(&br->multicast_lock);
	spin_lock_bh(&brmctx->br->multicast_lock);
	brmctx->multicast_mld_version = val;
	spin_unlock_bh(&brmctx->br->multicast_lock);

	return 0;
}
+9 −5
Original line number Diff line number Diff line
@@ -1286,7 +1286,8 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
	if (data[IFLA_BR_MCAST_ROUTER]) {
		u8 multicast_router = nla_get_u8(data[IFLA_BR_MCAST_ROUTER]);

		err = br_multicast_set_router(br, multicast_router);
		err = br_multicast_set_router(&br->multicast_ctx,
					      multicast_router);
		if (err)
			return err;
	}
@@ -1309,7 +1310,8 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
	if (data[IFLA_BR_MCAST_QUERIER]) {
		u8 mcast_querier = nla_get_u8(data[IFLA_BR_MCAST_QUERIER]);

		err = br_multicast_set_querier(br, mcast_querier);
		err = br_multicast_set_querier(&br->multicast_ctx,
					       mcast_querier);
		if (err)
			return err;
	}
@@ -1380,7 +1382,8 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
		__u8 igmp_version;

		igmp_version = nla_get_u8(data[IFLA_BR_MCAST_IGMP_VERSION]);
		err = br_multicast_set_igmp_version(br, igmp_version);
		err = br_multicast_set_igmp_version(&br->multicast_ctx,
						    igmp_version);
		if (err)
			return err;
	}
@@ -1390,7 +1393,8 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
		__u8 mld_version;

		mld_version = nla_get_u8(data[IFLA_BR_MCAST_MLD_VERSION]);
		err = br_multicast_set_mld_version(br, mld_version);
		err = br_multicast_set_mld_version(&br->multicast_ctx,
						   mld_version);
		if (err)
			return err;
	}
@@ -1573,7 +1577,7 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev)
	    nla_put_u8(skb, IFLA_BR_MCAST_QUERY_USE_IFADDR,
		       br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR)) ||
	    nla_put_u8(skb, IFLA_BR_MCAST_QUERIER,
		       br_opt_get(br, BROPT_MULTICAST_QUERIER)) ||
		       br->multicast_ctx.multicast_querier) ||
	    nla_put_u8(skb, IFLA_BR_MCAST_STATS_ENABLED,
		       br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)) ||
	    nla_put_u32(skb, IFLA_BR_MCAST_HASH_ELASTICITY, RHT_ELASTICITY) ||
+72 −6
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@ struct net_bridge_mcast {
	u32				multicast_last_member_count;
	u32				multicast_startup_query_count;

	u8				multicast_querier;
	u8				multicast_igmp_version;
	u8				multicast_router;
#if IS_ENABLED(CONFIG_IPV6)
@@ -431,7 +432,6 @@ enum net_bridge_opts {
	BROPT_NF_CALL_ARPTABLES,
	BROPT_GROUP_ADDR_SET,
	BROPT_MULTICAST_ENABLED,
	BROPT_MULTICAST_QUERIER,
	BROPT_MULTICAST_QUERY_USE_IFADDR,
	BROPT_MULTICAST_STATS_ENABLED,
	BROPT_HAS_IPV6_ADDR,
@@ -877,15 +877,17 @@ void br_multicast_dev_del(struct net_bridge *br);
void br_multicast_flood(struct net_bridge_mdb_entry *mdst, struct sk_buff *skb,
			struct net_bridge_mcast *brmctx,
			bool local_rcv, bool local_orig);
int br_multicast_set_router(struct net_bridge *br, unsigned long val);
int br_multicast_set_router(struct net_bridge_mcast *brmctx, unsigned long val);
int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val);
int br_multicast_toggle(struct net_bridge *br, unsigned long val,
			struct netlink_ext_ack *extack);
int br_multicast_set_querier(struct net_bridge *br, unsigned long val);
int br_multicast_set_querier(struct net_bridge_mcast *brmctx, unsigned long val);
int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val);
int br_multicast_set_igmp_version(struct net_bridge *br, unsigned long val);
int br_multicast_set_igmp_version(struct net_bridge_mcast *brmctx,
				  unsigned long val);
#if IS_ENABLED(CONFIG_IPV6)
int br_multicast_set_mld_version(struct net_bridge *br, unsigned long val);
int br_multicast_set_mld_version(struct net_bridge_mcast *brmctx,
				 unsigned long val);
#endif
struct net_bridge_mdb_entry *
br_mdb_ip_get(struct net_bridge *br, struct br_ip *dst);
@@ -943,6 +945,8 @@ bool br_multicast_toggle_global_vlan(struct net_bridge_vlan *vlan, bool on);
int br_mdb_replay(struct net_device *br_dev, struct net_device *dev,
		  const void *ctx, bool adding, struct notifier_block *nb,
		  struct netlink_ext_ack *extack);
int br_rports_fill_info(struct sk_buff *skb,
			const struct net_bridge_mcast *brmctx);

static inline bool br_group_is_l2(const struct br_ip *group)
{
@@ -1026,7 +1030,7 @@ __br_multicast_querier_exists(struct net_bridge_mcast *brmctx,
{
	bool own_querier_enabled;

	if (br_opt_get(brmctx->br, BROPT_MULTICAST_QUERIER)) {
	if (brmctx->multicast_querier) {
		if (is_ipv6 && !br_opt_get(brmctx->br, BROPT_HAS_IPV6_ADDR))
			own_querier_enabled = false;
		else
@@ -1165,6 +1169,61 @@ br_multicast_port_ctx_state_stopped(const struct net_bridge_mcast_port *pmctx)
	       (br_multicast_port_ctx_is_vlan(pmctx) &&
		pmctx->vlan->state == BR_STATE_BLOCKING);
}

static inline bool
br_rports_have_mc_router(const struct net_bridge_mcast *brmctx)
{
#if IS_ENABLED(CONFIG_IPV6)
	return !hlist_empty(&brmctx->ip4_mc_router_list) ||
	       !hlist_empty(&brmctx->ip6_mc_router_list);
#else
	return !hlist_empty(&brmctx->ip4_mc_router_list);
#endif
}

static inline bool
br_multicast_ctx_options_equal(const struct net_bridge_mcast *brmctx1,
			       const struct net_bridge_mcast *brmctx2)
{
	return brmctx1->multicast_igmp_version ==
	       brmctx2->multicast_igmp_version &&
	       brmctx1->multicast_last_member_count ==
	       brmctx2->multicast_last_member_count &&
	       brmctx1->multicast_startup_query_count ==
	       brmctx2->multicast_startup_query_count &&
	       brmctx1->multicast_last_member_interval ==
	       brmctx2->multicast_last_member_interval &&
	       brmctx1->multicast_membership_interval ==
	       brmctx2->multicast_membership_interval &&
	       brmctx1->multicast_querier_interval ==
	       brmctx2->multicast_querier_interval &&
	       brmctx1->multicast_query_interval ==
	       brmctx2->multicast_query_interval &&
	       brmctx1->multicast_query_response_interval ==
	       brmctx2->multicast_query_response_interval &&
	       brmctx1->multicast_startup_query_interval ==
	       brmctx2->multicast_startup_query_interval &&
	       brmctx1->multicast_querier == brmctx2->multicast_querier &&
	       brmctx1->multicast_router == brmctx2->multicast_router &&
	       !br_rports_have_mc_router(brmctx1) &&
	       !br_rports_have_mc_router(brmctx2) &&
#if IS_ENABLED(CONFIG_IPV6)
	       brmctx1->multicast_mld_version ==
	       brmctx2->multicast_mld_version &&
#endif
	       true;
}

static inline bool
br_multicast_ctx_matches_vlan_snooping(const struct net_bridge_mcast *brmctx)
{
	bool vlan_snooping_enabled;

	vlan_snooping_enabled = !!br_opt_get(brmctx->br,
					     BROPT_MCAST_VLAN_SNOOPING_ENABLED);

	return !!(vlan_snooping_enabled == br_multicast_ctx_is_vlan(brmctx));
}
#else
static inline int br_multicast_rcv(struct net_bridge_mcast **brmctx,
				   struct net_bridge_mcast_port **pmctx,
@@ -1330,6 +1389,13 @@ static inline int br_mdb_replay(struct net_device *br_dev,
{
	return -EOPNOTSUPP;
}

static inline bool
br_multicast_ctx_options_equal(const struct net_bridge_mcast *brmctx1,
			       const struct net_bridge_mcast *brmctx2)
{
	return true;
}
#endif

/* br_vlan.c */
Loading