diff mbox

[ovs-dev,2/6] stp: Use OpenFlow port number for stp ports.

Message ID 1491016286-86218-2-git-send-email-nic@opencloud.tech
State Changes Requested
Headers show

Commit Message

nickcooper-zhangtonghao April 1, 2017, 3:11 a.m. UTC
When a bridge stp enabled, we assign sequentially element
of stp_port array (in stp struct) to bridge ports. That is
ok when no ports are added to bridge. When adding a port
to bridge which stp enabled, the ovs-vswitchd will assign
stp_port sequentially again. Then the stp_port belonging
to one port may belong to other one. This patch uses the
OpenFlow port numbers instead of sequence numbers to avoid
it.

Signed-off-by: nickcooper-zhangtonghao <nic@opencloud.tech>
---
 tests/stp.at      | 90 ++++++++++++++++++++++++++++++++++++++++++-------------
 vswitchd/bridge.c | 10 +++++--
 2 files changed, 77 insertions(+), 23 deletions(-)

Comments

Jarno Rajahalme April 21, 2017, 12:34 a.m. UTC | #1
> On Mar 31, 2017, at 8:11 PM, nickcooper-zhangtonghao <nic@opencloud.tech> wrote:
> 
> When a bridge stp enabled, we assign sequentially element
> of stp_port array (in stp struct) to bridge ports. That is
> ok when no ports are added to bridge. When adding a port
> to bridge which stp enabled, the ovs-vswitchd will assign
> stp_port sequentially again. Then the stp_port belonging
> to one port may belong to other one.

Could you elaborate the problem with this STP port renumbering?

> This patch uses the
> OpenFlow port numbers instead of sequence numbers to avoid
> it.
> 

Using OpenFlow port numbers (32-bit) as STP port numbers (8-bit) seems wrong to me. Besides, you can always use the other-config stp-port-num in ovsdb to specify which STP port number you want, if you do not want them to be numbered automatically.

> Signed-off-by: nickcooper-zhangtonghao <nic@opencloud.tech>
> ---
> tests/stp.at      | 90 ++++++++++++++++++++++++++++++++++++++++++-------------
> vswitchd/bridge.c | 10 +++++--
> 2 files changed, 77 insertions(+), 23 deletions(-)
> 
> diff --git a/tests/stp.at b/tests/stp.at
> index bd5d208..98632a8 100644
> --- a/tests/stp.at
> +++ b/tests/stp.at
> @@ -570,11 +570,6 @@ for i in $(seq 0 35); do
> done
> 
> # root bridge sends query packet
> -# we don't want to lose that message, so send it twice
> -AT_CHECK([ovs-appctl netdev-dummy/receive br0 \
> -        '01005E010101000C29A027D18100000108004500001C000100004002CBCBAC102201E00101011114EEEB00000000'])
> -
> -ovs-appctl time/warp 1000
> AT_CHECK([ovs-appctl netdev-dummy/receive br0 \
>         '01005E010101000C29A027D18100000108004500001C000100004002CBCBAC102201E00101011114EEEB00000000'])
> 
> @@ -589,21 +584,14 @@ OVS_WAIT_UNTIL([ovs-appctl mdb/show br2 | grep 'querier'])
> # del p2 on the br0, the topology will be changed
> AT_CHECK([ovs-vsctl del-port br0 p2])
> 
> -# give time for STP to synchronize
> -ovs-appctl time/warp 3000
> -ovs-appctl time/warp 3000
> -ovs-appctl time/warp 3000
> -ovs-appctl time/warp 3000
> -ovs-appctl time/warp 3000
> -
> -ovs-appctl time/warp 3000
> -ovs-appctl time/warp 3000
> -ovs-appctl time/warp 3000
> -ovs-appctl time/warp 3000
> -ovs-appctl time/warp 3000
> -
> -ovs-appctl time/warp 3000
> -ovs-appctl time/warp 3000
> +# We give time for STP to synchronize. The message age of
> +# p6 port will time out after 20s. The p5 will left blocked
> +# state to forwarding after 30s and then br2 bridge will
> +# detect the topology change, flush the fdb and sent tcn BPDU.
> +# br1 and br0 will also flush fdb when receiving tcn BPDU.
> +for i in $(seq 0 52); do
> +    ovs-appctl time/warp 1000
> +done
> 
> # check fdb and mdb
> AT_CHECK([ovs-appctl fdb/show br0], [0], [dnl
> @@ -626,5 +614,67 @@ AT_CHECK([ovs-appctl mdb/show br2], [0], [dnl
>  port  VLAN  GROUP                Age
> ])
> 
> +AT_CLEANUP
> +
> +AT_SETUP([STP - check the stp ports num])
> +OVS_VSWITCHD_START([])
> +
> +AT_CHECK([
> +    ovs-vsctl -- \
> +    set port br0 other_config:stp-enable=false -- \
> +    set bridge br0 datapath-type=dummy stp_enable=true \
> +    other-config:hwaddr=aa:66:aa:66:00:00
> +], [0])
> +
> +AT_CHECK([
> +    ovs-vsctl add-port br0 p1 -- \
> +        set interface p1 type=dummy ofport_request=1
> +    ovs-vsctl add-port br0 p2 -- \
> +        set interface p2 type=dummy ofport_request=2
> +], [0])
> +
> +ovs-appctl time/stop
> +
> +# give time for STP to move initially
> +for i in $(seq 0 30); do
> +    ovs-appctl time/warp 1000
> +done
> +
> +AT_CHECK([ovs-appctl stp/show br0 | grep p1], [0], [dnl
> +	p1         designated forwarding 19    128.1
> +])
> +AT_CHECK([ovs-appctl stp/show br0 | grep p2], [0], [dnl
> +	p2         designated forwarding 19    128.2
> +])
> +
> +# add a stp port
> +AT_CHECK([
> +    ovs-vsctl add-port br0 p3 -- \
> +        set interface p3 type=dummy ofport_request=3
> +], [0])
> +
> +# The new stp port should be a listening state and other
> +# stp ports keep forwarding.
> +AT_CHECK([ovs-appctl stp/show br0 | grep p1], [0], [dnl
> +	p1         designated forwarding 19    128.1
> +])
> +AT_CHECK([ovs-appctl stp/show br0 | grep p2], [0], [dnl
> +	p2         designated forwarding 19    128.2
> +])
> +AT_CHECK([ovs-appctl stp/show br0 | grep p3], [0], [dnl
> +	p3         designated listening  19    128.3
> +])
> +
> +# delete p1 stp port
> +AT_CHECK([ovs-vsctl del-port br0 p1])
> +
> +# The other stp ports keep original state.
> +AT_CHECK([ovs-appctl stp/show br0 | grep p2], [0], [dnl
> +	p2         designated forwarding 19    128.2
> +])
> +AT_CHECK([ovs-appctl stp/show br0 | grep p3], [0], [dnl
> +	p3         designated listening  19    128.3
> +])
> +
> OVS_VSWITCHD_STOP
> AT_CLEANUP
> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
> index 867a26d..d683000 100644
> --- a/vswitchd/bridge.c
> +++ b/vswitchd/bridge.c
> @@ -1396,13 +1396,17 @@ port_configure_stp(const struct ofproto *ofproto, struct port *port,
>         bitmap_set1(port_num_bitmap, port_idx);
>         port_s->port_num = port_idx;
>     } else {
> -        if (*port_num_counter >= STP_MAX_PORTS) {
> -            VLOG_ERR("port %s: too many STP ports, disabling", port->name);
> +        if (iface->ofp_port > STP_MAX_PORTS) {
> +            VLOG_ERR("port %s: too many STP ports or OpenFlow port number "
> +                     "(%d) > STP_MAX_PORTS (%d), disabling", port->name,
> +                     iface->ofp_port, STP_MAX_PORTS);
> +
>             port_s->enable = false;
>             return;
>         }
> 
> -        port_s->port_num = (*port_num_counter)++;
> +        port_s->port_num = iface->ofp_port -1;
> +        (*port_num_counter)++;
>     }
> 
>     config_str = smap_get(&port->cfg->other_config, "stp-path-cost");
> -- 
> 1.8.3.1
> 
> 
> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
nickcooper-zhangtonghao April 21, 2017, 10:04 a.m. UTC | #2
> On Apr 21, 2017, at 8:34 AM, Jarno Rajahalme <jarno@ovn.org> wrote:
> 
>> 
>> On Mar 31, 2017, at 8:11 PM, nickcooper-zhangtonghao <nic@opencloud.tech <mailto:nic@opencloud.tech>> wrote:
>> 
>> When a bridge stp enabled, we assign sequentially element
>> of stp_port array (in stp struct) to bridge ports. That is
>> ok when no ports are added to bridge. When adding a port
>> to bridge which stp enabled, the ovs-vswitchd will assign
>> stp_port sequentially again. Then the stp_port belonging
>> to one port may belong to other one.
> 
> Could you elaborate the problem with this STP port renumbering?

When we add a port to bridge which stp is enabled, the stp ports are renumbered.

For example:
p0 is mapped to one array element of struct stp_port ports[STP_MAX_PORTS] (e.g. ports[0])
p1 is mapped to one array element of struct stp_port ports[STP_MAX_PORTS] (e.g. ports[1])

When we add a port p2 to bridge, the p2 may be mapped to ports[0], p0 is mapped to ports[1], and  p1 is mapped to ports[2].
But we hope that p2 may be mapped to ports[2], p0 is mapped to ports[0], and  p1 is mapped to ports[1].
If not, the stp ports of bridge will converge. As a general rule, the state of new port should be changed
(e.g goto forwarding state or blocking.) and other stp ports remain the same.


Test shell:

#!/bin/bash
ovs-vsctl add-br br0
ovs-vsctl add-br br1

ovs-appctl vlog/set ofproto_dpif:dbg

ovs-vsctl add-port br0 p1 -- \
    set interface p1 type=dummy options:pstream=punix:/tmp/p1.sock ofport_request=1

ovs-vsctl add-port br0 p2 -- \
    set interface p2 type=dummy options:pstream=punix:/tmp/p2.sock ofport_request=2

ovs-vsctl add-port br1 p6 -- \
    set interface p6 type=dummy options:stream=unix:/tmp/p1.sock ofport_request=6

ovs-vsctl add-port br1 p7 -- \
    set interface p7 type=dummy options:stream=unix:/tmp/p2.sock ofport_request=7

ovs-ofctl add-flow br0 action=normal
ovs-ofctl add-flow br1 action=normal

ovs-appctl netdev-dummy/set-admin-state up

ovs-vsctl set port br0 other_config:stp-enable=false -- \
    set bridge br0 stp_enable=true other-config:hwaddr=aa:66:aa:66:00:00

ovs-vsctl set port br1 other_config:stp-enable=false -- \
    set bridge br1 stp_enable=true other-config:hwaddr=aa:66:aa:66:00:01


# ovs-appctl stp/show
<---cut--->
Bridge ID:
	stp-priority	32768
	stp-system-id	aa:66:aa:66:00:01
	stp-hello-time	2s
	stp-max-age	20s
	stp-fwd-delay	15s

	Interface  Role       State      Cost  Pri.Nbr
	---------- ---------- ---------- ----- -------
	p6         alternate  blocking   19    128.1
	p7         root       forwarding 19    128.2


# ovs-vsctl add-port br1 p8
# ovs-appctl stp/show
<---cut--->
Bridge ID:
	stp-priority	32768
	stp-system-id	aa:66:aa:66:00:01
	stp-hello-time	2s
	stp-max-age	20s
	stp-fwd-delay	15s

	Interface  Role       State      Cost  Pri.Nbr
	---------- ---------- ---------- ----- -------
	p8         alternate  blocking   19    128.1
	p6         root       forwarding 19    128.2
	p7         designated listening  19    128.3


After adding the p8 port, p8 uses the p6 state, p6 uses the p7 state, and p7 uses the new state.
The rstp works well without elaboration.

>> This patch uses the
>> OpenFlow port numbers instead of sequence numbers to avoid
>> it.
>> 
> 
> Using OpenFlow port numbers (32-bit) as STP port numbers (8-bit) seems wrong to me. Besides, you can always use the other-config stp-port-num in ovsdb to specify which STP port number you want, if you do not want them to be numbered automatically.

Yes, the max number of stp ports on bridge is STP_MAX_PORTS(255), and this should not be problem. Assigning the openflow port num to stp port is simple. But we can use other way to assign stp port number. If you have any idea, please let me know.
diff mbox

Patch

diff --git a/tests/stp.at b/tests/stp.at
index bd5d208..98632a8 100644
--- a/tests/stp.at
+++ b/tests/stp.at
@@ -570,11 +570,6 @@  for i in $(seq 0 35); do
 done
 
 # root bridge sends query packet
-# we don't want to lose that message, so send it twice
-AT_CHECK([ovs-appctl netdev-dummy/receive br0 \
-        '01005E010101000C29A027D18100000108004500001C000100004002CBCBAC102201E00101011114EEEB00000000'])
-
-ovs-appctl time/warp 1000
 AT_CHECK([ovs-appctl netdev-dummy/receive br0 \
         '01005E010101000C29A027D18100000108004500001C000100004002CBCBAC102201E00101011114EEEB00000000'])
 
@@ -589,21 +584,14 @@  OVS_WAIT_UNTIL([ovs-appctl mdb/show br2 | grep 'querier'])
 # del p2 on the br0, the topology will be changed
 AT_CHECK([ovs-vsctl del-port br0 p2])
 
-# give time for STP to synchronize
-ovs-appctl time/warp 3000
-ovs-appctl time/warp 3000
-ovs-appctl time/warp 3000
-ovs-appctl time/warp 3000
-ovs-appctl time/warp 3000
-
-ovs-appctl time/warp 3000
-ovs-appctl time/warp 3000
-ovs-appctl time/warp 3000
-ovs-appctl time/warp 3000
-ovs-appctl time/warp 3000
-
-ovs-appctl time/warp 3000
-ovs-appctl time/warp 3000
+# We give time for STP to synchronize. The message age of
+# p6 port will time out after 20s. The p5 will left blocked
+# state to forwarding after 30s and then br2 bridge will
+# detect the topology change, flush the fdb and sent tcn BPDU.
+# br1 and br0 will also flush fdb when receiving tcn BPDU.
+for i in $(seq 0 52); do
+    ovs-appctl time/warp 1000
+done
 
 # check fdb and mdb
 AT_CHECK([ovs-appctl fdb/show br0], [0], [dnl
@@ -626,5 +614,67 @@  AT_CHECK([ovs-appctl mdb/show br2], [0], [dnl
  port  VLAN  GROUP                Age
 ])
 
+AT_CLEANUP
+
+AT_SETUP([STP - check the stp ports num])
+OVS_VSWITCHD_START([])
+
+AT_CHECK([
+    ovs-vsctl -- \
+    set port br0 other_config:stp-enable=false -- \
+    set bridge br0 datapath-type=dummy stp_enable=true \
+    other-config:hwaddr=aa:66:aa:66:00:00
+], [0])
+
+AT_CHECK([
+    ovs-vsctl add-port br0 p1 -- \
+        set interface p1 type=dummy ofport_request=1
+    ovs-vsctl add-port br0 p2 -- \
+        set interface p2 type=dummy ofport_request=2
+], [0])
+
+ovs-appctl time/stop
+
+# give time for STP to move initially
+for i in $(seq 0 30); do
+    ovs-appctl time/warp 1000
+done
+
+AT_CHECK([ovs-appctl stp/show br0 | grep p1], [0], [dnl
+	p1         designated forwarding 19    128.1
+])
+AT_CHECK([ovs-appctl stp/show br0 | grep p2], [0], [dnl
+	p2         designated forwarding 19    128.2
+])
+
+# add a stp port
+AT_CHECK([
+    ovs-vsctl add-port br0 p3 -- \
+        set interface p3 type=dummy ofport_request=3
+], [0])
+
+# The new stp port should be a listening state and other
+# stp ports keep forwarding.
+AT_CHECK([ovs-appctl stp/show br0 | grep p1], [0], [dnl
+	p1         designated forwarding 19    128.1
+])
+AT_CHECK([ovs-appctl stp/show br0 | grep p2], [0], [dnl
+	p2         designated forwarding 19    128.2
+])
+AT_CHECK([ovs-appctl stp/show br0 | grep p3], [0], [dnl
+	p3         designated listening  19    128.3
+])
+
+# delete p1 stp port
+AT_CHECK([ovs-vsctl del-port br0 p1])
+
+# The other stp ports keep original state.
+AT_CHECK([ovs-appctl stp/show br0 | grep p2], [0], [dnl
+	p2         designated forwarding 19    128.2
+])
+AT_CHECK([ovs-appctl stp/show br0 | grep p3], [0], [dnl
+	p3         designated listening  19    128.3
+])
+
 OVS_VSWITCHD_STOP
 AT_CLEANUP
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 867a26d..d683000 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -1396,13 +1396,17 @@  port_configure_stp(const struct ofproto *ofproto, struct port *port,
         bitmap_set1(port_num_bitmap, port_idx);
         port_s->port_num = port_idx;
     } else {
-        if (*port_num_counter >= STP_MAX_PORTS) {
-            VLOG_ERR("port %s: too many STP ports, disabling", port->name);
+        if (iface->ofp_port > STP_MAX_PORTS) {
+            VLOG_ERR("port %s: too many STP ports or OpenFlow port number "
+                     "(%d) > STP_MAX_PORTS (%d), disabling", port->name,
+                     iface->ofp_port, STP_MAX_PORTS);
+
             port_s->enable = false;
             return;
         }
 
-        port_s->port_num = (*port_num_counter)++;
+        port_s->port_num = iface->ofp_port -1;
+        (*port_num_counter)++;
     }
 
     config_str = smap_get(&port->cfg->other_config, "stp-path-cost");