Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bridge-mdb-limit'

Petr Machata says:

====================
bridge: Limit number of MDB entries per port, port-vlan

The MDB maintained by the bridge is limited. When the bridge is configured
for IGMP / MLD snooping, a buggy or malicious client can easily exhaust its
capacity. In SW datapath, the capacity is configurable through the
IFLA_BR_MCAST_HASH_MAX parameter, but ultimately is finite. Obviously a
similar limit exists in the HW datapath for purposes of offloading.

In order to prevent the issue of unilateral exhaustion of MDB resources,
introduce two parameters in each of two contexts:

- Per-port and (when BROPT_MCAST_VLAN_SNOOPING_ENABLED is enabled)
per-port-VLAN number of MDB entries that the port is member in.

- Per-port and (when BROPT_MCAST_VLAN_SNOOPING_ENABLED is enabled)
per-port-VLAN maximum permitted number of MDB entries, or 0 for
no limit.

Per-port number of entries keeps track of the total number of MDB entries
configured on a given port. The per-port-VLAN value then keeps track of the
subset of MDB entries configured specifically for the given VLAN, on that
port. The number is adjusted as port_groups are created and deleted, and
therefore under multicast lock.

A maximum value, if non-zero, then places a limit on the number of entries
that can be configured in a given context. Attempts to add entries above
the maximum are rejected.

Rejection reason of netlink-based requests to add MDB entries is
communicated through extack. This channel is unavailable for rejections
triggered from the control path. To address this lack of visibility, the
patchset adds a tracepoint, bridge:br_mdb_full:

# perf record -e bridge:br_mdb_full &
# [...]
# perf script | cut -d: -f4-
dev v2 af 2 src ::ffff:0.0.0.0 grp ::ffff:239.1.1.112/00:00:00:00:00:00 vid 0
dev v2 af 10 src :: grp ff0e::112/00:00:00:00:00:00 vid 0
dev v2 af 2 src ::ffff:0.0.0.0 grp ::ffff:239.1.1.112/00:00:00:00:00:00 vid 10
dev v2 af 10 src 2001:db8:1::1 grp ff0e::1/00:00:00:00:00:00 vid 10
dev v2 af 2 src ::ffff:192.0.2.1 grp ::ffff:239.1.1.1/00:00:00:00:00:00 vid 10

Another option to consume the tracepoint is e.g. through the bpftrace tool:

# bpftrace -e ' tracepoint:bridge:br_mdb_full /args->af != 0/ {
printf("dev %s src %s grp %s vid %u\n",
str(args->dev), ntop(args->src),
ntop(args->grp), args->vid);
}
tracepoint:bridge:br_mdb_full /args->af == 0/ {
printf("dev %s grp %s vid %u\n",
str(args->dev),
macaddr(args->grpmac), args->vid);
}'

This tracepoint is triggered for mcast_hash_max exhaustions as well.

The following is an example of how the feature is used. A more extensive
example is available in patch #8:

# bridge vlan set dev v1 vid 1 mcast_max_groups 1
# bridge mdb add dev br port v1 grp 230.1.2.3 temp vid 1
# bridge mdb add dev br port v1 grp 230.1.2.4 temp vid 1
Error: bridge: Port-VLAN is already in 1 groups, and mcast_max_groups=1.

The patchset progresses as follows:

- In patch #1, set strict_start_type at two bridge-related policies. The
reason is we are adding a new attribute to one of these, and want the new
attribute to be parsed strictly. The other was adjusted for completeness'
sake.

- In patches #2 to #5, br_mdb and br_multicast code is adjusted to make the
following additions smoother.

- In patch #6, add the tracepoint.

- In patch #7, the code to maintain number of MDB entries is added as
struct net_bridge_mcast_port::mdb_n_entries. The maximum is added, too,
as struct net_bridge_mcast_port::mdb_max_entries, however at this point
there is no way to set the value yet, and since 0 is treated as "no
limit", the functionality doesn't change at this point. Note however,
that mcast_hash_max violations already do trigger at this point.

- In patch #8, netlink plumbing is added: reading of number of entries, and
reading and writing of maximum.

The per-port values are passed through RTM_NEWLINK / RTM_GETLINK messages
in IFLA_BRPORT_MCAST_N_GROUPS and _MAX_GROUPS, inside IFLA_PROTINFO nest.

The per-port-vlan values are passed through RTM_GETVLAN / RTM_NEWVLAN
messages in BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS, _MAX_GROUPS, inside
BRIDGE_VLANDB_ENTRY.

The following patches deal with the selftest:

- Patches #9 and #10 clean up and move around some selftest code.

- Patches #11 to #14 add helpers and generalize the existing IGMP / MLD
support to allow generating packets with configurable group addresses and
varying source lists for (S,G) memberships.

- Patch #15 adds code to generate IGMP leave and MLD done packets.

- Patch #16 finally adds the selftest itself.

v3:
- Patch #7:
- Access mdb_max_/_n_entries through READ_/WRITE_ONCE
- Move extack setting to br_multicast_port_ngroups_inc_one().
Since we use NL_SET_ERR_MSG_FMT_MOD, the correct context
(port / port-vlan) can be passed through an argument.
This also removes the need for more READ/WRITE_ONCE's
at the extack-setting site.
- Patch #8:
- Move the br_multicast_port_ctx_vlan_disabled() check
out to the _vlan_ helpers callers. Thus these helpers
cannot fail, which makes them very similar to the
_port_ helpers. Have them take the MC context directly
and unify them.

v2:
- Cover letter:
- Add an example of a bpftrace-based probe script
- Patch #6:
- Report IPv4 as an IPv6-mapped address through the IPv6 buffer
as well, to save ring buffer space.
- Patch #7:
- In br_multicast_port_ngroups_inc_one(), bounce
if n>=max, not if n==max
- Adjust extack messages to mention ngroups, now
that the bounces appear when n>=max, not n==max
- In __br_multicast_enable_port_ctx(), do not reset
max to 0. Also do not count number of entries by
going through _inc, as that would end up incorrectly
bouncing the entries.
- Patch #8:
- Drop locks around accesses in
br_multicast_{port,vlan}_ngroups_{get,set_max}(),
- Drop bounces due to max<n in
br_multicast_{port,vlan}_ngroups_set_max().
- Patch #12:
- In the comment at payload_template_calc_checksum(),
s/%#02x/%02x/, that's the mausezahn payload format.
- Patch #16:
- Adjust the tests that check setting max below n and
reset of max on VLAN snooping enablement
- Make test naming uniform
- Enable testing of control path (IGMP/MLD) in
mcast_vlan_snooping bridge
- Reorganize the code so that test instances (per bridge
type and configuration type) always come right after
the test, in order of {d,q,qvs}{4,6}{cfg,ctl}.
Then groups of selftests are at the end of the file.
Similarly adjust invocation order of the tests.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1867 -79
+58
include/trace/events/bridge.h
··· 122 122 __entry->flags) 123 123 ); 124 124 125 + TRACE_EVENT(br_mdb_full, 126 + 127 + TP_PROTO(const struct net_device *dev, 128 + const struct br_ip *group), 129 + 130 + TP_ARGS(dev, group), 131 + 132 + TP_STRUCT__entry( 133 + __string(dev, dev->name) 134 + __field(int, af) 135 + __field(u16, vid) 136 + __array(__u8, src, 16) 137 + __array(__u8, grp, 16) 138 + __array(__u8, grpmac, ETH_ALEN) /* For af == 0. */ 139 + ), 140 + 141 + TP_fast_assign( 142 + struct in6_addr *in6; 143 + 144 + __assign_str(dev, dev->name); 145 + __entry->vid = group->vid; 146 + 147 + if (!group->proto) { 148 + __entry->af = 0; 149 + 150 + memset(__entry->src, 0, sizeof(__entry->src)); 151 + memset(__entry->grp, 0, sizeof(__entry->grp)); 152 + memcpy(__entry->grpmac, group->dst.mac_addr, ETH_ALEN); 153 + } else if (group->proto == htons(ETH_P_IP)) { 154 + __entry->af = AF_INET; 155 + 156 + in6 = (struct in6_addr *)__entry->src; 157 + ipv6_addr_set_v4mapped(group->src.ip4, in6); 158 + 159 + in6 = (struct in6_addr *)__entry->grp; 160 + ipv6_addr_set_v4mapped(group->dst.ip4, in6); 161 + 162 + memset(__entry->grpmac, 0, ETH_ALEN); 163 + 164 + #if IS_ENABLED(CONFIG_IPV6) 165 + } else { 166 + __entry->af = AF_INET6; 167 + 168 + in6 = (struct in6_addr *)__entry->src; 169 + *in6 = group->src.ip6; 170 + 171 + in6 = (struct in6_addr *)__entry->grp; 172 + *in6 = group->dst.ip6; 173 + 174 + memset(__entry->grpmac, 0, ETH_ALEN); 175 + #endif 176 + } 177 + ), 178 + 179 + TP_printk("dev %s af %u src %pI6c grp %pI6c/%pM vid %u", 180 + __get_str(dev), __entry->af, __entry->src, __entry->grp, 181 + __entry->grpmac, __entry->vid) 182 + ); 125 183 126 184 #endif /* _TRACE_BRIDGE_H */ 127 185
+2
include/uapi/linux/if_bridge.h
··· 523 523 BRIDGE_VLANDB_ENTRY_TUNNEL_INFO, 524 524 BRIDGE_VLANDB_ENTRY_STATS, 525 525 BRIDGE_VLANDB_ENTRY_MCAST_ROUTER, 526 + BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS, 527 + BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS, 526 528 __BRIDGE_VLANDB_ENTRY_MAX, 527 529 }; 528 530 #define BRIDGE_VLANDB_ENTRY_MAX (__BRIDGE_VLANDB_ENTRY_MAX - 1)
+2
include/uapi/linux/if_link.h
··· 567 567 IFLA_BRPORT_MCAST_EHT_HOSTS_CNT, 568 568 IFLA_BRPORT_LOCKED, 569 569 IFLA_BRPORT_MAB, 570 + IFLA_BRPORT_MCAST_N_GROUPS, 571 + IFLA_BRPORT_MCAST_MAX_GROUPS, 570 572 __IFLA_BRPORT_MAX 571 573 }; 572 574 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+7 -10
net/bridge/br_mdb.c
··· 849 849 } 850 850 851 851 p = br_multicast_new_port_group(cfg->p, &cfg->group, *pp, flags, NULL, 852 - MCAST_INCLUDE, cfg->rt_protocol); 853 - if (unlikely(!p)) { 854 - NL_SET_ERR_MSG_MOD(extack, "Couldn't allocate new (S, G) port group"); 852 + MCAST_INCLUDE, cfg->rt_protocol, extack); 853 + if (unlikely(!p)) 855 854 return -ENOMEM; 856 - } 855 + 857 856 rcu_assign_pointer(*pp, p); 858 857 if (!(flags & MDB_PG_FLAGS_PERMANENT) && !cfg->src_entry) 859 858 mod_timer(&p->timer, ··· 1074 1075 } 1075 1076 1076 1077 p = br_multicast_new_port_group(cfg->p, &cfg->group, *pp, flags, NULL, 1077 - cfg->filter_mode, cfg->rt_protocol); 1078 - if (unlikely(!p)) { 1079 - NL_SET_ERR_MSG_MOD(extack, "Couldn't allocate new (*, G) port group"); 1078 + cfg->filter_mode, cfg->rt_protocol, 1079 + extack); 1080 + if (unlikely(!p)) 1080 1081 return -ENOMEM; 1081 - } 1082 1082 1083 1083 err = br_mdb_add_group_srcs(cfg, p, brmctx, extack); 1084 1084 if (err) ··· 1099 1101 return 0; 1100 1102 1101 1103 err_del_port_group: 1102 - hlist_del_init(&p->mglist); 1103 - kfree(p); 1104 + br_multicast_del_port_group(p); 1104 1105 return err; 1105 1106 } 1106 1107
+173 -6
net/bridge/br_multicast.c
··· 31 31 #include <net/ip6_checksum.h> 32 32 #include <net/addrconf.h> 33 33 #endif 34 + #include <trace/events/bridge.h> 34 35 35 36 #include "br_private.h" 36 37 #include "br_private_mcast_eht.h" ··· 232 231 pmctx = NULL; 233 232 rcu_read_unlock(); 234 233 out: 234 + return pmctx; 235 + } 236 + 237 + static struct net_bridge_mcast_port * 238 + br_multicast_port_vid_to_port_ctx(struct net_bridge_port *port, u16 vid) 239 + { 240 + struct net_bridge_mcast_port *pmctx = NULL; 241 + struct net_bridge_vlan *vlan; 242 + 243 + lockdep_assert_held_once(&port->br->multicast_lock); 244 + 245 + if (!br_opt_get(port->br, BROPT_MCAST_VLAN_SNOOPING_ENABLED)) 246 + return NULL; 247 + 248 + /* Take RCU to access the vlan. */ 249 + rcu_read_lock(); 250 + 251 + vlan = br_vlan_find(nbp_vlan_group_rcu(port), vid); 252 + if (vlan && !br_multicast_port_ctx_vlan_disabled(&vlan->port_mcast_ctx)) 253 + pmctx = &vlan->port_mcast_ctx; 254 + 255 + rcu_read_unlock(); 256 + 235 257 return pmctx; 236 258 } 237 259 ··· 692 668 __br_multicast_del_group_src(src); 693 669 } 694 670 671 + static int 672 + br_multicast_port_ngroups_inc_one(struct net_bridge_mcast_port *pmctx, 673 + struct netlink_ext_ack *extack, 674 + const char *what) 675 + { 676 + u32 max = READ_ONCE(pmctx->mdb_max_entries); 677 + u32 n = READ_ONCE(pmctx->mdb_n_entries); 678 + 679 + if (max && n >= max) { 680 + NL_SET_ERR_MSG_FMT_MOD(extack, "%s is already in %u groups, and mcast_max_groups=%u", 681 + what, n, max); 682 + return -E2BIG; 683 + } 684 + 685 + WRITE_ONCE(pmctx->mdb_n_entries, n + 1); 686 + return 0; 687 + } 688 + 689 + static void br_multicast_port_ngroups_dec_one(struct net_bridge_mcast_port *pmctx) 690 + { 691 + u32 n = READ_ONCE(pmctx->mdb_n_entries); 692 + 693 + WARN_ON_ONCE(n == 0); 694 + WRITE_ONCE(pmctx->mdb_n_entries, n - 1); 695 + } 696 + 697 + static int br_multicast_port_ngroups_inc(struct net_bridge_port *port, 698 + const struct br_ip *group, 699 + struct netlink_ext_ack *extack) 700 + { 701 + struct net_bridge_mcast_port *pmctx; 702 + int err; 703 + 704 + lockdep_assert_held_once(&port->br->multicast_lock); 705 + 706 + /* Always count on the port context. */ 707 + err = br_multicast_port_ngroups_inc_one(&port->multicast_ctx, extack, 708 + "Port"); 709 + if (err) { 710 + trace_br_mdb_full(port->dev, group); 711 + return err; 712 + } 713 + 714 + /* Only count on the VLAN context if VID is given, and if snooping on 715 + * that VLAN is enabled. 716 + */ 717 + if (!group->vid) 718 + return 0; 719 + 720 + pmctx = br_multicast_port_vid_to_port_ctx(port, group->vid); 721 + if (!pmctx) 722 + return 0; 723 + 724 + err = br_multicast_port_ngroups_inc_one(pmctx, extack, "Port-VLAN"); 725 + if (err) { 726 + trace_br_mdb_full(port->dev, group); 727 + goto dec_one_out; 728 + } 729 + 730 + return 0; 731 + 732 + dec_one_out: 733 + br_multicast_port_ngroups_dec_one(&port->multicast_ctx); 734 + return err; 735 + } 736 + 737 + static void br_multicast_port_ngroups_dec(struct net_bridge_port *port, u16 vid) 738 + { 739 + struct net_bridge_mcast_port *pmctx; 740 + 741 + lockdep_assert_held_once(&port->br->multicast_lock); 742 + 743 + if (vid) { 744 + pmctx = br_multicast_port_vid_to_port_ctx(port, vid); 745 + if (pmctx) 746 + br_multicast_port_ngroups_dec_one(pmctx); 747 + } 748 + br_multicast_port_ngroups_dec_one(&port->multicast_ctx); 749 + } 750 + 751 + u32 br_multicast_ngroups_get(const struct net_bridge_mcast_port *pmctx) 752 + { 753 + return READ_ONCE(pmctx->mdb_n_entries); 754 + } 755 + 756 + void br_multicast_ngroups_set_max(struct net_bridge_mcast_port *pmctx, u32 max) 757 + { 758 + WRITE_ONCE(pmctx->mdb_max_entries, max); 759 + } 760 + 761 + u32 br_multicast_ngroups_get_max(const struct net_bridge_mcast_port *pmctx) 762 + { 763 + return READ_ONCE(pmctx->mdb_max_entries); 764 + } 765 + 695 766 static void br_multicast_destroy_port_group(struct net_bridge_mcast_gc *gc) 696 767 { 697 768 struct net_bridge_port_group *pg; ··· 821 702 } else { 822 703 br_multicast_star_g_handle_mode(pg, MCAST_INCLUDE); 823 704 } 705 + br_multicast_port_ngroups_dec(pg->key.port, pg->key.addr.vid); 824 706 hlist_add_head(&pg->mcast_gc.gc_node, &br->mcast_gc_list); 825 707 queue_work(system_long_wq, &br->mcast_gc_work); 826 708 ··· 1285 1165 return mp; 1286 1166 1287 1167 if (atomic_read(&br->mdb_hash_tbl.nelems) >= br->hash_max) { 1168 + trace_br_mdb_full(br->dev, group); 1288 1169 br_mc_disabled_update(br->dev, false, NULL); 1289 1170 br_opt_toggle(br, BROPT_MULTICAST_ENABLED, false); 1290 1171 return ERR_PTR(-E2BIG); ··· 1405 1284 unsigned char flags, 1406 1285 const unsigned char *src, 1407 1286 u8 filter_mode, 1408 - u8 rt_protocol) 1287 + u8 rt_protocol, 1288 + struct netlink_ext_ack *extack) 1409 1289 { 1410 1290 struct net_bridge_port_group *p; 1291 + int err; 1292 + 1293 + err = br_multicast_port_ngroups_inc(port, group, extack); 1294 + if (err) 1295 + return NULL; 1411 1296 1412 1297 p = kzalloc(sizeof(*p), GFP_ATOMIC); 1413 - if (unlikely(!p)) 1414 - return NULL; 1298 + if (unlikely(!p)) { 1299 + NL_SET_ERR_MSG_MOD(extack, "Couldn't allocate new port group"); 1300 + goto dec_out; 1301 + } 1415 1302 1416 1303 p->key.addr = *group; 1417 1304 p->key.port = port; ··· 1434 1305 if (!br_multicast_is_star_g(group) && 1435 1306 rhashtable_lookup_insert_fast(&port->br->sg_port_tbl, &p->rhnode, 1436 1307 br_sg_port_rht_params)) { 1437 - kfree(p); 1438 - return NULL; 1308 + NL_SET_ERR_MSG_MOD(extack, "Couldn't insert new port group"); 1309 + goto free_out; 1439 1310 } 1440 1311 1441 1312 rcu_assign_pointer(p->next, next); ··· 1449 1320 eth_broadcast_addr(p->eth_addr); 1450 1321 1451 1322 return p; 1323 + 1324 + free_out: 1325 + kfree(p); 1326 + dec_out: 1327 + br_multicast_port_ngroups_dec(port, group->vid); 1328 + return NULL; 1329 + } 1330 + 1331 + void br_multicast_del_port_group(struct net_bridge_port_group *p) 1332 + { 1333 + struct net_bridge_port *port = p->key.port; 1334 + __u16 vid = p->key.addr.vid; 1335 + 1336 + hlist_del_init(&p->mglist); 1337 + if (!br_multicast_is_star_g(&p->key.addr)) 1338 + rhashtable_remove_fast(&port->br->sg_port_tbl, &p->rhnode, 1339 + br_sg_port_rht_params); 1340 + kfree(p); 1341 + br_multicast_port_ngroups_dec(port, vid); 1452 1342 } 1453 1343 1454 1344 void br_multicast_host_join(const struct net_bridge_mcast *brmctx, ··· 1535 1387 } 1536 1388 1537 1389 p = br_multicast_new_port_group(pmctx->port, group, *pp, 0, src, 1538 - filter_mode, RTPROT_KERNEL); 1390 + filter_mode, RTPROT_KERNEL, NULL); 1539 1391 if (unlikely(!p)) { 1540 1392 p = ERR_PTR(-ENOMEM); 1541 1393 goto out; ··· 2080 1932 if (pmctx->multicast_router == MDB_RTR_TYPE_PERM) { 2081 1933 br_ip4_multicast_add_router(brmctx, pmctx); 2082 1934 br_ip6_multicast_add_router(brmctx, pmctx); 1935 + } 1936 + 1937 + if (br_multicast_port_ctx_is_vlan(pmctx)) { 1938 + struct net_bridge_port_group *pg; 1939 + u32 n = 0; 1940 + 1941 + /* The mcast_n_groups counter might be wrong. First, 1942 + * BR_VLFLAG_MCAST_ENABLED is toggled before temporary entries 1943 + * are flushed, thus mcast_n_groups after the toggle does not 1944 + * reflect the true values. And second, permanent entries added 1945 + * while BR_VLFLAG_MCAST_ENABLED was disabled, are not reflected 1946 + * either. Thus we have to refresh the counter. 1947 + */ 1948 + 1949 + hlist_for_each_entry(pg, &pmctx->port->mglist, mglist) { 1950 + if (pg->key.addr.vid == pmctx->vlan->vid) 1951 + n++; 1952 + } 1953 + WRITE_ONCE(pmctx->mdb_n_entries, n); 2083 1954 } 2084 1955 } 2085 1956
+18 -1
net/bridge/br_netlink.c
··· 202 202 + nla_total_size_64bit(sizeof(u64)) /* IFLA_BRPORT_HOLD_TIMER */ 203 203 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING 204 204 + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MULTICAST_ROUTER */ 205 + + nla_total_size(sizeof(u32)) /* IFLA_BRPORT_MCAST_N_GROUPS */ 206 + + nla_total_size(sizeof(u32)) /* IFLA_BRPORT_MCAST_MAX_GROUPS */ 205 207 #endif 206 208 + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_GROUP_FWD_MASK */ 207 209 + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MRP_RING_OPEN */ ··· 300 298 nla_put_u32(skb, IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT, 301 299 p->multicast_eht_hosts_limit) || 302 300 nla_put_u32(skb, IFLA_BRPORT_MCAST_EHT_HOSTS_CNT, 303 - p->multicast_eht_hosts_cnt)) 301 + p->multicast_eht_hosts_cnt) || 302 + nla_put_u32(skb, IFLA_BRPORT_MCAST_N_GROUPS, 303 + br_multicast_ngroups_get(&p->multicast_ctx)) || 304 + nla_put_u32(skb, IFLA_BRPORT_MCAST_MAX_GROUPS, 305 + br_multicast_ngroups_get_max(&p->multicast_ctx))) 304 306 return -EMSGSIZE; 305 307 #endif 306 308 ··· 864 858 } 865 859 866 860 static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = { 861 + [IFLA_BRPORT_UNSPEC] = { .strict_start_type = 862 + IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT + 1 }, 867 863 [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, 868 864 [IFLA_BRPORT_COST] = { .type = NLA_U32 }, 869 865 [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 }, ··· 889 881 [IFLA_BRPORT_MAB] = { .type = NLA_U8 }, 890 882 [IFLA_BRPORT_BACKUP_PORT] = { .type = NLA_U32 }, 891 883 [IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT] = { .type = NLA_U32 }, 884 + [IFLA_BRPORT_MCAST_N_GROUPS] = { .type = NLA_REJECT }, 885 + [IFLA_BRPORT_MCAST_MAX_GROUPS] = { .type = NLA_U32 }, 892 886 }; 893 887 894 888 /* Change the state of the port and notify spanning tree */ ··· 1024 1014 err = br_multicast_eht_set_hosts_limit(p, hlimit); 1025 1015 if (err) 1026 1016 return err; 1017 + } 1018 + 1019 + if (tb[IFLA_BRPORT_MCAST_MAX_GROUPS]) { 1020 + u32 max_groups; 1021 + 1022 + max_groups = nla_get_u32(tb[IFLA_BRPORT_MCAST_MAX_GROUPS]); 1023 + br_multicast_ngroups_set_max(&p->multicast_ctx, max_groups); 1027 1024 } 1028 1025 #endif 1029 1026
+10 -2
net/bridge/br_private.h
··· 126 126 struct hlist_node ip6_rlist; 127 127 #endif /* IS_ENABLED(CONFIG_IPV6) */ 128 128 unsigned char multicast_router; 129 + u32 mdb_n_entries; 130 + u32 mdb_max_entries; 129 131 #endif /* CONFIG_BRIDGE_IGMP_SNOOPING */ 130 132 }; 131 133 ··· 958 956 const struct br_ip *group, 959 957 struct net_bridge_port_group __rcu *next, 960 958 unsigned char flags, const unsigned char *src, 961 - u8 filter_mode, u8 rt_protocol); 959 + u8 filter_mode, u8 rt_protocol, 960 + struct netlink_ext_ack *extack); 961 + void br_multicast_del_port_group(struct net_bridge_port_group *p); 962 962 int br_mdb_hash_init(struct net_bridge *br); 963 963 void br_mdb_hash_fini(struct net_bridge *br); 964 964 void br_mdb_notify(struct net_device *dev, struct net_bridge_mdb_entry *mp, ··· 978 974 void br_multicast_get_stats(const struct net_bridge *br, 979 975 const struct net_bridge_port *p, 980 976 struct br_mcast_stats *dest); 977 + u32 br_multicast_ngroups_get(const struct net_bridge_mcast_port *pmctx); 978 + void br_multicast_ngroups_set_max(struct net_bridge_mcast_port *pmctx, u32 max); 979 + u32 br_multicast_ngroups_get_max(const struct net_bridge_mcast_port *pmctx); 981 980 void br_mdb_init(void); 982 981 void br_mdb_uninit(void); 983 982 void br_multicast_host_join(const struct net_bridge_mcast *brmctx, ··· 1764 1757 #ifdef CONFIG_BRIDGE_VLAN_FILTERING 1765 1758 bool br_vlan_opts_eq_range(const struct net_bridge_vlan *v_curr, 1766 1759 const struct net_bridge_vlan *range_end); 1767 - bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v); 1760 + bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v, 1761 + const struct net_bridge_port *p); 1768 1762 size_t br_vlan_opts_nl_size(void); 1769 1763 int br_vlan_process_options(const struct net_bridge *br, 1770 1764 const struct net_bridge_port *p,
+7 -4
net/bridge/br_vlan.c
··· 1816 1816 /* v_opts is used to dump the options which must be equal in the whole range */ 1817 1817 static bool br_vlan_fill_vids(struct sk_buff *skb, u16 vid, u16 vid_range, 1818 1818 const struct net_bridge_vlan *v_opts, 1819 + const struct net_bridge_port *p, 1819 1820 u16 flags, 1820 1821 bool dump_stats) 1821 1822 { ··· 1843 1842 goto out_err; 1844 1843 1845 1844 if (v_opts) { 1846 - if (!br_vlan_opts_fill(skb, v_opts)) 1845 + if (!br_vlan_opts_fill(skb, v_opts, p)) 1847 1846 goto out_err; 1848 1847 1849 1848 if (dump_stats && !br_vlan_stats_fill(skb, v_opts)) ··· 1926 1925 goto out_kfree; 1927 1926 } 1928 1927 1929 - if (!br_vlan_fill_vids(skb, vid, vid_range, v, flags, false)) 1928 + if (!br_vlan_fill_vids(skb, vid, vid_range, v, p, flags, false)) 1930 1929 goto out_err; 1931 1930 1932 1931 nlmsg_end(skb, nlh); ··· 2031 2030 2032 2031 if (!br_vlan_fill_vids(skb, range_start->vid, 2033 2032 range_end->vid, range_start, 2034 - vlan_flags, dump_stats)) { 2033 + p, vlan_flags, dump_stats)) { 2035 2034 err = -EMSGSIZE; 2036 2035 break; 2037 2036 } ··· 2057 2056 else if (!dump_global && 2058 2057 !br_vlan_fill_vids(skb, range_start->vid, 2059 2058 range_end->vid, range_start, 2060 - br_vlan_flags(range_start, pvid), 2059 + p, br_vlan_flags(range_start, pvid), 2061 2060 dump_stats)) 2062 2061 err = -EMSGSIZE; 2063 2062 } ··· 2132 2131 [BRIDGE_VLANDB_ENTRY_STATE] = { .type = NLA_U8 }, 2133 2132 [BRIDGE_VLANDB_ENTRY_TUNNEL_INFO] = { .type = NLA_NESTED }, 2134 2133 [BRIDGE_VLANDB_ENTRY_MCAST_ROUTER] = { .type = NLA_U8 }, 2134 + [BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS] = { .type = NLA_REJECT }, 2135 + [BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS] = { .type = NLA_U32 }, 2135 2136 }; 2136 2137 2137 2138 static int br_vlan_rtm_process_one(struct net_device *dev,
+26 -1
net/bridge/br_vlan_options.c
··· 48 48 curr_mc_rtr == range_mc_rtr; 49 49 } 50 50 51 - bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v) 51 + bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v, 52 + const struct net_bridge_port *p) 52 53 { 53 54 if (nla_put_u8(skb, BRIDGE_VLANDB_ENTRY_STATE, br_vlan_get_state(v)) || 54 55 !__vlan_tun_put(skb, v)) ··· 58 57 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING 59 58 if (nla_put_u8(skb, BRIDGE_VLANDB_ENTRY_MCAST_ROUTER, 60 59 br_vlan_multicast_router(v))) 60 + return false; 61 + if (p && !br_multicast_port_ctx_vlan_disabled(&v->port_mcast_ctx) && 62 + (nla_put_u32(skb, BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS, 63 + br_multicast_ngroups_get(&v->port_mcast_ctx)) || 64 + nla_put_u32(skb, BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS, 65 + br_multicast_ngroups_get_max(&v->port_mcast_ctx)))) 61 66 return false; 62 67 #endif 63 68 ··· 77 70 + nla_total_size(sizeof(u32)) /* BRIDGE_VLANDB_TINFO_ID */ 78 71 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING 79 72 + nla_total_size(sizeof(u8)) /* BRIDGE_VLANDB_ENTRY_MCAST_ROUTER */ 73 + + nla_total_size(sizeof(u32)) /* BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS */ 74 + + nla_total_size(sizeof(u32)) /* BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS */ 80 75 #endif 81 76 + 0; 82 77 } ··· 219 210 err = br_multicast_set_vlan_router(v, val); 220 211 if (err) 221 212 return err; 213 + *changed = true; 214 + } 215 + if (tb[BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS]) { 216 + u32 val; 217 + 218 + if (!p) { 219 + NL_SET_ERR_MSG_MOD(extack, "Can't set mcast_max_groups for non-port vlans"); 220 + return -EINVAL; 221 + } 222 + if (br_multicast_port_ctx_vlan_disabled(&v->port_mcast_ctx)) { 223 + NL_SET_ERR_MSG_MOD(extack, "Multicast snooping disabled on this VLAN"); 224 + return -EINVAL; 225 + } 226 + 227 + val = nla_get_u32(tb[BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS]); 228 + br_multicast_ngroups_set_max(&v->port_mcast_ctx, val); 222 229 *changed = true; 223 230 } 224 231 #endif
+1
net/core/net-traces.c
··· 41 41 EXPORT_TRACEPOINT_SYMBOL_GPL(br_fdb_external_learn_add); 42 42 EXPORT_TRACEPOINT_SYMBOL_GPL(fdb_delete); 43 43 EXPORT_TRACEPOINT_SYMBOL_GPL(br_fdb_update); 44 + EXPORT_TRACEPOINT_SYMBOL_GPL(br_mdb_full); 44 45 #endif 45 46 46 47 #if IS_ENABLED(CONFIG_PAGE_POOL)
+1 -1
net/core/rtnetlink.c
··· 58 58 #include "dev.h" 59 59 60 60 #define RTNL_MAX_TYPE 50 61 - #define RTNL_SLAVE_MAX_TYPE 40 61 + #define RTNL_SLAVE_MAX_TYPE 42 62 62 63 63 struct rtnl_link { 64 64 rtnl_doit_func doit;
+1
tools/testing/selftests/net/forwarding/Makefile
··· 4 4 bridge_locked_port.sh \ 5 5 bridge_mdb.sh \ 6 6 bridge_mdb_host.sh \ 7 + bridge_mdb_max.sh \ 7 8 bridge_mdb_port_down.sh \ 8 9 bridge_mld.sh \ 9 10 bridge_port_isolation.sh \
+6 -54
tools/testing/selftests/net/forwarding/bridge_mdb.sh
··· 1018 1018 ip -6 address del fe80::1/64 dev br0 1019 1019 } 1020 1020 1021 - igmpv3_is_in_get() 1022 - { 1023 - local igmpv3 1024 - 1025 - igmpv3=$(: 1026 - )"22:"$( : Type - Membership Report 1027 - )"00:"$( : Reserved 1028 - )"2a:f8:"$( : Checksum 1029 - )"00:00:"$( : Reserved 1030 - )"00:01:"$( : Number of Group Records 1031 - )"01:"$( : Record Type - IS_IN 1032 - )"00:"$( : Aux Data Len 1033 - )"00:01:"$( : Number of Sources 1034 - )"ef:01:01:01:"$( : Multicast Address - 239.1.1.1 1035 - )"c0:00:02:02"$( : Source Address - 192.0.2.2 1036 - ) 1037 - 1038 - echo $igmpv3 1039 - } 1040 - 1041 1021 ctrl_igmpv3_is_in_test() 1042 1022 { 1043 1023 RET=0 ··· 1029 1049 1030 1050 # IS_IN ( 192.0.2.2 ) 1031 1051 $MZ $h1.10 -c 1 -A 192.0.2.1 -B 239.1.1.1 \ 1032 - -t ip proto=2,p=$(igmpv3_is_in_get) -q 1052 + -t ip proto=2,p=$(igmpv3_is_in_get 239.1.1.1 192.0.2.2) -q 1033 1053 1034 1054 bridge -d mdb show dev br0 vid 10 | grep 239.1.1.1 | grep -q 192.0.2.2 1035 1055 check_fail $? "Permanent entry affected by IGMP packet" ··· 1042 1062 1043 1063 # IS_IN ( 192.0.2.2 ) 1044 1064 $MZ $h1.10 -c 1 -A 192.0.2.1 -B 239.1.1.1 \ 1045 - -t ip proto=2,p=$(igmpv3_is_in_get) -q 1065 + -t ip proto=2,p=$(igmpv3_is_in_get 239.1.1.1 192.0.2.2) -q 1046 1066 1047 1067 bridge -d mdb show dev br0 vid 10 | grep 239.1.1.1 | grep -v "src" | \ 1048 1068 grep -q 192.0.2.2 ··· 1054 1074 1055 1075 bridge mdb del dev br0 port $swp1 grp 239.1.1.1 vid 10 1056 1076 1057 - log_test "IGMPv3 MODE_IS_INCLUE tests" 1058 - } 1059 - 1060 - mldv2_is_in_get() 1061 - { 1062 - local hbh 1063 - local icmpv6 1064 - 1065 - hbh=$(: 1066 - )"3a:"$( : Next Header - ICMPv6 1067 - )"00:"$( : Hdr Ext Len 1068 - )"00:00:00:00:00:00:"$( : Options and Padding 1069 - ) 1070 - 1071 - icmpv6=$(: 1072 - )"8f:"$( : Type - MLDv2 Report 1073 - )"00:"$( : Code 1074 - )"45:39:"$( : Checksum 1075 - )"00:00:"$( : Reserved 1076 - )"00:01:"$( : Number of Group Records 1077 - )"01:"$( : Record Type - IS_IN 1078 - )"00:"$( : Aux Data Len 1079 - )"00:01:"$( : Number of Sources 1080 - )"ff:0e:00:00:00:00:00:00:"$( : Multicast address - ff0e::1 1081 - )"00:00:00:00:00:00:00:01:"$( : 1082 - )"20:01:0d:b8:00:01:00:00:"$( : Source Address - 2001:db8:1::2 1083 - )"00:00:00:00:00:00:00:02:"$( : 1084 - ) 1085 - 1086 - echo ${hbh}${icmpv6} 1077 + log_test "IGMPv3 MODE_IS_INCLUDE tests" 1087 1078 } 1088 1079 1089 1080 ctrl_mldv2_is_in_test() ··· 1067 1116 filter_mode include source_list 2001:db8:1::1 1068 1117 1069 1118 # IS_IN ( 2001:db8:1::2 ) 1119 + local p=$(mldv2_is_in_get fe80::1 ff0e::1 2001:db8:1::2) 1070 1120 $MZ -6 $h1.10 -c 1 -A fe80::1 -B ff0e::1 \ 1071 - -t ip hop=1,next=0,p=$(mldv2_is_in_get) -q 1121 + -t ip hop=1,next=0,p="$p" -q 1072 1122 1073 1123 bridge -d mdb show dev br0 vid 10 | grep ff0e::1 | \ 1074 1124 grep -q 2001:db8:1::2 ··· 1083 1131 1084 1132 # IS_IN ( 2001:db8:1::2 ) 1085 1133 $MZ -6 $h1.10 -c 1 -A fe80::1 -B ff0e::1 \ 1086 - -t ip hop=1,next=0,p=$(mldv2_is_in_get) -q 1134 + -t ip hop=1,next=0,p="$p" -q 1087 1135 1088 1136 bridge -d mdb show dev br0 vid 10 | grep ff0e::1 | grep -v "src" | \ 1089 1137 grep -q 2001:db8:1::2
+1336
tools/testing/selftests/net/forwarding/bridge_mdb_max.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + # +-----------------------+ +------------------------+ 5 + # | H1 (vrf) | | H2 (vrf) | 6 + # | + $h1.10 | | + $h2.10 | 7 + # | | 192.0.2.1/28 | | | 192.0.2.2/28 | 8 + # | | 2001:db8:1::1/64 | | | 2001:db8:1::2/64 | 9 + # | | | | | | 10 + # | | + $h1.20 | | | + $h2.20 | 11 + # | \ | 198.51.100.1/24 | | \ | 198.51.100.2/24 | 12 + # | \ | 2001:db8:2::1/64 | | \ | 2001:db8:2::2/64 | 13 + # | \| | | \| | 14 + # | + $h1 | | + $h2 | 15 + # +----|------------------+ +----|-------------------+ 16 + # | | 17 + # +----|--------------------------------------------------|-------------------+ 18 + # | SW | | | 19 + # | +--|--------------------------------------------------|-----------------+ | 20 + # | | + $swp1 BR0 (802.1q) + $swp2 | | 21 + # | | vid 10 vid 10 | | 22 + # | | vid 20 vid 20 | | 23 + # | | | | 24 + # | +-----------------------------------------------------------------------+ | 25 + # +---------------------------------------------------------------------------+ 26 + 27 + ALL_TESTS=" 28 + test_8021d 29 + test_8021q 30 + test_8021qvs 31 + " 32 + 33 + NUM_NETIFS=4 34 + source lib.sh 35 + source tc_common.sh 36 + 37 + h1_create() 38 + { 39 + simple_if_init $h1 40 + vlan_create $h1 10 v$h1 192.0.2.1/28 2001:db8:1::1/64 41 + vlan_create $h1 20 v$h1 198.51.100.1/24 2001:db8:2::1/64 42 + } 43 + 44 + h1_destroy() 45 + { 46 + vlan_destroy $h1 20 47 + vlan_destroy $h1 10 48 + simple_if_fini $h1 49 + } 50 + 51 + h2_create() 52 + { 53 + simple_if_init $h2 54 + vlan_create $h2 10 v$h2 192.0.2.2/28 55 + vlan_create $h2 20 v$h2 198.51.100.2/24 56 + } 57 + 58 + h2_destroy() 59 + { 60 + vlan_destroy $h2 20 61 + vlan_destroy $h2 10 62 + simple_if_fini $h2 63 + } 64 + 65 + switch_create_8021d() 66 + { 67 + log_info "802.1d tests" 68 + 69 + ip link add name br0 type bridge vlan_filtering 0 \ 70 + mcast_snooping 1 \ 71 + mcast_igmp_version 3 mcast_mld_version 2 72 + ip link set dev br0 up 73 + 74 + ip link set dev $swp1 master br0 75 + ip link set dev $swp1 up 76 + bridge link set dev $swp1 fastleave on 77 + 78 + ip link set dev $swp2 master br0 79 + ip link set dev $swp2 up 80 + } 81 + 82 + switch_create_8021q() 83 + { 84 + local br_flags=$1; shift 85 + 86 + log_info "802.1q $br_flags${br_flags:+ }tests" 87 + 88 + ip link add name br0 type bridge vlan_filtering 1 vlan_default_pvid 0 \ 89 + mcast_snooping 1 $br_flags \ 90 + mcast_igmp_version 3 mcast_mld_version 2 91 + bridge vlan add vid 10 dev br0 self 92 + bridge vlan add vid 20 dev br0 self 93 + ip link set dev br0 up 94 + 95 + ip link set dev $swp1 master br0 96 + ip link set dev $swp1 up 97 + bridge link set dev $swp1 fastleave on 98 + bridge vlan add vid 10 dev $swp1 99 + bridge vlan add vid 20 dev $swp1 100 + 101 + ip link set dev $swp2 master br0 102 + ip link set dev $swp2 up 103 + bridge vlan add vid 10 dev $swp2 104 + bridge vlan add vid 20 dev $swp2 105 + } 106 + 107 + switch_create_8021qvs() 108 + { 109 + switch_create_8021q "mcast_vlan_snooping 1" 110 + bridge vlan global set dev br0 vid 10 mcast_igmp_version 3 111 + bridge vlan global set dev br0 vid 10 mcast_mld_version 2 112 + bridge vlan global set dev br0 vid 20 mcast_igmp_version 3 113 + bridge vlan global set dev br0 vid 20 mcast_mld_version 2 114 + } 115 + 116 + switch_destroy() 117 + { 118 + ip link set dev $swp2 down 119 + ip link set dev $swp2 nomaster 120 + 121 + ip link set dev $swp1 down 122 + ip link set dev $swp1 nomaster 123 + 124 + ip link set dev br0 down 125 + ip link del dev br0 126 + } 127 + 128 + setup_prepare() 129 + { 130 + h1=${NETIFS[p1]} 131 + swp1=${NETIFS[p2]} 132 + 133 + swp2=${NETIFS[p3]} 134 + h2=${NETIFS[p4]} 135 + 136 + vrf_prepare 137 + forwarding_enable 138 + 139 + h1_create 140 + h2_create 141 + } 142 + 143 + cleanup() 144 + { 145 + pre_cleanup 146 + 147 + switch_destroy 2>/dev/null 148 + h2_destroy 149 + h1_destroy 150 + 151 + forwarding_restore 152 + vrf_cleanup 153 + } 154 + 155 + cfg_src_list() 156 + { 157 + local IPs=("$@") 158 + local IPstr=$(echo ${IPs[@]} | tr '[:space:]' , | sed 's/,$//') 159 + 160 + echo ${IPstr:+source_list }${IPstr} 161 + } 162 + 163 + cfg_group_op() 164 + { 165 + local op=$1; shift 166 + local locus=$1; shift 167 + local GRP=$1; shift 168 + local state=$1; shift 169 + local IPs=("$@") 170 + 171 + local source_list=$(cfg_src_list ${IPs[@]}) 172 + 173 + # Everything besides `bridge mdb' uses the "dev X vid Y" syntax, 174 + # so we use it here as well and convert. 175 + local br_locus=$(echo "$locus" | sed 's/^dev /port /') 176 + 177 + bridge mdb $op dev br0 $br_locus grp $GRP $state \ 178 + filter_mode include $source_list 179 + } 180 + 181 + cfg4_entries_op() 182 + { 183 + local op=$1; shift 184 + local locus=$1; shift 185 + local state=$1; shift 186 + local n=$1; shift 187 + local grp=${1:-1}; shift 188 + 189 + local GRP=239.1.1.${grp} 190 + local IPs=$(seq -f 192.0.2.%g 1 $((n - 1))) 191 + cfg_group_op "$op" "$locus" "$GRP" "$state" ${IPs[@]} 192 + } 193 + 194 + cfg4_entries_add() 195 + { 196 + cfg4_entries_op add "$@" 197 + } 198 + 199 + cfg4_entries_del() 200 + { 201 + cfg4_entries_op del "$@" 202 + } 203 + 204 + cfg6_entries_op() 205 + { 206 + local op=$1; shift 207 + local locus=$1; shift 208 + local state=$1; shift 209 + local n=$1; shift 210 + local grp=${1:-1}; shift 211 + 212 + local GRP=ff0e::${grp} 213 + local IPs=$(printf "2001:db8:1::%x\n" $(seq 1 $((n - 1)))) 214 + cfg_group_op "$op" "$locus" "$GRP" "$state" ${IPs[@]} 215 + } 216 + 217 + cfg6_entries_add() 218 + { 219 + cfg6_entries_op add "$@" 220 + } 221 + 222 + cfg6_entries_del() 223 + { 224 + cfg6_entries_op del "$@" 225 + } 226 + 227 + locus_dev_peer() 228 + { 229 + local dev_kw=$1; shift 230 + local dev=$1; shift 231 + local vid_kw=$1; shift 232 + local vid=$1; shift 233 + 234 + echo "$h1.${vid:-10}" 235 + } 236 + 237 + locus_dev() 238 + { 239 + local dev_kw=$1; shift 240 + local dev=$1; shift 241 + 242 + echo $dev 243 + } 244 + 245 + ctl4_entries_add() 246 + { 247 + local locus=$1; shift 248 + local state=$1; shift 249 + local n=$1; shift 250 + local grp=${1:-1}; shift 251 + 252 + local IPs=$(seq -f 192.0.2.%g 1 $((n - 1))) 253 + local peer=$(locus_dev_peer $locus) 254 + local GRP=239.1.1.${grp} 255 + $MZ $peer -c 1 -A 192.0.2.1 -B $GRP \ 256 + -t ip proto=2,p=$(igmpv3_is_in_get $GRP $IPs) -q 257 + sleep 1 258 + 259 + local nn=$(bridge mdb show dev br0 | grep $GRP | wc -l) 260 + if ((nn != n)); then 261 + echo mcast_max_groups > /dev/stderr 262 + false 263 + fi 264 + } 265 + 266 + ctl4_entries_del() 267 + { 268 + local locus=$1; shift 269 + local state=$1; shift 270 + local n=$1; shift 271 + local grp=${1:-1}; shift 272 + 273 + local peer=$(locus_dev_peer $locus) 274 + local GRP=239.1.1.${grp} 275 + $MZ $peer -c 1 -A 192.0.2.1 -B 224.0.0.2 \ 276 + -t ip proto=2,p=$(igmpv2_leave_get $GRP) -q 277 + sleep 1 278 + ! bridge mdb show dev br0 | grep -q $GRP 279 + } 280 + 281 + ctl6_entries_add() 282 + { 283 + local locus=$1; shift 284 + local state=$1; shift 285 + local n=$1; shift 286 + local grp=${1:-1}; shift 287 + 288 + local IPs=$(printf "2001:db8:1::%x\n" $(seq 1 $((n - 1)))) 289 + local peer=$(locus_dev_peer $locus) 290 + local SIP=fe80::1 291 + local GRP=ff0e::${grp} 292 + local p=$(mldv2_is_in_get $SIP $GRP $IPs) 293 + $MZ -6 $peer -c 1 -A $SIP -B $GRP -t ip hop=1,next=0,p="$p" -q 294 + sleep 1 295 + 296 + local nn=$(bridge mdb show dev br0 | grep $GRP | wc -l) 297 + if ((nn != n)); then 298 + echo mcast_max_groups > /dev/stderr 299 + false 300 + fi 301 + } 302 + 303 + ctl6_entries_del() 304 + { 305 + local locus=$1; shift 306 + local state=$1; shift 307 + local n=$1; shift 308 + local grp=${1:-1}; shift 309 + 310 + local peer=$(locus_dev_peer $locus) 311 + local SIP=fe80::1 312 + local GRP=ff0e::${grp} 313 + local p=$(mldv1_done_get $SIP $GRP) 314 + $MZ -6 $peer -c 1 -A $SIP -B $GRP -t ip hop=1,next=0,p="$p" -q 315 + sleep 1 316 + ! bridge mdb show dev br0 | grep -q $GRP 317 + } 318 + 319 + bridge_maxgroups_errmsg_check_cfg() 320 + { 321 + local msg=$1; shift 322 + local needle=$1; shift 323 + 324 + echo "$msg" | grep -q mcast_max_groups 325 + check_err $? "Adding MDB entries failed for the wrong reason: $msg" 326 + } 327 + 328 + bridge_maxgroups_errmsg_check_cfg4() 329 + { 330 + bridge_maxgroups_errmsg_check_cfg "$@" 331 + } 332 + 333 + bridge_maxgroups_errmsg_check_cfg6() 334 + { 335 + bridge_maxgroups_errmsg_check_cfg "$@" 336 + } 337 + 338 + bridge_maxgroups_errmsg_check_ctl4() 339 + { 340 + : 341 + } 342 + 343 + bridge_maxgroups_errmsg_check_ctl6() 344 + { 345 + : 346 + } 347 + 348 + bridge_port_ngroups_get() 349 + { 350 + local locus=$1; shift 351 + 352 + bridge -j -d link show $locus | 353 + jq '.[].mcast_n_groups' 354 + } 355 + 356 + bridge_port_maxgroups_get() 357 + { 358 + local locus=$1; shift 359 + 360 + bridge -j -d link show $locus | 361 + jq '.[].mcast_max_groups' 362 + } 363 + 364 + bridge_port_maxgroups_set() 365 + { 366 + local locus=$1; shift 367 + local max=$1; shift 368 + 369 + bridge link set dev $(locus_dev $locus) mcast_max_groups $max 370 + } 371 + 372 + bridge_port_vlan_ngroups_get() 373 + { 374 + local locus=$1; shift 375 + 376 + bridge -j -d vlan show $locus | 377 + jq '.[].vlans[].mcast_n_groups' 378 + } 379 + 380 + bridge_port_vlan_maxgroups_get() 381 + { 382 + local locus=$1; shift 383 + 384 + bridge -j -d vlan show $locus | 385 + jq '.[].vlans[].mcast_max_groups' 386 + } 387 + 388 + bridge_port_vlan_maxgroups_set() 389 + { 390 + local locus=$1; shift 391 + local max=$1; shift 392 + 393 + bridge vlan set $locus mcast_max_groups $max 394 + } 395 + 396 + test_ngroups_reporting() 397 + { 398 + local CFG=$1; shift 399 + local context=$1; shift 400 + local locus=$1; shift 401 + 402 + RET=0 403 + 404 + local n0=$(bridge_${context}_ngroups_get "$locus") 405 + ${CFG}_entries_add "$locus" temp 5 406 + check_err $? "Couldn't add MDB entries" 407 + local n1=$(bridge_${context}_ngroups_get "$locus") 408 + 409 + ((n1 == n0 + 5)) 410 + check_err $? "Number of groups was $n0, now is $n1, but $((n0 + 5)) expected" 411 + 412 + ${CFG}_entries_del "$locus" temp 5 413 + check_err $? "Couldn't delete MDB entries" 414 + local n2=$(bridge_${context}_ngroups_get "$locus") 415 + 416 + ((n2 == n0)) 417 + check_err $? "Number of groups was $n0, now is $n2, but should be back to $n0" 418 + 419 + log_test "$CFG: $context: ngroups reporting" 420 + } 421 + 422 + test_8021d_ngroups_reporting_cfg4() 423 + { 424 + test_ngroups_reporting cfg4 port "dev $swp1" 425 + } 426 + 427 + test_8021d_ngroups_reporting_ctl4() 428 + { 429 + test_ngroups_reporting ctl4 port "dev $swp1" 430 + } 431 + 432 + test_8021d_ngroups_reporting_cfg6() 433 + { 434 + test_ngroups_reporting cfg6 port "dev $swp1" 435 + } 436 + 437 + test_8021d_ngroups_reporting_ctl6() 438 + { 439 + test_ngroups_reporting ctl6 port "dev $swp1" 440 + } 441 + 442 + test_8021q_ngroups_reporting_cfg4() 443 + { 444 + test_ngroups_reporting cfg4 port "dev $swp1 vid 10" 445 + } 446 + 447 + test_8021q_ngroups_reporting_ctl4() 448 + { 449 + test_ngroups_reporting ctl4 port "dev $swp1 vid 10" 450 + } 451 + 452 + test_8021q_ngroups_reporting_cfg6() 453 + { 454 + test_ngroups_reporting cfg6 port "dev $swp1 vid 10" 455 + } 456 + 457 + test_8021q_ngroups_reporting_ctl6() 458 + { 459 + test_ngroups_reporting ctl6 port "dev $swp1 vid 10" 460 + } 461 + 462 + test_8021qvs_ngroups_reporting_cfg4() 463 + { 464 + test_ngroups_reporting cfg4 port_vlan "dev $swp1 vid 10" 465 + } 466 + 467 + test_8021qvs_ngroups_reporting_ctl4() 468 + { 469 + test_ngroups_reporting ctl4 port_vlan "dev $swp1 vid 10" 470 + } 471 + 472 + test_8021qvs_ngroups_reporting_cfg6() 473 + { 474 + test_ngroups_reporting cfg6 port_vlan "dev $swp1 vid 10" 475 + } 476 + 477 + test_8021qvs_ngroups_reporting_ctl6() 478 + { 479 + test_ngroups_reporting ctl6 port_vlan "dev $swp1 vid 10" 480 + } 481 + 482 + test_ngroups_cross_vlan() 483 + { 484 + local CFG=$1; shift 485 + 486 + local locus1="dev $swp1 vid 10" 487 + local locus2="dev $swp1 vid 20" 488 + 489 + RET=0 490 + 491 + local n10=$(bridge_port_vlan_ngroups_get "$locus1") 492 + local n20=$(bridge_port_vlan_ngroups_get "$locus2") 493 + ${CFG}_entries_add "$locus1" temp 5 111 494 + check_err $? "Couldn't add MDB entries to VLAN 10" 495 + local n11=$(bridge_port_vlan_ngroups_get "$locus1") 496 + local n21=$(bridge_port_vlan_ngroups_get "$locus2") 497 + 498 + ((n11 == n10 + 5)) 499 + check_err $? "Number of groups at VLAN 10 was $n10, now is $n11, but 5 entries added on VLAN 10, $((n10 + 5)) expected" 500 + 501 + ((n21 == n20)) 502 + check_err $? "Number of groups at VLAN 20 was $n20, now is $n21, but no change expected on VLAN 20" 503 + 504 + ${CFG}_entries_add "$locus2" temp 5 112 505 + check_err $? "Couldn't add MDB entries to VLAN 20" 506 + local n12=$(bridge_port_vlan_ngroups_get "$locus1") 507 + local n22=$(bridge_port_vlan_ngroups_get "$locus2") 508 + 509 + ((n12 == n11)) 510 + check_err $? "Number of groups at VLAN 10 was $n11, now is $n12, but no change expected on VLAN 10" 511 + 512 + ((n22 == n21 + 5)) 513 + check_err $? "Number of groups at VLAN 20 was $n21, now is $n22, but 5 entries added on VLAN 20, $((n21 + 5)) expected" 514 + 515 + ${CFG}_entries_del "$locus1" temp 5 111 516 + check_err $? "Couldn't delete MDB entries from VLAN 10" 517 + ${CFG}_entries_del "$locus2" temp 5 112 518 + check_err $? "Couldn't delete MDB entries from VLAN 20" 519 + local n13=$(bridge_port_vlan_ngroups_get "$locus1") 520 + local n23=$(bridge_port_vlan_ngroups_get "$locus2") 521 + 522 + ((n13 == n10)) 523 + check_err $? "Number of groups at VLAN 10 was $n10, now is $n13, but should be back to $n10" 524 + 525 + ((n23 == n20)) 526 + check_err $? "Number of groups at VLAN 20 was $n20, now is $n23, but should be back to $n20" 527 + 528 + log_test "$CFG: port_vlan: isolation of port and per-VLAN ngroups" 529 + } 530 + 531 + test_8021qvs_ngroups_cross_vlan_cfg4() 532 + { 533 + test_ngroups_cross_vlan cfg4 534 + } 535 + 536 + test_8021qvs_ngroups_cross_vlan_ctl4() 537 + { 538 + test_ngroups_cross_vlan ctl4 539 + } 540 + 541 + test_8021qvs_ngroups_cross_vlan_cfg6() 542 + { 543 + test_ngroups_cross_vlan cfg6 544 + } 545 + 546 + test_8021qvs_ngroups_cross_vlan_ctl6() 547 + { 548 + test_ngroups_cross_vlan ctl6 549 + } 550 + 551 + test_maxgroups_zero() 552 + { 553 + local CFG=$1; shift 554 + local context=$1; shift 555 + local locus=$1; shift 556 + 557 + RET=0 558 + local max 559 + 560 + max=$(bridge_${context}_maxgroups_get "$locus") 561 + ((max == 0)) 562 + check_err $? "Max groups on $locus should be 0, but $max reported" 563 + 564 + bridge_${context}_maxgroups_set "$locus" 100 565 + check_err $? "Failed to set max to 100" 566 + max=$(bridge_${context}_maxgroups_get "$locus") 567 + ((max == 100)) 568 + check_err $? "Max groups expected to be 100, but $max reported" 569 + 570 + bridge_${context}_maxgroups_set "$locus" 0 571 + check_err $? "Couldn't set maximum to 0" 572 + 573 + # Test that setting 0 explicitly still serves as infinity. 574 + ${CFG}_entries_add "$locus" temp 5 575 + check_err $? "Adding 5 MDB entries failed but should have passed" 576 + ${CFG}_entries_del "$locus" temp 5 577 + check_err $? "Couldn't delete MDB entries" 578 + 579 + log_test "$CFG: $context maxgroups: reporting and treatment of 0" 580 + } 581 + 582 + test_8021d_maxgroups_zero_cfg4() 583 + { 584 + test_maxgroups_zero cfg4 port "dev $swp1" 585 + } 586 + 587 + test_8021d_maxgroups_zero_ctl4() 588 + { 589 + test_maxgroups_zero ctl4 port "dev $swp1" 590 + } 591 + 592 + test_8021d_maxgroups_zero_cfg6() 593 + { 594 + test_maxgroups_zero cfg6 port "dev $swp1" 595 + } 596 + 597 + test_8021d_maxgroups_zero_ctl6() 598 + { 599 + test_maxgroups_zero ctl6 port "dev $swp1" 600 + } 601 + 602 + test_8021q_maxgroups_zero_cfg4() 603 + { 604 + test_maxgroups_zero cfg4 port "dev $swp1 vid 10" 605 + } 606 + 607 + test_8021q_maxgroups_zero_ctl4() 608 + { 609 + test_maxgroups_zero ctl4 port "dev $swp1 vid 10" 610 + } 611 + 612 + test_8021q_maxgroups_zero_cfg6() 613 + { 614 + test_maxgroups_zero cfg6 port "dev $swp1 vid 10" 615 + } 616 + 617 + test_8021q_maxgroups_zero_ctl6() 618 + { 619 + test_maxgroups_zero ctl6 port "dev $swp1 vid 10" 620 + } 621 + 622 + test_8021qvs_maxgroups_zero_cfg4() 623 + { 624 + test_maxgroups_zero cfg4 port_vlan "dev $swp1 vid 10" 625 + } 626 + 627 + test_8021qvs_maxgroups_zero_ctl4() 628 + { 629 + test_maxgroups_zero ctl4 port_vlan "dev $swp1 vid 10" 630 + } 631 + 632 + test_8021qvs_maxgroups_zero_cfg6() 633 + { 634 + test_maxgroups_zero cfg6 port_vlan "dev $swp1 vid 10" 635 + } 636 + 637 + test_8021qvs_maxgroups_zero_ctl6() 638 + { 639 + test_maxgroups_zero ctl6 port_vlan "dev $swp1 vid 10" 640 + } 641 + 642 + test_maxgroups_zero_cross_vlan() 643 + { 644 + local CFG=$1; shift 645 + 646 + local locus0="dev $swp1" 647 + local locus1="dev $swp1 vid 10" 648 + local locus2="dev $swp1 vid 20" 649 + local max 650 + 651 + RET=0 652 + 653 + bridge_port_vlan_maxgroups_set "$locus1" 100 654 + check_err $? "$locus1: Failed to set max to 100" 655 + 656 + max=$(bridge_port_maxgroups_get "$locus0") 657 + ((max == 0)) 658 + check_err $? "$locus0: Max groups expected to be 0, but $max reported" 659 + 660 + max=$(bridge_port_vlan_maxgroups_get "$locus2") 661 + ((max == 0)) 662 + check_err $? "$locus2: Max groups expected to be 0, but $max reported" 663 + 664 + bridge_port_vlan_maxgroups_set "$locus2" 100 665 + check_err $? "$locus2: Failed to set max to 100" 666 + 667 + max=$(bridge_port_maxgroups_get "$locus0") 668 + ((max == 0)) 669 + check_err $? "$locus0: Max groups expected to be 0, but $max reported" 670 + 671 + max=$(bridge_port_vlan_maxgroups_get "$locus2") 672 + ((max == 100)) 673 + check_err $? "$locus2: Max groups expected to be 100, but $max reported" 674 + 675 + bridge_port_maxgroups_set "$locus0" 100 676 + check_err $? "$locus0: Failed to set max to 100" 677 + 678 + max=$(bridge_port_maxgroups_get "$locus0") 679 + ((max == 100)) 680 + check_err $? "$locus0: Max groups expected to be 100, but $max reported" 681 + 682 + max=$(bridge_port_vlan_maxgroups_get "$locus2") 683 + ((max == 100)) 684 + check_err $? "$locus2: Max groups expected to be 100, but $max reported" 685 + 686 + bridge_port_vlan_maxgroups_set "$locus1" 0 687 + check_err $? "$locus1: Failed to set max to 0" 688 + 689 + max=$(bridge_port_maxgroups_get "$locus0") 690 + ((max == 100)) 691 + check_err $? "$locus0: Max groups expected to be 100, but $max reported" 692 + 693 + max=$(bridge_port_vlan_maxgroups_get "$locus2") 694 + ((max == 100)) 695 + check_err $? "$locus2: Max groups expected to be 100, but $max reported" 696 + 697 + bridge_port_vlan_maxgroups_set "$locus2" 0 698 + check_err $? "$locus2: Failed to set max to 0" 699 + 700 + max=$(bridge_port_maxgroups_get "$locus0") 701 + ((max == 100)) 702 + check_err $? "$locus0: Max groups expected to be 100, but $max reported" 703 + 704 + max=$(bridge_port_vlan_maxgroups_get "$locus2") 705 + ((max == 0)) 706 + check_err $? "$locus2: Max groups expected to be 0 but $max reported" 707 + 708 + bridge_port_maxgroups_set "$locus0" 0 709 + check_err $? "$locus0: Failed to set max to 0" 710 + 711 + max=$(bridge_port_maxgroups_get "$locus0") 712 + ((max == 0)) 713 + check_err $? "$locus0: Max groups expected to be 0, but $max reported" 714 + 715 + max=$(bridge_port_vlan_maxgroups_get "$locus2") 716 + ((max == 0)) 717 + check_err $? "$locus2: Max groups expected to be 0, but $max reported" 718 + 719 + log_test "$CFG: port_vlan maxgroups: isolation of port and per-VLAN maximums" 720 + } 721 + 722 + test_8021qvs_maxgroups_zero_cross_vlan_cfg4() 723 + { 724 + test_maxgroups_zero_cross_vlan cfg4 725 + } 726 + 727 + test_8021qvs_maxgroups_zero_cross_vlan_ctl4() 728 + { 729 + test_maxgroups_zero_cross_vlan ctl4 730 + } 731 + 732 + test_8021qvs_maxgroups_zero_cross_vlan_cfg6() 733 + { 734 + test_maxgroups_zero_cross_vlan cfg6 735 + } 736 + 737 + test_8021qvs_maxgroups_zero_cross_vlan_ctl6() 738 + { 739 + test_maxgroups_zero_cross_vlan ctl6 740 + } 741 + 742 + test_maxgroups_too_low() 743 + { 744 + local CFG=$1; shift 745 + local context=$1; shift 746 + local locus=$1; shift 747 + 748 + RET=0 749 + 750 + local n=$(bridge_${context}_ngroups_get "$locus") 751 + local msg 752 + 753 + ${CFG}_entries_add "$locus" temp 5 111 754 + check_err $? "$locus: Couldn't add MDB entries" 755 + 756 + bridge_${context}_maxgroups_set "$locus" $((n+2)) 757 + check_err $? "$locus: Setting maxgroups to $((n+2)) failed" 758 + 759 + msg=$(${CFG}_entries_add "$locus" temp 2 112 2>&1) 760 + check_fail $? "$locus: Adding more entries passed when max<n" 761 + bridge_maxgroups_errmsg_check_cfg "$msg" 762 + 763 + ${CFG}_entries_del "$locus" temp 5 111 764 + check_err $? "$locus: Couldn't delete MDB entries" 765 + 766 + ${CFG}_entries_add "$locus" temp 2 112 767 + check_err $? "$locus: Adding more entries failed" 768 + 769 + ${CFG}_entries_del "$locus" temp 2 112 770 + check_err $? "$locus: Deleting more entries failed" 771 + 772 + bridge_${context}_maxgroups_set "$locus" 0 773 + check_err $? "$locus: Couldn't set maximum to 0" 774 + 775 + log_test "$CFG: $context maxgroups: configure below ngroups" 776 + } 777 + 778 + test_8021d_maxgroups_too_low_cfg4() 779 + { 780 + test_maxgroups_too_low cfg4 port "dev $swp1" 781 + } 782 + 783 + test_8021d_maxgroups_too_low_ctl4() 784 + { 785 + test_maxgroups_too_low ctl4 port "dev $swp1" 786 + } 787 + 788 + test_8021d_maxgroups_too_low_cfg6() 789 + { 790 + test_maxgroups_too_low cfg6 port "dev $swp1" 791 + } 792 + 793 + test_8021d_maxgroups_too_low_ctl6() 794 + { 795 + test_maxgroups_too_low ctl6 port "dev $swp1" 796 + } 797 + 798 + test_8021q_maxgroups_too_low_cfg4() 799 + { 800 + test_maxgroups_too_low cfg4 port "dev $swp1 vid 10" 801 + } 802 + 803 + test_8021q_maxgroups_too_low_ctl4() 804 + { 805 + test_maxgroups_too_low ctl4 port "dev $swp1 vid 10" 806 + } 807 + 808 + test_8021q_maxgroups_too_low_cfg6() 809 + { 810 + test_maxgroups_too_low cfg6 port "dev $swp1 vid 10" 811 + } 812 + 813 + test_8021q_maxgroups_too_low_ctl6() 814 + { 815 + test_maxgroups_too_low ctl6 port "dev $swp1 vid 10" 816 + } 817 + 818 + test_8021qvs_maxgroups_too_low_cfg4() 819 + { 820 + test_maxgroups_too_low cfg4 port_vlan "dev $swp1 vid 10" 821 + } 822 + 823 + test_8021qvs_maxgroups_too_low_ctl4() 824 + { 825 + test_maxgroups_too_low ctl4 port_vlan "dev $swp1 vid 10" 826 + } 827 + 828 + test_8021qvs_maxgroups_too_low_cfg6() 829 + { 830 + test_maxgroups_too_low cfg6 port_vlan "dev $swp1 vid 10" 831 + } 832 + 833 + test_8021qvs_maxgroups_too_low_ctl6() 834 + { 835 + test_maxgroups_too_low ctl6 port_vlan "dev $swp1 vid 10" 836 + } 837 + 838 + test_maxgroups_too_many_entries() 839 + { 840 + local CFG=$1; shift 841 + local context=$1; shift 842 + local locus=$1; shift 843 + 844 + RET=0 845 + 846 + local n=$(bridge_${context}_ngroups_get "$locus") 847 + local msg 848 + 849 + # Configure a low maximum 850 + bridge_${context}_maxgroups_set "$locus" $((n+1)) 851 + check_err $? "$locus: Couldn't set maximum" 852 + 853 + # Try to add more entries than the configured maximum 854 + msg=$(${CFG}_entries_add "$locus" temp 5 2>&1) 855 + check_fail $? "Adding 5 MDB entries passed, but should have failed" 856 + bridge_maxgroups_errmsg_check_${CFG} "$msg" 857 + 858 + # When adding entries through the control path, as many as possible 859 + # get created. That's consistent with the mcast_hash_max behavior. 860 + # So there, drop the entries explicitly. 861 + if [[ ${CFG%[46]} == ctl ]]; then 862 + ${CFG}_entries_del "$locus" temp 17 2>&1 863 + fi 864 + 865 + local n2=$(bridge_${context}_ngroups_get "$locus") 866 + ((n2 == n)) 867 + check_err $? "Number of groups was $n, but after a failed attempt to add MDB entries it changed to $n2" 868 + 869 + bridge_${context}_maxgroups_set "$locus" 0 870 + check_err $? "$locus: Couldn't set maximum to 0" 871 + 872 + log_test "$CFG: $context maxgroups: add too many MDB entries" 873 + } 874 + 875 + test_8021d_maxgroups_too_many_entries_cfg4() 876 + { 877 + test_maxgroups_too_many_entries cfg4 port "dev $swp1" 878 + } 879 + 880 + test_8021d_maxgroups_too_many_entries_ctl4() 881 + { 882 + test_maxgroups_too_many_entries ctl4 port "dev $swp1" 883 + } 884 + 885 + test_8021d_maxgroups_too_many_entries_cfg6() 886 + { 887 + test_maxgroups_too_many_entries cfg6 port "dev $swp1" 888 + } 889 + 890 + test_8021d_maxgroups_too_many_entries_ctl6() 891 + { 892 + test_maxgroups_too_many_entries ctl6 port "dev $swp1" 893 + } 894 + 895 + test_8021q_maxgroups_too_many_entries_cfg4() 896 + { 897 + test_maxgroups_too_many_entries cfg4 port "dev $swp1 vid 10" 898 + } 899 + 900 + test_8021q_maxgroups_too_many_entries_ctl4() 901 + { 902 + test_maxgroups_too_many_entries ctl4 port "dev $swp1 vid 10" 903 + } 904 + 905 + test_8021q_maxgroups_too_many_entries_cfg6() 906 + { 907 + test_maxgroups_too_many_entries cfg6 port "dev $swp1 vid 10" 908 + } 909 + 910 + test_8021q_maxgroups_too_many_entries_ctl6() 911 + { 912 + test_maxgroups_too_many_entries ctl6 port "dev $swp1 vid 10" 913 + } 914 + 915 + test_8021qvs_maxgroups_too_many_entries_cfg4() 916 + { 917 + test_maxgroups_too_many_entries cfg4 port_vlan "dev $swp1 vid 10" 918 + } 919 + 920 + test_8021qvs_maxgroups_too_many_entries_ctl4() 921 + { 922 + test_maxgroups_too_many_entries ctl4 port_vlan "dev $swp1 vid 10" 923 + } 924 + 925 + test_8021qvs_maxgroups_too_many_entries_cfg6() 926 + { 927 + test_maxgroups_too_many_entries cfg6 port_vlan "dev $swp1 vid 10" 928 + } 929 + 930 + test_8021qvs_maxgroups_too_many_entries_ctl6() 931 + { 932 + test_maxgroups_too_many_entries ctl6 port_vlan "dev $swp1 vid 10" 933 + } 934 + 935 + test_maxgroups_too_many_cross_vlan() 936 + { 937 + local CFG=$1; shift 938 + 939 + RET=0 940 + 941 + local locus0="dev $swp1" 942 + local locus1="dev $swp1 vid 10" 943 + local locus2="dev $swp1 vid 20" 944 + local n1=$(bridge_port_vlan_ngroups_get "$locus1") 945 + local n2=$(bridge_port_vlan_ngroups_get "$locus2") 946 + local msg 947 + 948 + if ((n1 > n2)); then 949 + local tmp=$n1 950 + n1=$n2 951 + n2=$tmp 952 + 953 + tmp="$locus1" 954 + locus1="$locus2" 955 + locus2="$tmp" 956 + fi 957 + 958 + # Now 0 <= n1 <= n2. 959 + ${CFG}_entries_add "$locus2" temp 5 112 960 + check_err $? "Couldn't add 5 entries" 961 + 962 + n2=$(bridge_port_vlan_ngroups_get "$locus2") 963 + # Now 0 <= n1 < n2-1. 964 + 965 + # Setting locus1'maxgroups to n2-1 should pass. The number is 966 + # smaller than both the absolute number of MDB entries, and in 967 + # particular than number of locus2's number of entries, but it is 968 + # large enough to cover locus1's entries. Thus we check that 969 + # individual VLAN's ngroups are independent. 970 + bridge_port_vlan_maxgroups_set "$locus1" $((n2-1)) 971 + check_err $? "Setting ${locus1}'s maxgroups to $((n2-1)) failed" 972 + 973 + msg=$(${CFG}_entries_add "$locus1" temp $n2 111 2>&1) 974 + check_fail $? "$locus1: Adding $n2 MDB entries passed, but should have failed" 975 + bridge_maxgroups_errmsg_check_${CFG} "$msg" 976 + 977 + bridge_port_maxgroups_set "$locus0" $((n1 + n2 + 2)) 978 + check_err $? "$locus0: Couldn't set maximum" 979 + 980 + msg=$(${CFG}_entries_add "$locus1" temp 5 111 2>&1) 981 + check_fail $? "$locus1: Adding 5 MDB entries passed, but should have failed" 982 + bridge_maxgroups_errmsg_check_${CFG} "$msg" 983 + 984 + # IGMP/MLD packets can cause several entries to be added, before 985 + # the maximum is hit and the rest is then bounced. Remove what was 986 + # committed, if anything. 987 + ${CFG}_entries_del "$locus1" temp 5 111 2>/dev/null 988 + 989 + ${CFG}_entries_add "$locus1" temp 2 111 990 + check_err $? "$locus1: Adding 2 MDB entries failed, but should have passed" 991 + 992 + ${CFG}_entries_del "$locus1" temp 2 111 993 + check_err $? "Couldn't delete MDB entries" 994 + 995 + ${CFG}_entries_del "$locus2" temp 5 112 996 + check_err $? "Couldn't delete MDB entries" 997 + 998 + bridge_port_vlan_maxgroups_set "$locus1" 0 999 + check_err $? "$locus1: Couldn't set maximum to 0" 1000 + 1001 + bridge_port_maxgroups_set "$locus0" 0 1002 + check_err $? "$locus0: Couldn't set maximum to 0" 1003 + 1004 + log_test "$CFG: port_vlan maxgroups: isolation of port and per-VLAN ngroups" 1005 + } 1006 + 1007 + test_8021qvs_maxgroups_too_many_cross_vlan_cfg4() 1008 + { 1009 + test_maxgroups_too_many_cross_vlan cfg4 1010 + } 1011 + 1012 + test_8021qvs_maxgroups_too_many_cross_vlan_ctl4() 1013 + { 1014 + test_maxgroups_too_many_cross_vlan ctl4 1015 + } 1016 + 1017 + test_8021qvs_maxgroups_too_many_cross_vlan_cfg6() 1018 + { 1019 + test_maxgroups_too_many_cross_vlan cfg6 1020 + } 1021 + 1022 + test_8021qvs_maxgroups_too_many_cross_vlan_ctl6() 1023 + { 1024 + test_maxgroups_too_many_cross_vlan ctl6 1025 + } 1026 + 1027 + test_vlan_attributes() 1028 + { 1029 + local locus=$1; shift 1030 + local expect=$1; shift 1031 + 1032 + RET=0 1033 + 1034 + local max=$(bridge_port_vlan_maxgroups_get "$locus") 1035 + local n=$(bridge_port_vlan_ngroups_get "$locus") 1036 + 1037 + eval "[[ $max $expect ]]" 1038 + check_err $? "$locus: maxgroups attribute expected to be $expect, but was $max" 1039 + 1040 + eval "[[ $n $expect ]]" 1041 + check_err $? "$locus: ngroups attribute expected to be $expect, but was $n" 1042 + 1043 + log_test "port_vlan: presence of ngroups and maxgroups attributes" 1044 + } 1045 + 1046 + test_8021q_vlan_attributes() 1047 + { 1048 + test_vlan_attributes "dev $swp1 vid 10" "== null" 1049 + } 1050 + 1051 + test_8021qvs_vlan_attributes() 1052 + { 1053 + test_vlan_attributes "dev $swp1 vid 10" "-ge 0" 1054 + } 1055 + 1056 + test_toggle_vlan_snooping() 1057 + { 1058 + local mode=$1; shift 1059 + 1060 + RET=0 1061 + 1062 + local CFG=cfg4 1063 + local context=port_vlan 1064 + local locus="dev $swp1 vid 10" 1065 + 1066 + ${CFG}_entries_add "$locus" $mode 5 1067 + check_err $? "Couldn't add MDB entries" 1068 + 1069 + bridge_${context}_maxgroups_set "$locus" 100 1070 + check_err $? "Failed to set max to 100" 1071 + 1072 + ip link set dev br0 type bridge mcast_vlan_snooping 0 1073 + sleep 1 1074 + ip link set dev br0 type bridge mcast_vlan_snooping 1 1075 + 1076 + local n=$(bridge_${context}_ngroups_get "$locus") 1077 + local nn=$(bridge mdb show dev br0 | grep $swp1 | wc -l) 1078 + ((nn == n)) 1079 + check_err $? "mcast_n_groups expected to be $nn, but $n reported" 1080 + 1081 + local max=$(bridge_${context}_maxgroups_get "$locus") 1082 + ((max == 100)) 1083 + check_err $? "Max groups expected to be 100 but $max reported" 1084 + 1085 + bridge_${context}_maxgroups_set "$locus" 0 1086 + check_err $? "Failed to set max to 0" 1087 + 1088 + log_test "$CFG: $context: $mode: mcast_vlan_snooping toggle" 1089 + } 1090 + 1091 + test_toggle_vlan_snooping_temp() 1092 + { 1093 + test_toggle_vlan_snooping temp 1094 + } 1095 + 1096 + test_toggle_vlan_snooping_permanent() 1097 + { 1098 + test_toggle_vlan_snooping permanent 1099 + } 1100 + 1101 + # ngroup test suites 1102 + 1103 + test_8021d_ngroups_cfg4() 1104 + { 1105 + test_8021d_ngroups_reporting_cfg4 1106 + } 1107 + 1108 + test_8021d_ngroups_ctl4() 1109 + { 1110 + test_8021d_ngroups_reporting_ctl4 1111 + } 1112 + 1113 + test_8021d_ngroups_cfg6() 1114 + { 1115 + test_8021d_ngroups_reporting_cfg6 1116 + } 1117 + 1118 + test_8021d_ngroups_ctl6() 1119 + { 1120 + test_8021d_ngroups_reporting_ctl6 1121 + } 1122 + 1123 + test_8021q_ngroups_cfg4() 1124 + { 1125 + test_8021q_ngroups_reporting_cfg4 1126 + } 1127 + 1128 + test_8021q_ngroups_ctl4() 1129 + { 1130 + test_8021q_ngroups_reporting_ctl4 1131 + } 1132 + 1133 + test_8021q_ngroups_cfg6() 1134 + { 1135 + test_8021q_ngroups_reporting_cfg6 1136 + } 1137 + 1138 + test_8021q_ngroups_ctl6() 1139 + { 1140 + test_8021q_ngroups_reporting_ctl6 1141 + } 1142 + 1143 + test_8021qvs_ngroups_cfg4() 1144 + { 1145 + test_8021qvs_ngroups_reporting_cfg4 1146 + test_8021qvs_ngroups_cross_vlan_cfg4 1147 + } 1148 + 1149 + test_8021qvs_ngroups_ctl4() 1150 + { 1151 + test_8021qvs_ngroups_reporting_ctl4 1152 + test_8021qvs_ngroups_cross_vlan_ctl4 1153 + } 1154 + 1155 + test_8021qvs_ngroups_cfg6() 1156 + { 1157 + test_8021qvs_ngroups_reporting_cfg6 1158 + test_8021qvs_ngroups_cross_vlan_cfg6 1159 + } 1160 + 1161 + test_8021qvs_ngroups_ctl6() 1162 + { 1163 + test_8021qvs_ngroups_reporting_ctl6 1164 + test_8021qvs_ngroups_cross_vlan_ctl6 1165 + } 1166 + 1167 + # maxgroups test suites 1168 + 1169 + test_8021d_maxgroups_cfg4() 1170 + { 1171 + test_8021d_maxgroups_zero_cfg4 1172 + test_8021d_maxgroups_too_low_cfg4 1173 + test_8021d_maxgroups_too_many_entries_cfg4 1174 + } 1175 + 1176 + test_8021d_maxgroups_ctl4() 1177 + { 1178 + test_8021d_maxgroups_zero_ctl4 1179 + test_8021d_maxgroups_too_low_ctl4 1180 + test_8021d_maxgroups_too_many_entries_ctl4 1181 + } 1182 + 1183 + test_8021d_maxgroups_cfg6() 1184 + { 1185 + test_8021d_maxgroups_zero_cfg6 1186 + test_8021d_maxgroups_too_low_cfg6 1187 + test_8021d_maxgroups_too_many_entries_cfg6 1188 + } 1189 + 1190 + test_8021d_maxgroups_ctl6() 1191 + { 1192 + test_8021d_maxgroups_zero_ctl6 1193 + test_8021d_maxgroups_too_low_ctl6 1194 + test_8021d_maxgroups_too_many_entries_ctl6 1195 + } 1196 + 1197 + test_8021q_maxgroups_cfg4() 1198 + { 1199 + test_8021q_maxgroups_zero_cfg4 1200 + test_8021q_maxgroups_too_low_cfg4 1201 + test_8021q_maxgroups_too_many_entries_cfg4 1202 + } 1203 + 1204 + test_8021q_maxgroups_ctl4() 1205 + { 1206 + test_8021q_maxgroups_zero_ctl4 1207 + test_8021q_maxgroups_too_low_ctl4 1208 + test_8021q_maxgroups_too_many_entries_ctl4 1209 + } 1210 + 1211 + test_8021q_maxgroups_cfg6() 1212 + { 1213 + test_8021q_maxgroups_zero_cfg6 1214 + test_8021q_maxgroups_too_low_cfg6 1215 + test_8021q_maxgroups_too_many_entries_cfg6 1216 + } 1217 + 1218 + test_8021q_maxgroups_ctl6() 1219 + { 1220 + test_8021q_maxgroups_zero_ctl6 1221 + test_8021q_maxgroups_too_low_ctl6 1222 + test_8021q_maxgroups_too_many_entries_ctl6 1223 + } 1224 + 1225 + test_8021qvs_maxgroups_cfg4() 1226 + { 1227 + test_8021qvs_maxgroups_zero_cfg4 1228 + test_8021qvs_maxgroups_zero_cross_vlan_cfg4 1229 + test_8021qvs_maxgroups_too_low_cfg4 1230 + test_8021qvs_maxgroups_too_many_entries_cfg4 1231 + test_8021qvs_maxgroups_too_many_cross_vlan_cfg4 1232 + } 1233 + 1234 + test_8021qvs_maxgroups_ctl4() 1235 + { 1236 + test_8021qvs_maxgroups_zero_ctl4 1237 + test_8021qvs_maxgroups_zero_cross_vlan_ctl4 1238 + test_8021qvs_maxgroups_too_low_ctl4 1239 + test_8021qvs_maxgroups_too_many_entries_ctl4 1240 + test_8021qvs_maxgroups_too_many_cross_vlan_ctl4 1241 + } 1242 + 1243 + test_8021qvs_maxgroups_cfg6() 1244 + { 1245 + test_8021qvs_maxgroups_zero_cfg6 1246 + test_8021qvs_maxgroups_zero_cross_vlan_cfg6 1247 + test_8021qvs_maxgroups_too_low_cfg6 1248 + test_8021qvs_maxgroups_too_many_entries_cfg6 1249 + test_8021qvs_maxgroups_too_many_cross_vlan_cfg6 1250 + } 1251 + 1252 + test_8021qvs_maxgroups_ctl6() 1253 + { 1254 + test_8021qvs_maxgroups_zero_ctl6 1255 + test_8021qvs_maxgroups_zero_cross_vlan_ctl6 1256 + test_8021qvs_maxgroups_too_low_ctl6 1257 + test_8021qvs_maxgroups_too_many_entries_ctl6 1258 + test_8021qvs_maxgroups_too_many_cross_vlan_ctl6 1259 + } 1260 + 1261 + # other test suites 1262 + 1263 + test_8021qvs_toggle_vlan_snooping() 1264 + { 1265 + test_toggle_vlan_snooping_temp 1266 + test_toggle_vlan_snooping_permanent 1267 + } 1268 + 1269 + # test groups 1270 + 1271 + test_8021d() 1272 + { 1273 + # Tests for vlan_filtering 0 mcast_vlan_snooping 0. 1274 + 1275 + switch_create_8021d 1276 + setup_wait 1277 + 1278 + test_8021d_ngroups_cfg4 1279 + test_8021d_ngroups_ctl4 1280 + test_8021d_ngroups_cfg6 1281 + test_8021d_ngroups_ctl6 1282 + test_8021d_maxgroups_cfg4 1283 + test_8021d_maxgroups_ctl4 1284 + test_8021d_maxgroups_cfg6 1285 + test_8021d_maxgroups_ctl6 1286 + 1287 + switch_destroy 1288 + } 1289 + 1290 + test_8021q() 1291 + { 1292 + # Tests for vlan_filtering 1 mcast_vlan_snooping 0. 1293 + 1294 + switch_create_8021q 1295 + setup_wait 1296 + 1297 + test_8021q_vlan_attributes 1298 + test_8021q_ngroups_cfg4 1299 + test_8021q_ngroups_ctl4 1300 + test_8021q_ngroups_cfg6 1301 + test_8021q_ngroups_ctl6 1302 + test_8021q_maxgroups_cfg4 1303 + test_8021q_maxgroups_ctl4 1304 + test_8021q_maxgroups_cfg6 1305 + test_8021q_maxgroups_ctl6 1306 + 1307 + switch_destroy 1308 + } 1309 + 1310 + test_8021qvs() 1311 + { 1312 + # Tests for vlan_filtering 1 mcast_vlan_snooping 1. 1313 + 1314 + switch_create_8021qvs 1315 + setup_wait 1316 + 1317 + test_8021qvs_vlan_attributes 1318 + test_8021qvs_ngroups_cfg4 1319 + test_8021qvs_ngroups_ctl4 1320 + test_8021qvs_ngroups_cfg6 1321 + test_8021qvs_ngroups_ctl6 1322 + test_8021qvs_maxgroups_cfg4 1323 + test_8021qvs_maxgroups_ctl4 1324 + test_8021qvs_maxgroups_cfg6 1325 + test_8021qvs_maxgroups_ctl6 1326 + test_8021qvs_toggle_vlan_snooping 1327 + 1328 + switch_destroy 1329 + } 1330 + 1331 + trap cleanup EXIT 1332 + 1333 + setup_prepare 1334 + tests_run 1335 + 1336 + exit $EXIT_STATUS
+216
tools/testing/selftests/net/forwarding/lib.sh
··· 1671 1671 1672 1672 log_test "${type}_stats notifications" 1673 1673 } 1674 + 1675 + ipv4_to_bytes() 1676 + { 1677 + local IP=$1; shift 1678 + 1679 + printf '%02x:' ${IP//./ } | 1680 + sed 's/:$//' 1681 + } 1682 + 1683 + # Convert a given IPv6 address, `IP' such that the :: token, if present, is 1684 + # expanded, and each 16-bit group is padded with zeroes to be 4 hexadecimal 1685 + # digits. An optional `BYTESEP' parameter can be given to further separate 1686 + # individual bytes of each 16-bit group. 1687 + expand_ipv6() 1688 + { 1689 + local IP=$1; shift 1690 + local bytesep=$1; shift 1691 + 1692 + local cvt_ip=${IP/::/_} 1693 + local colons=${cvt_ip//[^:]/} 1694 + local allcol=::::::: 1695 + # IP where :: -> the appropriate number of colons: 1696 + local allcol_ip=${cvt_ip/_/${allcol:${#colons}}} 1697 + 1698 + echo $allcol_ip | tr : '\n' | 1699 + sed s/^/0000/ | 1700 + sed 's/.*\(..\)\(..\)/\1'"$bytesep"'\2/' | 1701 + tr '\n' : | 1702 + sed 's/:$//' 1703 + } 1704 + 1705 + ipv6_to_bytes() 1706 + { 1707 + local IP=$1; shift 1708 + 1709 + expand_ipv6 "$IP" : 1710 + } 1711 + 1712 + u16_to_bytes() 1713 + { 1714 + local u16=$1; shift 1715 + 1716 + printf "%04x" $u16 | sed 's/^/000/;s/^.*\(..\)\(..\)$/\1:\2/' 1717 + } 1718 + 1719 + # Given a mausezahn-formatted payload (colon-separated bytes given as %02x), 1720 + # possibly with a keyword CHECKSUM stashed where a 16-bit checksum should be, 1721 + # calculate checksum as per RFC 1071, assuming the CHECKSUM field (if any) 1722 + # stands for 00:00. 1723 + payload_template_calc_checksum() 1724 + { 1725 + local payload=$1; shift 1726 + 1727 + ( 1728 + # Set input radix. 1729 + echo "16i" 1730 + # Push zero for the initial checksum. 1731 + echo 0 1732 + 1733 + # Pad the payload with a terminating 00: in case we get an odd 1734 + # number of bytes. 1735 + echo "${payload%:}:00:" | 1736 + sed 's/CHECKSUM/00:00/g' | 1737 + tr '[:lower:]' '[:upper:]' | 1738 + # Add the word to the checksum. 1739 + sed 's/\(..\):\(..\):/\1\2+\n/g' | 1740 + # Strip the extra odd byte we pushed if left unconverted. 1741 + sed 's/\(..\):$//' 1742 + 1743 + echo "10000 ~ +" # Calculate and add carry. 1744 + echo "FFFF r - p" # Bit-flip and print. 1745 + ) | 1746 + dc | 1747 + tr '[:upper:]' '[:lower:]' 1748 + } 1749 + 1750 + payload_template_expand_checksum() 1751 + { 1752 + local payload=$1; shift 1753 + local checksum=$1; shift 1754 + 1755 + local ckbytes=$(u16_to_bytes $checksum) 1756 + 1757 + echo "$payload" | sed "s/CHECKSUM/$ckbytes/g" 1758 + } 1759 + 1760 + payload_template_nbytes() 1761 + { 1762 + local payload=$1; shift 1763 + 1764 + payload_template_expand_checksum "${payload%:}" 0 | 1765 + sed 's/:/\n/g' | wc -l 1766 + } 1767 + 1768 + igmpv3_is_in_get() 1769 + { 1770 + local GRP=$1; shift 1771 + local sources=("$@") 1772 + 1773 + local igmpv3 1774 + local nsources=$(u16_to_bytes ${#sources[@]}) 1775 + 1776 + # IS_IN ( $sources ) 1777 + igmpv3=$(: 1778 + )"22:"$( : Type - Membership Report 1779 + )"00:"$( : Reserved 1780 + )"CHECKSUM:"$( : Checksum 1781 + )"00:00:"$( : Reserved 1782 + )"00:01:"$( : Number of Group Records 1783 + )"01:"$( : Record Type - IS_IN 1784 + )"00:"$( : Aux Data Len 1785 + )"${nsources}:"$( : Number of Sources 1786 + )"$(ipv4_to_bytes $GRP):"$( : Multicast Address 1787 + )"$(for src in "${sources[@]}"; do 1788 + ipv4_to_bytes $src 1789 + echo -n : 1790 + done)"$( : Source Addresses 1791 + ) 1792 + local checksum=$(payload_template_calc_checksum "$igmpv3") 1793 + 1794 + payload_template_expand_checksum "$igmpv3" $checksum 1795 + } 1796 + 1797 + igmpv2_leave_get() 1798 + { 1799 + local GRP=$1; shift 1800 + 1801 + local payload=$(: 1802 + )"17:"$( : Type - Leave Group 1803 + )"00:"$( : Max Resp Time - not meaningful 1804 + )"CHECKSUM:"$( : Checksum 1805 + )"$(ipv4_to_bytes $GRP)"$( : Group Address 1806 + ) 1807 + local checksum=$(payload_template_calc_checksum "$payload") 1808 + 1809 + payload_template_expand_checksum "$payload" $checksum 1810 + } 1811 + 1812 + mldv2_is_in_get() 1813 + { 1814 + local SIP=$1; shift 1815 + local GRP=$1; shift 1816 + local sources=("$@") 1817 + 1818 + local hbh 1819 + local icmpv6 1820 + local nsources=$(u16_to_bytes ${#sources[@]}) 1821 + 1822 + hbh=$(: 1823 + )"3a:"$( : Next Header - ICMPv6 1824 + )"00:"$( : Hdr Ext Len 1825 + )"00:00:00:00:00:00:"$( : Options and Padding 1826 + ) 1827 + 1828 + icmpv6=$(: 1829 + )"8f:"$( : Type - MLDv2 Report 1830 + )"00:"$( : Code 1831 + )"CHECKSUM:"$( : Checksum 1832 + )"00:00:"$( : Reserved 1833 + )"00:01:"$( : Number of Group Records 1834 + )"01:"$( : Record Type - IS_IN 1835 + )"00:"$( : Aux Data Len 1836 + )"${nsources}:"$( : Number of Sources 1837 + )"$(ipv6_to_bytes $GRP):"$( : Multicast address 1838 + )"$(for src in "${sources[@]}"; do 1839 + ipv6_to_bytes $src 1840 + echo -n : 1841 + done)"$( : Source Addresses 1842 + ) 1843 + 1844 + local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6)) 1845 + local sudohdr=$(: 1846 + )"$(ipv6_to_bytes $SIP):"$( : SIP 1847 + )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address 1848 + )"${len}:"$( : Upper-layer length 1849 + )"00:3a:"$( : Zero and next-header 1850 + ) 1851 + local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6}) 1852 + 1853 + payload_template_expand_checksum "$hbh$icmpv6" $checksum 1854 + } 1855 + 1856 + mldv1_done_get() 1857 + { 1858 + local SIP=$1; shift 1859 + local GRP=$1; shift 1860 + 1861 + local hbh 1862 + local icmpv6 1863 + 1864 + hbh=$(: 1865 + )"3a:"$( : Next Header - ICMPv6 1866 + )"00:"$( : Hdr Ext Len 1867 + )"00:00:00:00:00:00:"$( : Options and Padding 1868 + ) 1869 + 1870 + icmpv6=$(: 1871 + )"84:"$( : Type - MLDv1 Done 1872 + )"00:"$( : Code 1873 + )"CHECKSUM:"$( : Checksum 1874 + )"00:00:"$( : Max Resp Delay - not meaningful 1875 + )"00:00:"$( : Reserved 1876 + )"$(ipv6_to_bytes $GRP):"$( : Multicast address 1877 + ) 1878 + 1879 + local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6)) 1880 + local sudohdr=$(: 1881 + )"$(ipv6_to_bytes $SIP):"$( : SIP 1882 + )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address 1883 + )"${len}:"$( : Upper-layer length 1884 + )"00:3a:"$( : Zero and next-header 1885 + ) 1886 + local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6}) 1887 + 1888 + payload_template_expand_checksum "$hbh$icmpv6" $checksum 1889 + }