Commit f7397cd2 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-bridge-mcast-add-and-enforce-query-interval-minimum'

Nikolay Aleksandrov says:

====================
net: bridge: mcast: add and enforce query interval minimum

This set adds and enforces 1 second minimum value for bridge multicast
query and startup query intervals in order to avoid rearming the timers
too often which could lock and crash the host. I doubt anyone is using
such low values or anything lower than 1 second, so it seems like a good
minimum. In order to be compatible if the value is lower then it is
overwritten and a log message is emitted, since we can't return an error
at this point.

Eric, I looked for the syzbot reports in its dashboard but couldn't find
them so I've added you as the reporter.

I've prepared a global bridge igmp rate limiting patch but wasn't
sure if it's ok for -net. It adds a static limit of 32k packets per
second, I plan to send it for net-next with added drop counters for
each bridge so it can be easily debugged.

Original report can be seen at:
https://lore.kernel.org/netdev/e8b9ce41-57b9-b6e2-a46a-ff9c791cf0ba@gmail.com/
====================

Link: https://lore.kernel.org/r/20211227172116.320768-1-nikolay@nvidia.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents fb7bc920 f83a112b
...@@ -4522,6 +4522,38 @@ int br_multicast_set_mld_version(struct net_bridge_mcast *brmctx, ...@@ -4522,6 +4522,38 @@ int br_multicast_set_mld_version(struct net_bridge_mcast *brmctx,
} }
#endif #endif
void br_multicast_set_query_intvl(struct net_bridge_mcast *brmctx,
unsigned long val)
{
unsigned long intvl_jiffies = clock_t_to_jiffies(val);
if (intvl_jiffies < BR_MULTICAST_QUERY_INTVL_MIN) {
br_info(brmctx->br,
"trying to set multicast query interval below minimum, setting to %lu (%ums)\n",
jiffies_to_clock_t(BR_MULTICAST_QUERY_INTVL_MIN),
jiffies_to_msecs(BR_MULTICAST_QUERY_INTVL_MIN));
intvl_jiffies = BR_MULTICAST_QUERY_INTVL_MIN;
}
brmctx->multicast_query_interval = intvl_jiffies;
}
void br_multicast_set_startup_query_intvl(struct net_bridge_mcast *brmctx,
unsigned long val)
{
unsigned long intvl_jiffies = clock_t_to_jiffies(val);
if (intvl_jiffies < BR_MULTICAST_STARTUP_QUERY_INTVL_MIN) {
br_info(brmctx->br,
"trying to set multicast startup query interval below minimum, setting to %lu (%ums)\n",
jiffies_to_clock_t(BR_MULTICAST_STARTUP_QUERY_INTVL_MIN),
jiffies_to_msecs(BR_MULTICAST_STARTUP_QUERY_INTVL_MIN));
intvl_jiffies = BR_MULTICAST_STARTUP_QUERY_INTVL_MIN;
}
brmctx->multicast_startup_query_interval = intvl_jiffies;
}
/** /**
* br_multicast_list_adjacent - Returns snooped multicast addresses * br_multicast_list_adjacent - Returns snooped multicast addresses
* @dev: The bridge port adjacent to which to retrieve addresses * @dev: The bridge port adjacent to which to retrieve addresses
......
...@@ -1357,7 +1357,7 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], ...@@ -1357,7 +1357,7 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
if (data[IFLA_BR_MCAST_QUERY_INTVL]) { if (data[IFLA_BR_MCAST_QUERY_INTVL]) {
u64 val = nla_get_u64(data[IFLA_BR_MCAST_QUERY_INTVL]); u64 val = nla_get_u64(data[IFLA_BR_MCAST_QUERY_INTVL]);
br->multicast_ctx.multicast_query_interval = clock_t_to_jiffies(val); br_multicast_set_query_intvl(&br->multicast_ctx, val);
} }
if (data[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]) { if (data[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]) {
...@@ -1369,7 +1369,7 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], ...@@ -1369,7 +1369,7 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
if (data[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]) { if (data[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]) {
u64 val = nla_get_u64(data[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]); u64 val = nla_get_u64(data[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]);
br->multicast_ctx.multicast_startup_query_interval = clock_t_to_jiffies(val); br_multicast_set_startup_query_intvl(&br->multicast_ctx, val);
} }
if (data[IFLA_BR_MCAST_STATS_ENABLED]) { if (data[IFLA_BR_MCAST_STATS_ENABLED]) {
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#define BR_MAX_PORTS (1<<BR_PORT_BITS) #define BR_MAX_PORTS (1<<BR_PORT_BITS)
#define BR_MULTICAST_DEFAULT_HASH_MAX 4096 #define BR_MULTICAST_DEFAULT_HASH_MAX 4096
#define BR_MULTICAST_QUERY_INTVL_MIN msecs_to_jiffies(1000)
#define BR_MULTICAST_STARTUP_QUERY_INTVL_MIN BR_MULTICAST_QUERY_INTVL_MIN
#define BR_HWDOM_MAX BITS_PER_LONG #define BR_HWDOM_MAX BITS_PER_LONG
...@@ -963,6 +965,10 @@ int br_multicast_dump_querier_state(struct sk_buff *skb, ...@@ -963,6 +965,10 @@ int br_multicast_dump_querier_state(struct sk_buff *skb,
int nest_attr); int nest_attr);
size_t br_multicast_querier_state_size(void); size_t br_multicast_querier_state_size(void);
size_t br_rports_size(const struct net_bridge_mcast *brmctx); size_t br_rports_size(const struct net_bridge_mcast *brmctx);
void br_multicast_set_query_intvl(struct net_bridge_mcast *brmctx,
unsigned long val);
void br_multicast_set_startup_query_intvl(struct net_bridge_mcast *brmctx,
unsigned long val);
static inline bool br_group_is_l2(const struct br_ip *group) static inline bool br_group_is_l2(const struct br_ip *group)
{ {
......
...@@ -658,7 +658,7 @@ static ssize_t multicast_query_interval_show(struct device *d, ...@@ -658,7 +658,7 @@ static ssize_t multicast_query_interval_show(struct device *d,
static int set_query_interval(struct net_bridge *br, unsigned long val, static int set_query_interval(struct net_bridge *br, unsigned long val,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
br->multicast_ctx.multicast_query_interval = clock_t_to_jiffies(val); br_multicast_set_query_intvl(&br->multicast_ctx, val);
return 0; return 0;
} }
...@@ -706,7 +706,7 @@ static ssize_t multicast_startup_query_interval_show( ...@@ -706,7 +706,7 @@ static ssize_t multicast_startup_query_interval_show(
static int set_startup_query_interval(struct net_bridge *br, unsigned long val, static int set_startup_query_interval(struct net_bridge *br, unsigned long val,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
br->multicast_ctx.multicast_startup_query_interval = clock_t_to_jiffies(val); br_multicast_set_startup_query_intvl(&br->multicast_ctx, val);
return 0; return 0;
} }
......
...@@ -521,7 +521,7 @@ static int br_vlan_process_global_one_opts(const struct net_bridge *br, ...@@ -521,7 +521,7 @@ static int br_vlan_process_global_one_opts(const struct net_bridge *br,
u64 val; u64 val;
val = nla_get_u64(tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL]); val = nla_get_u64(tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL]);
v->br_mcast_ctx.multicast_query_interval = clock_t_to_jiffies(val); br_multicast_set_query_intvl(&v->br_mcast_ctx, val);
*changed = true; *changed = true;
} }
if (tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL]) { if (tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL]) {
...@@ -535,7 +535,7 @@ static int br_vlan_process_global_one_opts(const struct net_bridge *br, ...@@ -535,7 +535,7 @@ static int br_vlan_process_global_one_opts(const struct net_bridge *br,
u64 val; u64 val;
val = nla_get_u64(tb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL]); val = nla_get_u64(tb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL]);
v->br_mcast_ctx.multicast_startup_query_interval = clock_t_to_jiffies(val); br_multicast_set_startup_query_intvl(&v->br_mcast_ctx, val);
*changed = true; *changed = true;
} }
if (tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER]) { if (tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER]) {
......
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