1) According to 6.4.12 of IEEE 802.1AX-2008, Figure 6-18, if the partner's sync
bit is not set, the lacp port state should be set to EXPIRED.
Function lacpdu_recv() makes the state of the lacp port to PORT_STATE_CURRENT
when the teamd receives any valid lacp packet. Fix it by checking the parter's
sync bit.
2) According to 6.4.15 of IEEE 802.1AX-2008, Figure 6-22, the state that the
port is selected moves MUX state from DETACHED to ATTACHED.
But ATTACHED sate does not mean that the port can send and receive user frames.
COLLECTING_DISTRIBUTION state is the sate that the port can send and receive
user frames. To move MUX state from ATTACHED to COLLECTING_DISTRIBUTION, the
partner state should be sync as well as the port selected.
In function lacp_port_actor_update(), only INFO_STATE_SYNCHRONIZATION should
be set to the actor.state when the port is selected. INFO_STATE_COLLECTING and
INFO_STATE_DISTRIBUTING should be set to false with ATTACHED mode and set to
true when INFO_STATE_SYNCHRONIZATION of partner.state is set.
In function lacp_port_should_be_{enabled, disabled}(), we also need to check
the INFO_STATE_SYNCHRONIZATION bit of partner.state.
Reported-by: Cisco Systems
Signed-off-by: Hangbin Liu <liuhangbin(a)gmail.com>
---
teamd/teamd_runner_lacp.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/teamd/teamd_runner_lacp.c b/teamd/teamd_runner_lacp.c
index 7b8f0a7..5e763ad 100644
--- a/teamd/teamd_runner_lacp.c
+++ b/teamd/teamd_runner_lacp.c
@@ -333,7 +333,8 @@ static int lacp_port_should_be_enabled(struct lacp_port *lacp_port)
struct lacp *lacp = lacp_port->lacp;
if (lacp_port_selected(lacp_port) &&
- lacp_port->agg_lead == lacp->selected_agg_lead)
+ lacp_port->agg_lead == lacp->selected_agg_lead &&
+ lacp_port->partner.state & INFO_STATE_SYNCHRONIZATION)
return true;
return false;
}
@@ -343,7 +344,8 @@ static int lacp_port_should_be_disabled(struct lacp_port *lacp_port)
struct lacp *lacp = lacp_port->lacp;
if (!lacp_port_selected(lacp_port) ||
- lacp_port->agg_lead != lacp->selected_agg_lead)
+ lacp_port->agg_lead != lacp->selected_agg_lead ||
+ !(lacp_port->partner.state & INFO_STATE_SYNCHRONIZATION))
return true;
return false;
}
@@ -914,9 +916,13 @@ static void lacp_port_actor_update(struct lacp_port *lacp_port)
if (lacp_port->lacp->cfg.fast_rate)
state |= INFO_STATE_LACP_TIMEOUT;
if (lacp_port_selected(lacp_port) &&
- lacp_port_agg_selected(lacp_port))
- state |= INFO_STATE_SYNCHRONIZATION |
- INFO_STATE_COLLECTING | INFO_STATE_DISTRIBUTING;
+ lacp_port_agg_selected(lacp_port)) {
+ state |= INFO_STATE_SYNCHRONIZATION;
+ state &= ~(INFO_STATE_COLLECTING | INFO_STATE_DISTRIBUTING);
+ if (lacp_port->partner.state & INFO_STATE_SYNCHRONIZATION)
+ state |= INFO_STATE_COLLECTING |
+ INFO_STATE_DISTRIBUTING;
+ }
if (lacp_port->state == PORT_STATE_EXPIRED)
state |= INFO_STATE_EXPIRED;
if (lacp_port->state == PORT_STATE_DEFAULTED)
@@ -1095,7 +1101,10 @@ static int lacpdu_recv(struct lacp_port *lacp_port)
return err;
}
- err = lacp_port_set_state(lacp_port, PORT_STATE_CURRENT);
+ if (lacp_port->partner.state & INFO_STATE_SYNCHRONIZATION)
+ err = lacp_port_set_state(lacp_port, PORT_STATE_CURRENT);
+ else
+ err = lacp_port_set_state(lacp_port, PORT_STATE_EXPIRED);
if (err)
return err;
--
2.19.2
Show replies by date