Commit 1bc6cc4f authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'bridge-mcast-preparations-for-vxlan-mdb'

Ido Schimmel says:

====================
bridge: mcast: Preparations for VXLAN MDB

This patchset contains small preparations for VXLAN MDB that were split
from this RFC [1]. Tested using existing bridge MDB forwarding
selftests.

[1] https://lore.kernel.org/netdev/20230204170801.3897900-1-idosch@nvidia.com/
====================

Link: https://lore.kernel.org/r/20230209071852.613102-1-idosch@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents ee7e1788 04913912
Loading
Loading
Loading
Loading
+28 −21
Original line number Diff line number Diff line
@@ -259,7 +259,7 @@ static int __mdb_fill_info(struct sk_buff *skb,
#endif
	} else {
		ether_addr_copy(e.addr.u.mac_addr, mp->addr.dst.mac_addr);
		e.state = MDB_PG_FLAGS_PERMANENT;
		e.state = MDB_PERMANENT;
	}
	e.addr.proto = mp->addr.proto;
	nest_ent = nla_nest_start_noflag(skb,
@@ -421,8 +421,6 @@ static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb)

	rcu_read_lock();

	cb->seq = net->dev_base_seq;

	for_each_netdev_rcu(net, dev) {
		if (netif_is_bridge_master(dev)) {
			struct net_bridge *br = netdev_priv(dev);
@@ -685,51 +683,58 @@ static const struct nla_policy br_mdbe_attrs_pol[MDBE_ATTR_MAX + 1] = {
	[MDBE_ATTR_RTPROT] = NLA_POLICY_MIN(NLA_U8, RTPROT_STATIC),
};

static bool is_valid_mdb_entry(struct br_mdb_entry *entry,
static int validate_mdb_entry(const struct nlattr *attr,
			      struct netlink_ext_ack *extack)
{
	struct br_mdb_entry *entry = nla_data(attr);

	if (nla_len(attr) != sizeof(struct br_mdb_entry)) {
		NL_SET_ERR_MSG_MOD(extack, "Invalid MDBA_SET_ENTRY attribute length");
		return -EINVAL;
	}

	if (entry->ifindex == 0) {
		NL_SET_ERR_MSG_MOD(extack, "Zero entry ifindex is not allowed");
		return false;
		return -EINVAL;
	}

	if (entry->addr.proto == htons(ETH_P_IP)) {
		if (!ipv4_is_multicast(entry->addr.u.ip4)) {
			NL_SET_ERR_MSG_MOD(extack, "IPv4 entry group address is not multicast");
			return false;
			return -EINVAL;
		}
		if (ipv4_is_local_multicast(entry->addr.u.ip4)) {
			NL_SET_ERR_MSG_MOD(extack, "IPv4 entry group address is local multicast");
			return false;
			return -EINVAL;
		}
#if IS_ENABLED(CONFIG_IPV6)
	} else if (entry->addr.proto == htons(ETH_P_IPV6)) {
		if (ipv6_addr_is_ll_all_nodes(&entry->addr.u.ip6)) {
			NL_SET_ERR_MSG_MOD(extack, "IPv6 entry group address is link-local all nodes");
			return false;
			return -EINVAL;
		}
#endif
	} else if (entry->addr.proto == 0) {
		/* L2 mdb */
		if (!is_multicast_ether_addr(entry->addr.u.mac_addr)) {
			NL_SET_ERR_MSG_MOD(extack, "L2 entry group is not multicast");
			return false;
			return -EINVAL;
		}
	} else {
		NL_SET_ERR_MSG_MOD(extack, "Unknown entry protocol");
		return false;
		return -EINVAL;
	}

	if (entry->state != MDB_PERMANENT && entry->state != MDB_TEMPORARY) {
		NL_SET_ERR_MSG_MOD(extack, "Unknown entry state");
		return false;
		return -EINVAL;
	}
	if (entry->vid >= VLAN_VID_MASK) {
		NL_SET_ERR_MSG_MOD(extack, "Invalid entry VLAN id");
		return false;
		return -EINVAL;
	}

	return true;
	return 0;
}

static bool is_valid_mdb_source(struct nlattr *attr, __be16 proto,
@@ -1294,6 +1299,14 @@ static int br_mdb_config_attrs_init(struct nlattr *set_attrs,
	return 0;
}

static const struct nla_policy mdba_policy[MDBA_SET_ENTRY_MAX + 1] = {
	[MDBA_SET_ENTRY_UNSPEC] = { .strict_start_type = MDBA_SET_ENTRY_ATTRS + 1 },
	[MDBA_SET_ENTRY] = NLA_POLICY_VALIDATE_FN(NLA_BINARY,
						  validate_mdb_entry,
						  sizeof(struct br_mdb_entry)),
	[MDBA_SET_ENTRY_ATTRS] = { .type = NLA_NESTED },
};

static int br_mdb_config_init(struct net *net, const struct nlmsghdr *nlh,
			      struct br_mdb_config *cfg,
			      struct netlink_ext_ack *extack)
@@ -1304,7 +1317,7 @@ static int br_mdb_config_init(struct net *net, const struct nlmsghdr *nlh,
	int err;

	err = nlmsg_parse_deprecated(nlh, sizeof(*bpm), tb,
				     MDBA_SET_ENTRY_MAX, NULL, extack);
				     MDBA_SET_ENTRY_MAX, mdba_policy, extack);
	if (err)
		return err;

@@ -1346,14 +1359,8 @@ static int br_mdb_config_init(struct net *net, const struct nlmsghdr *nlh,
		NL_SET_ERR_MSG_MOD(extack, "Missing MDBA_SET_ENTRY attribute");
		return -EINVAL;
	}
	if (nla_len(tb[MDBA_SET_ENTRY]) != sizeof(struct br_mdb_entry)) {
		NL_SET_ERR_MSG_MOD(extack, "Invalid MDBA_SET_ENTRY attribute length");
		return -EINVAL;
	}

	cfg->entry = nla_data(tb[MDBA_SET_ENTRY]);
	if (!is_valid_mdb_entry(cfg->entry, extack))
		return -EINVAL;

	if (cfg->entry->ifindex != cfg->br->dev->ifindex) {
		struct net_device *pdev;
+99 −0
Original line number Diff line number Diff line
@@ -742,10 +742,109 @@ cfg_test_port()
	cfg_test_port_l2
}

ipv4_grps_get()
{
	local max_grps=$1; shift
	local i

	for i in $(seq 0 $((max_grps - 1))); do
		echo "239.1.1.$i"
	done
}

ipv6_grps_get()
{
	local max_grps=$1; shift
	local i

	for i in $(seq 0 $((max_grps - 1))); do
		echo "ff0e::$(printf %x $i)"
	done
}

l2_grps_get()
{
	local max_grps=$1; shift
	local i

	for i in $(seq 0 $((max_grps - 1))); do
		echo "01:00:00:00:00:$(printf %02x $i)"
	done
}

cfg_test_dump_common()
{
	local name=$1; shift
	local fn=$1; shift
	local max_bridges=2
	local max_grps=256
	local max_ports=32
	local num_entries
	local batch_file
	local grp
	local i j

	RET=0

	# Create net devices.
	for i in $(seq 1 $max_bridges); do
		ip link add name br-test${i} up type bridge vlan_filtering 1 \
			mcast_snooping 1
		for j in $(seq 1 $max_ports); do
			ip link add name br-test${i}-du${j} up \
				master br-test${i} type dummy
		done
	done

	# Create batch file with MDB entries.
	batch_file=$(mktemp)
	for i in $(seq 1 $max_bridges); do
		for j in $(seq 1 $max_ports); do
			for grp in $($fn $max_grps); do
				echo "mdb add dev br-test${i} \
					port br-test${i}-du${j} grp $grp \
					permanent vid 1" >> $batch_file
			done
		done
	done

	# Program the batch file and check for expected number of entries.
	bridge -b $batch_file
	for i in $(seq 1 $max_bridges); do
		num_entries=$(bridge mdb show dev br-test${i} | \
			grep "permanent" | wc -l)
		[[ $num_entries -eq $((max_grps * max_ports)) ]]
		check_err $? "Wrong number of entries in br-test${i}"
	done

	# Cleanup.
	rm $batch_file
	for i in $(seq 1 $max_bridges); do
		ip link del dev br-test${i}
		for j in $(seq $max_ports); do
			ip link del dev br-test${i}-du${j}
		done
	done

	log_test "$name large scale dump tests"
}

# Check large scale dump.
cfg_test_dump()
{
	echo
	log_info "# Large scale dump tests"

	cfg_test_dump_common "IPv4" ipv4_grps_get
	cfg_test_dump_common "IPv6" ipv6_grps_get
	cfg_test_dump_common "L2" l2_grps_get
}

cfg_test()
{
	cfg_test_host
	cfg_test_port
	cfg_test_dump
}

__fwd_test_host_ip()