2017-05-19 18:51 GMT+02:00 Xin Long <lucien.xin@xxxxxxxxx>: > On Sat, May 20, 2017 at 12:25 AM, Ivan Vecera <cera@xxxxxxx> wrote: >> Current bridge code incorrectly handles starting/stopping of hello and >> hold timers during STP enable/disable. >> >> 1. Timers are stopped in br_stp_start() during NO_STP->USER_STP >> transition. This is not correct as the timers are stopped in NO_STP >> case. >> >> 2. Timers are started in br_stp_stop() during USER_STP->NO_STP transition. >> This is not also correct as the timers should be stopped in NO_STP >> state. >> >> 3. Timers are NOT stopped in br_stp_stop() during KERNEL_STP->NO_STP >> transition. They should be stopped as they are running in KERNEL_STP >> state and should not run in NO_STP case. >> >> The patch is a follow-up for "bridge: start hello_timer when enabling >> KERNEL_STP in br_stp_start" patch from Xin Long. >> >> Cc: davem@xxxxxxxxxxxxx >> Cc: sashok@xxxxxxxxxxxxxxxxxxx >> Cc: stephen@xxxxxxxxxxxxxxxxxx >> Cc: bridge@xxxxxxxxxxxxxxxxxxxxxxxxxx >> Cc: lucien.xin@xxxxxxxxx >> Cc: nikolay@xxxxxxxxxxxxxxxxxxx >> Signed-off-by: Ivan Vecera <cera@xxxxxxx> >> --- >> net/bridge/br_stp_if.c | 15 +++++---------- >> 1 file changed, 5 insertions(+), 10 deletions(-) >> >> diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c >> index 0db8102995a5..f137ebf27755 100644 >> --- a/net/bridge/br_stp_if.c >> +++ b/net/bridge/br_stp_if.c >> @@ -150,7 +150,6 @@ static int br_stp_call_user(struct net_bridge *br, char *arg) >> >> static void br_stp_start(struct net_bridge *br) >> { >> - struct net_bridge_port *p; >> int err = -ENOENT; >> >> if (net_eq(dev_net(br->dev), &init_net)) >> @@ -169,11 +168,6 @@ static void br_stp_start(struct net_bridge *br) >> if (!err) { >> br->stp_enabled = BR_USER_STP; >> br_debug(br, "userspace STP started\n"); >> - >> - /* Stop hello and hold timers */ >> - del_timer(&br->hello_timer); >> - list_for_each_entry(p, &br->port_list, list) >> - del_timer(&p->hold_timer); >> } else { >> br->stp_enabled = BR_KERNEL_STP; >> br_debug(br, "using kernel STP\n"); >> @@ -197,13 +191,14 @@ static void br_stp_stop(struct net_bridge *br) >> br_err(br, "failed to stop userspace STP (%d)\n", err); >> >> /* To start timers on any ports left in blocking */ >> - mod_timer(&br->hello_timer, jiffies + br->hello_time); >> - list_for_each_entry(p, &br->port_list, list) >> - mod_timer(&p->hold_timer, >> - round_jiffies(jiffies + BR_HOLD_TIME)); >> spin_lock_bh(&br->lock); >> br_port_state_selection(br); >> spin_unlock_bh(&br->lock); >> + } else { >> + /* BR_KERNEL_STP - stop hello and hold timers */ >> + del_timer(&br->hello_timer); >> + list_for_each_entry(p, &br->port_list, list) >> + del_timer(&p->hold_timer); > I'm thinking, what if the timers are running when deleting them ? > del_timer may not be going to delete it, and still have to stop itself > next time when br->stp_enabled = BR_NO_STP. > > So do you think it's better to do nothing here and just leave it to be > stopped by itself when checking br->stp_enabled in > br_hello_timer_expired ? Yes, this kind of "lazy stopping" could be safer. I.