* [Bridge] [RFC] bridge: STP timer management range checking
[not found] ` <20080831100537.6929c51e@extreme>
@ 2008-08-31 17:43 ` Stephen Hemminger
2008-08-31 22:02 ` Alan Cox
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Stephen Hemminger @ 2008-08-31 17:43 UTC (permalink / raw)
To: David Miller, Dushan Tcholich
Cc: Robert Hancock, netdev, bridge, LKML, Francois Romieu
The Spanning Tree Protocol timers need to be set within certain boundaries
to keep the internal protocol engine working, and to be interoperable.
This patch restricts changes to those timers to the values defined in IEEE 802.1D
specification.
The only exception to the standards are:
* if STP is disabled allow forwarding delay to be turned off
* allow wider range of ageing timer since this isn't directly part of
STP, and setting it to zero allows for non-remembering bridge.
Warning: this may cause user backlash since apparently working but standards
conforming configurations will get configuration errors that they didn't
see before.
--- a/net/bridge/br_ioctl.c 2008-08-31 10:00:44.000000000 -0700
+++ b/net/bridge/br_ioctl.c 2008-08-31 10:34:00.000000000 -0700
@@ -177,38 +177,63 @@ static int old_dev_ioctl(struct net_devi
}
case BRCTL_SET_BRIDGE_FORWARD_DELAY:
+ {
+ unsigned long t = clock_t_to_jiffies(args[1]);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ /* enforce range checking per IEEE 802.1D 17.14 */
+ if (br->stp_enabled != BR_NO_STP &&
+ (t < 4*HZ || t > 30 * HZ))
+ return -EINVAL;
+
spin_lock_bh(&br->lock);
- br->bridge_forward_delay = clock_t_to_jiffies(args[1]);
+ br->bridge_forward_delay = t;
if (br_is_root_bridge(br))
br->forward_delay = br->bridge_forward_delay;
spin_unlock_bh(&br->lock);
return 0;
-
+ }
case BRCTL_SET_BRIDGE_HELLO_TIME:
+ {
+ unsigned long t = clock_t_to_jiffies(args[1]);
+
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (t < HZ || t > 15 * HZ)
+ return -EINVAL;
+
spin_lock_bh(&br->lock);
- br->bridge_hello_time = clock_t_to_jiffies(args[1]);
+ br->bridge_hello_time = t;
if (br_is_root_bridge(br))
br->hello_time = br->bridge_hello_time;
spin_unlock_bh(&br->lock);
return 0;
-
+ }
case BRCTL_SET_BRIDGE_MAX_AGE:
+ {
+ unsigned long t = clock_t_to_jiffies(args[1]);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ /* enforce range checking per IEEE 802.1D 17.14 */
+ if (t < 6 * HZ || t > 40 * HZ)
+ return -EINVAL;
+
+ if (t < 2 * (br->bridge_hello_time + HZ))
+ return -EINVAL;
+
+ if (t / 2 + HZ > br->bridge_forward_delay)
+ return -EINVAL;
+
spin_lock_bh(&br->lock);
br->bridge_max_age = clock_t_to_jiffies(args[1]);
if (br_is_root_bridge(br))
br->max_age = br->bridge_max_age;
spin_unlock_bh(&br->lock);
return 0;
-
+ }
case BRCTL_SET_AGEING_TIME:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
--- a/net/bridge/br_sysfs_br.c 2008-08-31 10:23:59.000000000 -0700
+++ b/net/bridge/br_sysfs_br.c 2008-08-31 10:32:53.000000000 -0700
@@ -29,11 +29,12 @@
*/
static ssize_t store_bridge_parm(struct device *d,
const char *buf, size_t len,
- void (*set)(struct net_bridge *, unsigned long))
+ int (*set)(struct net_bridge *, unsigned long))
{
struct net_bridge *br = to_bridge(d);
char *endp;
unsigned long val;
+ int rc;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -43,9 +44,10 @@ static ssize_t store_bridge_parm(struct
return -EINVAL;
spin_lock_bh(&br->lock);
- (*set)(br, val);
+ rc = (*set)(br, val);
spin_unlock_bh(&br->lock);
- return len;
+
+ return rc ? rc : len;
}
@@ -56,12 +58,19 @@ static ssize_t show_forward_delay(struct
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
}
-static void set_forward_delay(struct net_bridge *br, unsigned long val)
+static int set_forward_delay(struct net_bridge *br, unsigned long val)
{
unsigned long delay = clock_t_to_jiffies(val);
+
+ if (br->stp_enabled != BR_NO_STP &&
+ (delay < 4*HZ || delay > 30 * HZ))
+ return -EINVAL;
+
br->forward_delay = delay;
if (br_is_root_bridge(br))
br->bridge_forward_delay = delay;
+
+ return 0;
}
static ssize_t store_forward_delay(struct device *d,
@@ -80,12 +89,18 @@ static ssize_t show_hello_time(struct de
jiffies_to_clock_t(to_bridge(d)->hello_time));
}
-static void set_hello_time(struct net_bridge *br, unsigned long val)
+static int set_hello_time(struct net_bridge *br, unsigned long val)
{
unsigned long t = clock_t_to_jiffies(val);
+
+ if (t < HZ || t > 15 * HZ)
+ return -EINVAL;
+
br->hello_time = t;
if (br_is_root_bridge(br))
br->bridge_hello_time = t;
+
+ return 0;
}
static ssize_t store_hello_time(struct device *d,
@@ -104,12 +119,24 @@ static ssize_t show_max_age(struct devic
jiffies_to_clock_t(to_bridge(d)->max_age));
}
-static void set_max_age(struct net_bridge *br, unsigned long val)
+static int set_max_age(struct net_bridge *br, unsigned long val)
{
unsigned long t = clock_t_to_jiffies(val);
+
+ /* enforce range checking per IEEE 802.1D 17.14 */
+ if (t < 6 * HZ || t > 40 * HZ)
+ return -EINVAL;
+
+ if (t < 2 * (br->bridge_hello_time + HZ))
+ return -EINVAL;
+
+ if (t / 2 + HZ > br->bridge_forward_delay)
+ return -EINVAL;
+
br->max_age = t;
if (br_is_root_bridge(br))
br->bridge_max_age = t;
+ return 0;
}
static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
@@ -126,9 +153,10 @@ static ssize_t show_ageing_time(struct d
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
}
-static void set_ageing_time(struct net_bridge *br, unsigned long val)
+static int set_ageing_time(struct net_bridge *br, unsigned long val)
{
br->ageing_time = clock_t_to_jiffies(val);
+ return 0;
}
static ssize_t store_ageing_time(struct device *d,
@@ -180,9 +208,10 @@ static ssize_t show_priority(struct devi
(br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
}
-static void set_priority(struct net_bridge *br, unsigned long val)
+static int set_priority(struct net_bridge *br, unsigned long val)
{
br_stp_set_bridge_priority(br, (u16) val);
+ return 0;
}
static ssize_t store_priority(struct device *d, struct device_attribute *attr,
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Bridge] [RFC] bridge: STP timer management range checking
2008-08-31 17:43 ` [Bridge] [RFC] bridge: STP timer management range checking Stephen Hemminger
@ 2008-08-31 22:02 ` Alan Cox
2008-08-31 23:29 ` Stephen Hemminger
2008-09-01 2:25 ` Valdis.Kletnieks
` (2 subsequent siblings)
3 siblings, 1 reply; 13+ messages in thread
From: Alan Cox @ 2008-08-31 22:02 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Robert Hancock, netdev, bridge, LKML, Francois Romieu,
Dushan Tcholich, David Miller
On Sun, 31 Aug 2008 10:43:09 -0700
Stephen Hemminger <shemminger@vyatta.com> wrote:
> The Spanning Tree Protocol timers need to be set within certain boundaries
> to keep the internal protocol engine working, and to be interoperable.
> This patch restricts changes to those timers to the values defined in IEEE 802.1D
> specification.
Why do we care ? You have to be the network administrator to set values,
there are cases you may want to be out of the spec and you are
privileged. The kernel does need to stop things being done which are
fatal but running around restricting privileged administrators who have
the ability to bring the network down anyway isn't its job.
Seems bogus extra code to me - stops things working that should be
allowed too.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Bridge] [RFC] bridge: STP timer management range checking
2008-08-31 22:02 ` Alan Cox
@ 2008-08-31 23:29 ` Stephen Hemminger
2008-09-01 8:38 ` Alan Cox
0 siblings, 1 reply; 13+ messages in thread
From: Stephen Hemminger @ 2008-08-31 23:29 UTC (permalink / raw)
To: Alan Cox
Cc: Robert Hancock, netdev, bridge, LKML, Francois Romieu,
Stephen Hemminger, Dushan Tcholich, David Miller
Alan Cox wrote:
> On Sun, 31 Aug 2008 10:43:09 -0700
> Stephen Hemminger <shemminger@vyatta.com> wrote:
>
>
>> The Spanning Tree Protocol timers need to be set within certain boundaries
>> to keep the internal protocol engine working, and to be interoperable.
>> This patch restricts changes to those timers to the values defined in IEEE 802.1D
>> specification.
>>
>
> Why do we care ? You have to be the network administrator to set values,
> there are cases you may want to be out of the spec and you are
> privileged. The kernel does need to stop things being done which are
> fatal but running around restricting privileged administrators who have
> the ability to bring the network down anyway isn't its job.
>
> Seems bogus extra code to me - stops things working that should be
> allowed too.
>
The timer configuration is propagated in network protocol, so
misconfigured Linux box
could survive but effect other devices on the network that are less
robust. Maybe the
small values would cause some other bridge to crash, go infinite loop, ...
More likely robust devices might ignore our packets (because values out
of range), leading to
routing loops and other disasters.
The kernel does need to stop administrative settings from taking out a
network. If someone
has a custom device or other non-standard usage, they can always rebuild
the kernel and
remove the range check.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Bridge] [RFC] bridge: STP timer management range checking
2008-08-31 17:43 ` [Bridge] [RFC] bridge: STP timer management range checking Stephen Hemminger
2008-08-31 22:02 ` Alan Cox
@ 2008-09-01 2:25 ` Valdis.Kletnieks
2008-09-03 0:28 ` David Miller
2008-09-04 22:47 ` [Bridge] [PATCH] bridge: don't allow setting hello time to zero Stephen Hemminger
3 siblings, 0 replies; 13+ messages in thread
From: Valdis.Kletnieks @ 2008-09-01 2:25 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Robert Hancock, netdev, bridge, LKML, Francois Romieu,
Dushan Tcholich, David Miller
[-- Attachment #1: Type: text/plain, Size: 742 bytes --]
On Sun, 31 Aug 2008 10:43:09 PDT, Stephen Hemminger said:
> Warning: this may cause user backlash since apparently working but standards
> conforming configurations will get configuration errors that they didn't
> see before.
Did you mean "apparently working but *non*-standards conforming"?
Other than that, seems to be a sane application of "Be conservative in what you
send". Our network is some 30K cat-5 ports, 1100 switches, 1300 wireless
access points, and we appreciate it every time somebody makes things more
bulletproof. And yes, we prefer things to out-and-out *fail* rather than
run in a wonky configuration - hard failures usually get fixed in a few
minutes, wonkiness can drag on for months of mystifying symptoms...
[-- Attachment #2: Type: application/pgp-signature, Size: 226 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Bridge] [RFC] bridge: STP timer management range checking
2008-08-31 23:29 ` Stephen Hemminger
@ 2008-09-01 8:38 ` Alan Cox
2008-09-02 16:40 ` Rick Jones
0 siblings, 1 reply; 13+ messages in thread
From: Alan Cox @ 2008-09-01 8:38 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Robert Hancock, netdev, bridge, LKML, Francois Romieu,
Stephen Hemminger, Dushan Tcholich, David Miller
> > Seems bogus extra code to me - stops things working that should be
> > allowed too.
> >
> The timer configuration is propagated in network protocol, so
> misconfigured Linux box
> could survive but effect other devices on the network that are less
> robust. Maybe the
That would be irrelevant. CAP_NET_ADMIN lets you make that size mess
anyway.
> small values would cause some other bridge to crash, go infinite loop, ...
> More likely robust devices might ignore our packets (because values out
> of range), leading to
> routing loops and other disasters.
Spamming tree isn't secure, news at 11.
> The kernel does need to stop administrative settings from taking out a
> network.
If you have CAP_NET_ADMIN you can trivially take out the network unless
it is properly switched.
Now you might want your pretty little GUI and/or config tools to warn
people that their configuration is outside 802 specs but that is a
different matter altogether
Alan
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Bridge] [RFC] bridge: STP timer management range checking
2008-09-01 8:38 ` Alan Cox
@ 2008-09-02 16:40 ` Rick Jones
2008-09-02 23:41 ` David Miller
0 siblings, 1 reply; 13+ messages in thread
From: Rick Jones @ 2008-09-02 16:40 UTC (permalink / raw)
To: Alan Cox
Cc: Robert Hancock, netdev, bridge, LKML, Stephen Hemminger,
Francois Romieu, Stephen Hemminger, Dushan Tcholich, David Miller
Can one change the TCP maximum RTO to be smaller than specified in the
specs?
rick jones
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Bridge] [RFC] bridge: STP timer management range checking
2008-09-02 16:40 ` Rick Jones
@ 2008-09-02 23:41 ` David Miller
2008-09-03 0:00 ` Rick Jones
0 siblings, 1 reply; 13+ messages in thread
From: David Miller @ 2008-09-02 23:41 UTC (permalink / raw)
To: rick.jones2
Cc: hancockr, netdev, bridge, linux-kernel, stephen.hemminger, romieu,
shemminger, dusanc, alan
From: Rick Jones <rick.jones2@hp.com>
Date: Tue, 02 Sep 2008 09:40:46 -0700
> Can one change the TCP maximum RTO to be smaller than specified in the specs?
We always min-clamp the RTO at RTO calculation time in order to be
compatible with BSD's coarse grained times.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Bridge] [RFC] bridge: STP timer management range checking
2008-09-02 23:41 ` David Miller
@ 2008-09-03 0:00 ` Rick Jones
0 siblings, 0 replies; 13+ messages in thread
From: Rick Jones @ 2008-09-03 0:00 UTC (permalink / raw)
To: David Miller
Cc: hancockr, netdev, bridge, linux-kernel, stephen.hemminger, romieu,
shemminger, dusanc, alan
David Miller wrote:
> From: Rick Jones <rick.jones2@hp.com>
> Date: Tue, 02 Sep 2008 09:40:46 -0700
>>Can one change the TCP maximum RTO to be smaller than specified in the specs?
> We always min-clamp the RTO at RTO calculation time in order to be
> compatible with BSD's coarse grained times.
But tuning TCP_RTO_MAX isn't permitted right? I'm drawing (perhaps
flawed) parallels/distinctions between what is/isn't permitted to tweak
for timers for one protocol versus another and wondering which may be a
case of sauce for the goose/gander.
rick jones
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Bridge] [RFC] bridge: STP timer management range checking
2008-08-31 17:43 ` [Bridge] [RFC] bridge: STP timer management range checking Stephen Hemminger
2008-08-31 22:02 ` Alan Cox
2008-09-01 2:25 ` Valdis.Kletnieks
@ 2008-09-03 0:28 ` David Miller
2008-09-04 22:47 ` [Bridge] [PATCH] bridge: don't allow setting hello time to zero Stephen Hemminger
3 siblings, 0 replies; 13+ messages in thread
From: David Miller @ 2008-09-03 0:28 UTC (permalink / raw)
To: shemminger; +Cc: hancockr, netdev, bridge, linux-kernel, romieu, dusanc
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Sun, 31 Aug 2008 10:43:09 -0700
> The Spanning Tree Protocol timers need to be set within certain boundaries
> to keep the internal protocol engine working, and to be interoperable.
> This patch restricts changes to those timers to the values defined in IEEE 802.1D
> specification.
>
> The only exception to the standards are:
> * if STP is disabled allow forwarding delay to be turned off
> * allow wider range of ageing timer since this isn't directly part of
> STP, and setting it to zero allows for non-remembering bridge.
>
> Warning: this may cause user backlash since apparently working but standards
> conforming configurations will get configuration errors that they didn't
> see before.
I don't think we can really add these kinds of restrictions wholesale
like this.
And the user is reporting that using brctl to turn off STP doesn't
appear to actually turn off STP and thus fix all of the crazy
ksoftirqd high cpu load problems.
So what we need to do is resolve the user configuration issue that is
causing this problem to begin with.
^ permalink raw reply [flat|nested] 13+ messages in thread
* [Bridge] [PATCH] bridge: don't allow setting hello time to zero
2008-08-31 17:43 ` [Bridge] [RFC] bridge: STP timer management range checking Stephen Hemminger
` (2 preceding siblings ...)
2008-09-03 0:28 ` David Miller
@ 2008-09-04 22:47 ` Stephen Hemminger
2008-09-08 20:46 ` David Miller
3 siblings, 1 reply; 13+ messages in thread
From: Stephen Hemminger @ 2008-09-04 22:47 UTC (permalink / raw)
To: David Miller
Cc: Robert Hancock, netdev, bridge, LKML, Francois Romieu,
Dushan Tcholich
The bridge hello time can't be safely set to values less than 1 second,
otherwise it is possible to end up with a runaway timer.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/bridge/br_ioctl.c 2008-09-04 15:25:41.000000000 -0700
+++ b/net/bridge/br_ioctl.c 2008-09-04 15:44:33.000000000 -0700
@@ -188,15 +188,21 @@ static int old_dev_ioctl(struct net_devi
return 0;
case BRCTL_SET_BRIDGE_HELLO_TIME:
+ {
+ unsigned long t = clock_t_to_jiffies(args[1]);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (t < HZ)
+ return -EINVAL;
+
spin_lock_bh(&br->lock);
- br->bridge_hello_time = clock_t_to_jiffies(args[1]);
+ br->bridge_hello_time = t;
if (br_is_root_bridge(br))
br->hello_time = br->bridge_hello_time;
spin_unlock_bh(&br->lock);
return 0;
+ }
case BRCTL_SET_BRIDGE_MAX_AGE:
if (!capable(CAP_NET_ADMIN))
--- a/net/bridge/br_sysfs_br.c 2008-09-04 15:27:20.000000000 -0700
+++ b/net/bridge/br_sysfs_br.c 2008-09-04 15:33:31.000000000 -0700
@@ -29,11 +29,12 @@
*/
static ssize_t store_bridge_parm(struct device *d,
const char *buf, size_t len,
- void (*set)(struct net_bridge *, unsigned long))
+ int (*set)(struct net_bridge *, unsigned long))
{
struct net_bridge *br = to_bridge(d);
char *endp;
unsigned long val;
+ int err;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -43,9 +44,9 @@ static ssize_t store_bridge_parm(struct
return -EINVAL;
spin_lock_bh(&br->lock);
- (*set)(br, val);
+ err = (*set)(br, val);
spin_unlock_bh(&br->lock);
- return len;
+ return err ? err : len;
}
@@ -56,12 +57,13 @@ static ssize_t show_forward_delay(struct
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
}
-static void set_forward_delay(struct net_bridge *br, unsigned long val)
+static int set_forward_delay(struct net_bridge *br, unsigned long val)
{
unsigned long delay = clock_t_to_jiffies(val);
br->forward_delay = delay;
if (br_is_root_bridge(br))
br->bridge_forward_delay = delay;
+ return 0;
}
static ssize_t store_forward_delay(struct device *d,
@@ -80,12 +82,17 @@ static ssize_t show_hello_time(struct de
jiffies_to_clock_t(to_bridge(d)->hello_time));
}
-static void set_hello_time(struct net_bridge *br, unsigned long val)
+static int set_hello_time(struct net_bridge *br, unsigned long val)
{
unsigned long t = clock_t_to_jiffies(val);
+
+ if (t < HZ)
+ return -EINVAL;
+
br->hello_time = t;
if (br_is_root_bridge(br))
br->bridge_hello_time = t;
+ return 0;
}
static ssize_t store_hello_time(struct device *d,
@@ -104,12 +111,13 @@ static ssize_t show_max_age(struct devic
jiffies_to_clock_t(to_bridge(d)->max_age));
}
-static void set_max_age(struct net_bridge *br, unsigned long val)
+static int set_max_age(struct net_bridge *br, unsigned long val)
{
unsigned long t = clock_t_to_jiffies(val);
br->max_age = t;
if (br_is_root_bridge(br))
br->bridge_max_age = t;
+ return 0;
}
static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
@@ -126,9 +134,10 @@ static ssize_t show_ageing_time(struct d
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
}
-static void set_ageing_time(struct net_bridge *br, unsigned long val)
+static int set_ageing_time(struct net_bridge *br, unsigned long val)
{
br->ageing_time = clock_t_to_jiffies(val);
+ return 0;
}
static ssize_t store_ageing_time(struct device *d,
@@ -180,9 +189,10 @@ static ssize_t show_priority(struct devi
(br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
}
-static void set_priority(struct net_bridge *br, unsigned long val)
+static int set_priority(struct net_bridge *br, unsigned long val)
{
br_stp_set_bridge_priority(br, (u16) val);
+ return 0;
}
static ssize_t store_priority(struct device *d, struct device_attribute *attr,
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Bridge] [PATCH] bridge: don't allow setting hello time to zero
2008-09-04 22:47 ` [Bridge] [PATCH] bridge: don't allow setting hello time to zero Stephen Hemminger
@ 2008-09-08 20:46 ` David Miller
2008-09-08 21:35 ` Dushan Tcholich
0 siblings, 1 reply; 13+ messages in thread
From: David Miller @ 2008-09-08 20:46 UTC (permalink / raw)
To: shemminger; +Cc: hancockr, netdev, bridge, linux-kernel, romieu, dusanc
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Thu, 4 Sep 2008 15:47:09 -0700
> The bridge hello time can't be safely set to values less than 1 second,
> otherwise it is possible to end up with a runaway timer.
>
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Applied, thanks Stephen.
I added more information to the commit message so that Dushan's
incredibly contribution to this bug getting fixed are mentioned.
I don't see how we would have figured out Bridging as even the
cause without his detective work. So it's definitely wrong not
to give him at least some mention in the commit message :-/
bridge: don't allow setting hello time to zero
Dushan Tcholich reports that on his system ksoftirqd can consume
between %6 to %10 of cpu time, and cause ~200 context switches per
second.
He then correlated this with a report by bdupree@techfinesse.com:
http://marc.info/?l=linux-kernel&m=119613299024398&w=2
and the culprit cause seems to be starting the bridge interface.
In particular, when starting the bridge interface, his scripts
are specifying a hello timer interval of "0".
The bridge hello time can't be safely set to values less than 1
second, otherwise it is possible to end up with a runaway timer.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/bridge/br_ioctl.c | 8 +++++++-
net/bridge/br_sysfs_br.c | 26 ++++++++++++++++++--------
2 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index eeee218..5bbf073 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -188,15 +188,21 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return 0;
case BRCTL_SET_BRIDGE_HELLO_TIME:
+ {
+ unsigned long t = clock_t_to_jiffies(args[1]);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (t < HZ)
+ return -EINVAL;
+
spin_lock_bh(&br->lock);
- br->bridge_hello_time = clock_t_to_jiffies(args[1]);
+ br->bridge_hello_time = t;
if (br_is_root_bridge(br))
br->hello_time = br->bridge_hello_time;
spin_unlock_bh(&br->lock);
return 0;
+ }
case BRCTL_SET_BRIDGE_MAX_AGE:
if (!capable(CAP_NET_ADMIN))
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 27d6a51..158dee8 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -29,11 +29,12 @@
*/
static ssize_t store_bridge_parm(struct device *d,
const char *buf, size_t len,
- void (*set)(struct net_bridge *, unsigned long))
+ int (*set)(struct net_bridge *, unsigned long))
{
struct net_bridge *br = to_bridge(d);
char *endp;
unsigned long val;
+ int err;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -43,9 +44,9 @@ static ssize_t store_bridge_parm(struct device *d,
return -EINVAL;
spin_lock_bh(&br->lock);
- (*set)(br, val);
+ err = (*set)(br, val);
spin_unlock_bh(&br->lock);
- return len;
+ return err ? err : len;
}
@@ -56,12 +57,13 @@ static ssize_t show_forward_delay(struct device *d,
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
}
-static void set_forward_delay(struct net_bridge *br, unsigned long val)
+static int set_forward_delay(struct net_bridge *br, unsigned long val)
{
unsigned long delay = clock_t_to_jiffies(val);
br->forward_delay = delay;
if (br_is_root_bridge(br))
br->bridge_forward_delay = delay;
+ return 0;
}
static ssize_t store_forward_delay(struct device *d,
@@ -80,12 +82,17 @@ static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
jiffies_to_clock_t(to_bridge(d)->hello_time));
}
-static void set_hello_time(struct net_bridge *br, unsigned long val)
+static int set_hello_time(struct net_bridge *br, unsigned long val)
{
unsigned long t = clock_t_to_jiffies(val);
+
+ if (t < HZ)
+ return -EINVAL;
+
br->hello_time = t;
if (br_is_root_bridge(br))
br->bridge_hello_time = t;
+ return 0;
}
static ssize_t store_hello_time(struct device *d,
@@ -104,12 +111,13 @@ static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
jiffies_to_clock_t(to_bridge(d)->max_age));
}
-static void set_max_age(struct net_bridge *br, unsigned long val)
+static int set_max_age(struct net_bridge *br, unsigned long val)
{
unsigned long t = clock_t_to_jiffies(val);
br->max_age = t;
if (br_is_root_bridge(br))
br->bridge_max_age = t;
+ return 0;
}
static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
@@ -126,9 +134,10 @@ static ssize_t show_ageing_time(struct device *d,
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
}
-static void set_ageing_time(struct net_bridge *br, unsigned long val)
+static int set_ageing_time(struct net_bridge *br, unsigned long val)
{
br->ageing_time = clock_t_to_jiffies(val);
+ return 0;
}
static ssize_t store_ageing_time(struct device *d,
@@ -180,9 +189,10 @@ static ssize_t show_priority(struct device *d, struct device_attribute *attr,
(br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
}
-static void set_priority(struct net_bridge *br, unsigned long val)
+static int set_priority(struct net_bridge *br, unsigned long val)
{
br_stp_set_bridge_priority(br, (u16) val);
+ return 0;
}
static ssize_t store_priority(struct device *d, struct device_attribute *attr,
--
1.5.6.5.GIT
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [Bridge] [PATCH] bridge: don't allow setting hello time to zero
2008-09-08 20:46 ` David Miller
@ 2008-09-08 21:35 ` Dushan Tcholich
2008-09-08 22:33 ` Stephen Hemminger
0 siblings, 1 reply; 13+ messages in thread
From: Dushan Tcholich @ 2008-09-08 21:35 UTC (permalink / raw)
To: David Miller; +Cc: hancockr, netdev, bridge, linux-kernel, romieu, shemminger
On Mon, Sep 8, 2008 at 10:46 PM, David Miller <davem@davemloft.net> wrote:
> From: Stephen Hemminger <shemminger@vyatta.com>
> Date: Thu, 4 Sep 2008 15:47:09 -0700
>
>> The bridge hello time can't be safely set to values less than 1 second,
>> otherwise it is possible to end up with a runaway timer.
>>
>> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
>
> Applied, thanks Stephen.
>
> I added more information to the commit message so that Dushan's
> incredibly contribution to this bug getting fixed are mentioned.
> I don't see how we would have figured out Bridging as even the
> cause without his detective work. So it's definitely wrong not
> to give him at least some mention in the commit message :-/
>
I don't know what to say :)
Thank you
> bridge: don't allow setting hello time to zero
>
> Dushan Tcholich reports that on his system ksoftirqd can consume
> between %6 to %10 of cpu time, and cause ~200 context switches per
> second.
>
A little nitpick: 200 times greater context switch rate :), like
100000 per second.
> He then correlated this with a report by bdupree@techfinesse.com:
>
> http://marc.info/?l=linux-kernel&m=119613299024398&w=2
>
> and the culprit cause seems to be starting the bridge interface.
> In particular, when starting the bridge interface, his scripts
> are specifying a hello timer interval of "0".
>
> The bridge hello time can't be safely set to values less than 1
> second, otherwise it is possible to end up with a runaway timer.
Btw. is there a way to make the command to turn STP off work too?
brctl stp br0 off
Because AFAIK if I shut down STP the hello timer should shut down too,
but it still continues to work.
Thank you for your time and effort
Dushan Tcholich
>
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> Signed-off-by: David S. Miller <davem@davemloft.net>
> ---
> net/bridge/br_ioctl.c | 8 +++++++-
> net/bridge/br_sysfs_br.c | 26 ++++++++++++++++++--------
> 2 files changed, 25 insertions(+), 9 deletions(-)
>
> diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
> index eeee218..5bbf073 100644
> --- a/net/bridge/br_ioctl.c
> +++ b/net/bridge/br_ioctl.c
> @@ -188,15 +188,21 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
> return 0;
>
> case BRCTL_SET_BRIDGE_HELLO_TIME:
> + {
> + unsigned long t = clock_t_to_jiffies(args[1]);
> if (!capable(CAP_NET_ADMIN))
> return -EPERM;
>
> + if (t < HZ)
> + return -EINVAL;
> +
> spin_lock_bh(&br->lock);
> - br->bridge_hello_time = clock_t_to_jiffies(args[1]);
> + br->bridge_hello_time = t;
> if (br_is_root_bridge(br))
> br->hello_time = br->bridge_hello_time;
> spin_unlock_bh(&br->lock);
> return 0;
> + }
>
> case BRCTL_SET_BRIDGE_MAX_AGE:
> if (!capable(CAP_NET_ADMIN))
> diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
> index 27d6a51..158dee8 100644
> --- a/net/bridge/br_sysfs_br.c
> +++ b/net/bridge/br_sysfs_br.c
> @@ -29,11 +29,12 @@
> */
> static ssize_t store_bridge_parm(struct device *d,
> const char *buf, size_t len,
> - void (*set)(struct net_bridge *, unsigned long))
> + int (*set)(struct net_bridge *, unsigned long))
> {
> struct net_bridge *br = to_bridge(d);
> char *endp;
> unsigned long val;
> + int err;
>
> if (!capable(CAP_NET_ADMIN))
> return -EPERM;
> @@ -43,9 +44,9 @@ static ssize_t store_bridge_parm(struct device *d,
> return -EINVAL;
>
> spin_lock_bh(&br->lock);
> - (*set)(br, val);
> + err = (*set)(br, val);
> spin_unlock_bh(&br->lock);
> - return len;
> + return err ? err : len;
> }
>
>
> @@ -56,12 +57,13 @@ static ssize_t show_forward_delay(struct device *d,
> return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
> }
>
> -static void set_forward_delay(struct net_bridge *br, unsigned long val)
> +static int set_forward_delay(struct net_bridge *br, unsigned long val)
> {
> unsigned long delay = clock_t_to_jiffies(val);
> br->forward_delay = delay;
> if (br_is_root_bridge(br))
> br->bridge_forward_delay = delay;
> + return 0;
> }
>
> static ssize_t store_forward_delay(struct device *d,
> @@ -80,12 +82,17 @@ static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
> jiffies_to_clock_t(to_bridge(d)->hello_time));
> }
>
> -static void set_hello_time(struct net_bridge *br, unsigned long val)
> +static int set_hello_time(struct net_bridge *br, unsigned long val)
> {
> unsigned long t = clock_t_to_jiffies(val);
> +
> + if (t < HZ)
> + return -EINVAL;
> +
> br->hello_time = t;
> if (br_is_root_bridge(br))
> br->bridge_hello_time = t;
> + return 0;
> }
>
> static ssize_t store_hello_time(struct device *d,
> @@ -104,12 +111,13 @@ static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
> jiffies_to_clock_t(to_bridge(d)->max_age));
> }
>
> -static void set_max_age(struct net_bridge *br, unsigned long val)
> +static int set_max_age(struct net_bridge *br, unsigned long val)
> {
> unsigned long t = clock_t_to_jiffies(val);
> br->max_age = t;
> if (br_is_root_bridge(br))
> br->bridge_max_age = t;
> + return 0;
> }
>
> static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
> @@ -126,9 +134,10 @@ static ssize_t show_ageing_time(struct device *d,
> return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
> }
>
> -static void set_ageing_time(struct net_bridge *br, unsigned long val)
> +static int set_ageing_time(struct net_bridge *br, unsigned long val)
> {
> br->ageing_time = clock_t_to_jiffies(val);
> + return 0;
> }
>
> static ssize_t store_ageing_time(struct device *d,
> @@ -180,9 +189,10 @@ static ssize_t show_priority(struct device *d, struct device_attribute *attr,
> (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
> }
>
> -static void set_priority(struct net_bridge *br, unsigned long val)
> +static int set_priority(struct net_bridge *br, unsigned long val)
> {
> br_stp_set_bridge_priority(br, (u16) val);
> + return 0;
> }
>
> static ssize_t store_priority(struct device *d, struct device_attribute *attr,
> --
> 1.5.6.5.GIT
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Bridge] [PATCH] bridge: don't allow setting hello time to zero
2008-09-08 21:35 ` Dushan Tcholich
@ 2008-09-08 22:33 ` Stephen Hemminger
0 siblings, 0 replies; 13+ messages in thread
From: Stephen Hemminger @ 2008-09-08 22:33 UTC (permalink / raw)
To: Dushan Tcholich, David Miller
Cc: hancockr, netdev, bridge, linux-kernel, romieu
On Mon, 8 Sep 2008 23:35:19 +0200
"Dushan Tcholich" <dusanc@gmail.com> wrote:
> On Mon, Sep 8, 2008 at 10:46 PM, David Miller <davem@davemloft.net> wrote:
> > From: Stephen Hemminger <shemminger@vyatta.com>
> > Date: Thu, 4 Sep 2008 15:47:09 -0700
> >
> >> The bridge hello time can't be safely set to values less than 1 second,
> >> otherwise it is possible to end up with a runaway timer.
> >>
> >> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> >
> > Applied, thanks Stephen.
> >
> > I added more information to the commit message so that Dushan's
> > incredibly contribution to this bug getting fixed are mentioned.
> > I don't see how we would have figured out Bridging as even the
> > cause without his detective work. So it's definitely wrong not
> > to give him at least some mention in the commit message :-/
> >
>
> I don't know what to say :)
>
> Thank you
> > bridge: don't allow setting hello time to zero
> >
> > Dushan Tcholich reports that on his system ksoftirqd can consume
> > between %6 to %10 of cpu time, and cause ~200 context switches per
> > second.
> >
> A little nitpick: 200 times greater context switch rate :), like
> 100000 per second.
>
> > He then correlated this with a report by bdupree@techfinesse.com:
> >
> > http://marc.info/?l=linux-kernel&m=119613299024398&w=2
> >
> > and the culprit cause seems to be starting the bridge interface.
> > In particular, when starting the bridge interface, his scripts
> > are specifying a hello timer interval of "0".
> >
> > The bridge hello time can't be safely set to values less than 1
> > second, otherwise it is possible to end up with a runaway timer.
>
> Btw. is there a way to make the command to turn STP off work too?
> brctl stp br0 off
> Because AFAIK if I shut down STP the hello timer should shut down too,
> but it still continues to work.
>
> Thank you for your time and effort
>
> Dushan Tcholich
>
The basics:
* Hello timer is always enabled
* STP defaults to off unless you turn it on
* Turn STP on/off with brctl.
In the existing design, the hello timer always runs, even when STP
is not turned on. If STP is not enabled, the packet is just never
created. Fixing it would not be hard (or gain much), but would have
to deal with complex lock ordering and timer problems, so it isn't
worth fixing for current releases.
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2008-09-08 22:33 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <fa.wTMiBcGRgw2fBtdHwtX7y0lkc8s@ifi.uio.no>
[not found] ` <48975BD3.6040709@shaw.ca>
[not found] ` <a08621850808041337k1d1deb6fk78098d9fcd4930dd@mail.gmail.com>
[not found] ` <20080807185802.GA16327@electric-eye.fr.zoreil.com>
[not found] ` <a08621850808101200n220afd2dve58abe67830b7a4f@mail.gmail.com>
[not found] ` <a08621850808110053j5cbf23e6xdf52c9e7440abf19@mail.gmail.com>
[not found] ` <a08621850808291848q5660148fx57d576ecfcbfce8@mail.gmail.com>
[not found] ` <a08621850808310151o143845h195a8658d02270d9@mail.gmail.com>
[not found] ` <20080831100537.6929c51e@extreme>
2008-08-31 17:43 ` [Bridge] [RFC] bridge: STP timer management range checking Stephen Hemminger
2008-08-31 22:02 ` Alan Cox
2008-08-31 23:29 ` Stephen Hemminger
2008-09-01 8:38 ` Alan Cox
2008-09-02 16:40 ` Rick Jones
2008-09-02 23:41 ` David Miller
2008-09-03 0:00 ` Rick Jones
2008-09-01 2:25 ` Valdis.Kletnieks
2008-09-03 0:28 ` David Miller
2008-09-04 22:47 ` [Bridge] [PATCH] bridge: don't allow setting hello time to zero Stephen Hemminger
2008-09-08 20:46 ` David Miller
2008-09-08 21:35 ` Dushan Tcholich
2008-09-08 22:33 ` Stephen Hemminger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox