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

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.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents ee7e1788 04913912
...@@ -259,7 +259,7 @@ static int __mdb_fill_info(struct sk_buff *skb, ...@@ -259,7 +259,7 @@ static int __mdb_fill_info(struct sk_buff *skb,
#endif #endif
} else { } else {
ether_addr_copy(e.addr.u.mac_addr, mp->addr.dst.mac_addr); 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; e.addr.proto = mp->addr.proto;
nest_ent = nla_nest_start_noflag(skb, nest_ent = nla_nest_start_noflag(skb,
...@@ -421,8 +421,6 @@ static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -421,8 +421,6 @@ static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
rcu_read_lock(); rcu_read_lock();
cb->seq = net->dev_base_seq;
for_each_netdev_rcu(net, dev) { for_each_netdev_rcu(net, dev) {
if (netif_is_bridge_master(dev)) { if (netif_is_bridge_master(dev)) {
struct net_bridge *br = netdev_priv(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] = { ...@@ -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), [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 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) { if (entry->ifindex == 0) {
NL_SET_ERR_MSG_MOD(extack, "Zero entry ifindex is not allowed"); 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 (entry->addr.proto == htons(ETH_P_IP)) {
if (!ipv4_is_multicast(entry->addr.u.ip4)) { if (!ipv4_is_multicast(entry->addr.u.ip4)) {
NL_SET_ERR_MSG_MOD(extack, "IPv4 entry group address is not multicast"); 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)) { if (ipv4_is_local_multicast(entry->addr.u.ip4)) {
NL_SET_ERR_MSG_MOD(extack, "IPv4 entry group address is local multicast"); NL_SET_ERR_MSG_MOD(extack, "IPv4 entry group address is local multicast");
return false; return -EINVAL;
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
} else if (entry->addr.proto == htons(ETH_P_IPV6)) { } else if (entry->addr.proto == htons(ETH_P_IPV6)) {
if (ipv6_addr_is_ll_all_nodes(&entry->addr.u.ip6)) { 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"); NL_SET_ERR_MSG_MOD(extack, "IPv6 entry group address is link-local all nodes");
return false; return -EINVAL;
} }
#endif #endif
} else if (entry->addr.proto == 0) { } else if (entry->addr.proto == 0) {
/* L2 mdb */ /* L2 mdb */
if (!is_multicast_ether_addr(entry->addr.u.mac_addr)) { if (!is_multicast_ether_addr(entry->addr.u.mac_addr)) {
NL_SET_ERR_MSG_MOD(extack, "L2 entry group is not multicast"); NL_SET_ERR_MSG_MOD(extack, "L2 entry group is not multicast");
return false; return -EINVAL;
} }
} else { } else {
NL_SET_ERR_MSG_MOD(extack, "Unknown entry protocol"); NL_SET_ERR_MSG_MOD(extack, "Unknown entry protocol");
return false; return -EINVAL;
} }
if (entry->state != MDB_PERMANENT && entry->state != MDB_TEMPORARY) { if (entry->state != MDB_PERMANENT && entry->state != MDB_TEMPORARY) {
NL_SET_ERR_MSG_MOD(extack, "Unknown entry state"); NL_SET_ERR_MSG_MOD(extack, "Unknown entry state");
return false; return -EINVAL;
} }
if (entry->vid >= VLAN_VID_MASK) { if (entry->vid >= VLAN_VID_MASK) {
NL_SET_ERR_MSG_MOD(extack, "Invalid entry VLAN id"); 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, 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, ...@@ -1294,6 +1299,14 @@ static int br_mdb_config_attrs_init(struct nlattr *set_attrs,
return 0; 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, static int br_mdb_config_init(struct net *net, const struct nlmsghdr *nlh,
struct br_mdb_config *cfg, struct br_mdb_config *cfg,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
...@@ -1304,7 +1317,7 @@ static int br_mdb_config_init(struct net *net, const struct nlmsghdr *nlh, ...@@ -1304,7 +1317,7 @@ static int br_mdb_config_init(struct net *net, const struct nlmsghdr *nlh,
int err; int err;
err = nlmsg_parse_deprecated(nlh, sizeof(*bpm), tb, err = nlmsg_parse_deprecated(nlh, sizeof(*bpm), tb,
MDBA_SET_ENTRY_MAX, NULL, extack); MDBA_SET_ENTRY_MAX, mdba_policy, extack);
if (err) if (err)
return err; return err;
...@@ -1346,14 +1359,8 @@ static int br_mdb_config_init(struct net *net, const struct nlmsghdr *nlh, ...@@ -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"); NL_SET_ERR_MSG_MOD(extack, "Missing MDBA_SET_ENTRY attribute");
return -EINVAL; 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]); 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) { if (cfg->entry->ifindex != cfg->br->dev->ifindex) {
struct net_device *pdev; struct net_device *pdev;
......
...@@ -742,10 +742,109 @@ cfg_test_port() ...@@ -742,10 +742,109 @@ cfg_test_port()
cfg_test_port_l2 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()
{ {
cfg_test_host cfg_test_host
cfg_test_port cfg_test_port
cfg_test_dump
} }
__fwd_test_host_ip() __fwd_test_host_ip()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment