diff options
author | Jakub Kicinski <kuba@kernel.org> | 2021-01-27 17:40:36 -0800 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2021-01-27 17:40:37 -0800 |
commit | c7f3489bfce36d273c51e2c29d7ff2b9184ab145 (patch) | |
tree | ceb3a5e7bd00174202d0b1aad547ce909c29f389 | |
parent | 1d96006dccf0994dd91f327f59493afd6398b01d (diff) | |
parent | 2dba407f994e5b0eb3b70a8cb280e014ec4a7ff3 (diff) | |
download | linux-c7f3489bfce36d273c51e2c29d7ff2b9184ab145.tar.gz linux-c7f3489bfce36d273c51e2c29d7ff2b9184ab145.tar.bz2 linux-c7f3489bfce36d273c51e2c29d7ff2b9184ab145.zip |
Merge branch 'net-bridge-multicast-per-port-eht-hosts-limit'
Nikolay Aleksandrov says:
====================
net: bridge: multicast: per-port EHT hosts limit
This set adds a simple configurable per-port EHT tracked hosts limit.
Patch 01 adds a default limit of 512 tracked hosts per-port, since the EHT
changes are still only in net-next that shouldn't be a problem. Then
patch 02 adds the ability to configure and retrieve the hosts limit
and to retrieve the current number of tracked hosts per port.
Let's be on the safe side and limit the number of tracked hosts by
default while allowing the user to increase that limit if needed.
====================
Link: https://lore.kernel.org/r/20210126093533.441338-1-razor@blackwall.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r-- | include/uapi/linux/if_link.h | 2 | ||||
-rw-r--r-- | net/bridge/br_multicast.c | 1 | ||||
-rw-r--r-- | net/bridge/br_multicast_eht.c | 22 | ||||
-rw-r--r-- | net/bridge/br_netlink.c | 19 | ||||
-rw-r--r-- | net/bridge/br_private.h | 2 | ||||
-rw-r--r-- | net/bridge/br_private_mcast_eht.h | 28 | ||||
-rw-r--r-- | net/bridge/br_sysfs_if.c | 26 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 2 |
8 files changed, 100 insertions, 2 deletions
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 2bd0d8bbcdb2..eb8018c3a737 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -525,6 +525,8 @@ enum { IFLA_BRPORT_BACKUP_PORT, IFLA_BRPORT_MRP_RING_OPEN, IFLA_BRPORT_MRP_IN_OPEN, + IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT, + IFLA_BRPORT_MCAST_EHT_HOSTS_CNT, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 3aa2833f60c7..6f672eb7ff33 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1608,6 +1608,7 @@ static void br_mc_disabled_update(struct net_device *dev, bool value) int br_multicast_add_port(struct net_bridge_port *port) { port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY; + port->multicast_eht_hosts_limit = BR_MCAST_DEFAULT_EHT_HOSTS_LIMIT; timer_setup(&port->multicast_router_timer, br_multicast_router_expired, 0); diff --git a/net/bridge/br_multicast_eht.c b/net/bridge/br_multicast_eht.c index ff9b3ba37cab..fea38b9a7268 100644 --- a/net/bridge/br_multicast_eht.c +++ b/net/bridge/br_multicast_eht.c @@ -127,6 +127,8 @@ static void __eht_destroy_host(struct net_bridge_group_eht_host *eht_host) { WARN_ON(!hlist_empty(&eht_host->set_entries)); + br_multicast_eht_hosts_dec(eht_host->pg); + rb_erase(&eht_host->rb_node, &eht_host->pg->eht_host_tree); RB_CLEAR_NODE(&eht_host->rb_node); kfree(eht_host); @@ -257,6 +259,9 @@ __eht_lookup_create_host(struct net_bridge_port_group *pg, return this; } + if (br_multicast_eht_hosts_over_limit(pg)) + return NULL; + eht_host = kzalloc(sizeof(*eht_host), GFP_ATOMIC); if (!eht_host) return NULL; @@ -269,6 +274,8 @@ __eht_lookup_create_host(struct net_bridge_port_group *pg, rb_link_node(&eht_host->rb_node, parent, link); rb_insert_color(&eht_host->rb_node, &pg->eht_host_tree); + br_multicast_eht_hosts_inc(pg); + return eht_host; } @@ -854,3 +861,18 @@ bool br_multicast_eht_handle(struct net_bridge_port_group *pg, out: return changed; } + +int br_multicast_eht_set_hosts_limit(struct net_bridge_port *p, + u32 eht_hosts_limit) +{ + struct net_bridge *br = p->br; + + if (!eht_hosts_limit) + return -EINVAL; + + spin_lock_bh(&br->multicast_lock); + p->multicast_eht_hosts_limit = eht_hosts_limit; + spin_unlock_bh(&br->multicast_lock); + + return 0; +} diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 762f273802cd..bd3962da345a 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -18,6 +18,7 @@ #include "br_private_stp.h" #include "br_private_cfm.h" #include "br_private_tunnel.h" +#include "br_private_mcast_eht.h" static int __get_num_vlan_infos(struct net_bridge_vlan_group *vg, u32 filter_mask) @@ -199,6 +200,8 @@ static inline size_t br_port_info_size(void) + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_GROUP_FWD_MASK */ + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MRP_RING_OPEN */ + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MRP_IN_OPEN */ + + nla_total_size(sizeof(u32)) /* IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT */ + + nla_total_size(sizeof(u32)) /* IFLA_BRPORT_MCAST_EHT_HOSTS_CNT */ + 0; } @@ -283,7 +286,11 @@ static int br_port_fill_attrs(struct sk_buff *skb, #ifdef CONFIG_BRIDGE_IGMP_SNOOPING if (nla_put_u8(skb, IFLA_BRPORT_MULTICAST_ROUTER, - p->multicast_router)) + p->multicast_router) || + nla_put_u32(skb, IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT, + p->multicast_eht_hosts_limit) || + nla_put_u32(skb, IFLA_BRPORT_MCAST_EHT_HOSTS_CNT, + p->multicast_eht_hosts_cnt)) return -EMSGSIZE; #endif @@ -820,6 +827,7 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = { [IFLA_BRPORT_NEIGH_SUPPRESS] = { .type = NLA_U8 }, [IFLA_BRPORT_ISOLATED] = { .type = NLA_U8 }, [IFLA_BRPORT_BACKUP_PORT] = { .type = NLA_U32 }, + [IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT] = { .type = NLA_U32 }, }; /* Change the state of the port and notify spanning tree */ @@ -955,6 +963,15 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) if (err) return err; } + + if (tb[IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT]) { + u32 hlimit; + + hlimit = nla_get_u32(tb[IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT]); + err = br_multicast_eht_set_hosts_limit(p, hlimit); + if (err) + return err; + } #endif if (tb[IFLA_BRPORT_GROUP_FWD_MASK]) { diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 0e26ba623006..d242ba668e47 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -310,6 +310,8 @@ struct net_bridge_port { #if IS_ENABLED(CONFIG_IPV6) struct bridge_mcast_own_query ip6_own_query; #endif /* IS_ENABLED(CONFIG_IPV6) */ + u32 multicast_eht_hosts_limit; + u32 multicast_eht_hosts_cnt; unsigned char multicast_router; struct bridge_mcast_stats __percpu *mcast_stats; struct timer_list multicast_router_timer; diff --git a/net/bridge/br_private_mcast_eht.h b/net/bridge/br_private_mcast_eht.h index 9daffa3ad8d5..f89049f4892c 100644 --- a/net/bridge/br_private_mcast_eht.h +++ b/net/bridge/br_private_mcast_eht.h @@ -4,6 +4,8 @@ #ifndef _BR_PRIVATE_MCAST_EHT_H_ #define _BR_PRIVATE_MCAST_EHT_H_ +#define BR_MCAST_DEFAULT_EHT_HOSTS_LIMIT 512 + union net_bridge_eht_addr { __be32 ip4; #if IS_ENABLED(CONFIG_IPV6) @@ -47,6 +49,7 @@ struct net_bridge_group_eht_set { struct net_bridge_mcast_gc mcast_gc; }; +#ifdef CONFIG_BRIDGE_IGMP_SNOOPING void br_multicast_eht_clean_sets(struct net_bridge_port_group *pg); bool br_multicast_eht_handle(struct net_bridge_port_group *pg, void *h_addr, @@ -54,6 +57,8 @@ bool br_multicast_eht_handle(struct net_bridge_port_group *pg, u32 nsrcs, size_t addr_size, int grec_type); +int br_multicast_eht_set_hosts_limit(struct net_bridge_port *p, + u32 eht_hosts_limit); static inline bool br_multicast_eht_should_del_pg(const struct net_bridge_port_group *pg) @@ -62,4 +67,27 @@ br_multicast_eht_should_del_pg(const struct net_bridge_port_group *pg) RB_EMPTY_ROOT(&pg->eht_host_tree)); } +static inline bool +br_multicast_eht_hosts_over_limit(const struct net_bridge_port_group *pg) +{ + const struct net_bridge_port *p = pg->key.port; + + return !!(p->multicast_eht_hosts_cnt >= p->multicast_eht_hosts_limit); +} + +static inline void br_multicast_eht_hosts_inc(struct net_bridge_port_group *pg) +{ + struct net_bridge_port *p = pg->key.port; + + p->multicast_eht_hosts_cnt++; +} + +static inline void br_multicast_eht_hosts_dec(struct net_bridge_port_group *pg) +{ + struct net_bridge_port *p = pg->key.port; + + p->multicast_eht_hosts_cnt--; +} +#endif /* CONFIG_BRIDGE_IGMP_SNOOPING */ + #endif /* _BR_PRIVATE_MCAST_EHT_H_ */ diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 7a59cdddd3ce..b66305fae26b 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -16,6 +16,7 @@ #include <linux/sched/signal.h> #include "br_private.h" +#include "br_private_mcast_eht.h" struct brport_attribute { struct attribute attr; @@ -245,6 +246,29 @@ static int store_multicast_router(struct net_bridge_port *p, static BRPORT_ATTR(multicast_router, 0644, show_multicast_router, store_multicast_router); +static ssize_t show_multicast_eht_hosts_limit(struct net_bridge_port *p, + char *buf) +{ + return sprintf(buf, "%u\n", p->multicast_eht_hosts_limit); +} + +static int store_multicast_eht_hosts_limit(struct net_bridge_port *p, + unsigned long v) +{ + return br_multicast_eht_set_hosts_limit(p, v); +} +static BRPORT_ATTR(multicast_eht_hosts_limit, 0644, + show_multicast_eht_hosts_limit, + store_multicast_eht_hosts_limit); + +static ssize_t show_multicast_eht_hosts_cnt(struct net_bridge_port *p, + char *buf) +{ + return sprintf(buf, "%u\n", p->multicast_eht_hosts_cnt); +} +static BRPORT_ATTR(multicast_eht_hosts_cnt, 0444, show_multicast_eht_hosts_cnt, + NULL); + BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE); BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UNICAST); #endif @@ -274,6 +298,8 @@ static const struct brport_attribute *brport_attrs[] = { &brport_attr_multicast_router, &brport_attr_multicast_fast_leave, &brport_attr_multicast_to_unicast, + &brport_attr_multicast_eht_hosts_limit, + &brport_attr_multicast_eht_hosts_cnt, #endif &brport_attr_proxyarp, &brport_attr_proxyarp_wifi, diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 3d6ab194d0f5..c313aaf2bce1 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -55,7 +55,7 @@ #include <net/net_namespace.h> #define RTNL_MAX_TYPE 50 -#define RTNL_SLAVE_MAX_TYPE 36 +#define RTNL_SLAVE_MAX_TYPE 40 struct rtnl_link { rtnl_doit_func doit; |