struct netdev_lag_lower_state_info info;
info.link_up = port->linkup;
- info.tx_enabled = team_port_enabled(port);
+ info.tx_enabled = team_port_tx_enabled(port);
netdev_lower_state_changed(port->dev, &info);
}
else
team->ops.transmit = team->mode->ops->transmit;
- if (!team->tx_en_port_count || !team_is_mode_set(team) ||
+ if (!team->rx_en_port_count || !team_is_mode_set(team) ||
!team->mode->ops->receive)
team->ops.receive = team_dummy_receive;
else
port = team_port_get_rcu(skb->dev);
team = port->team;
- if (!team_port_enabled(port)) {
+ if (!team_port_rx_enabled(port)) {
if (is_link_local_ether_addr(eth_hdr(skb)->h_dest))
/* link-local packets are mostly useful when stack receives them
* with the link they arrive on.
static void team_queue_override_port_prio_changed(struct team *team,
struct team_port *port)
{
- if (!port->queue_id || !team_port_enabled(port))
+ if (!port->queue_id || !team_port_tx_enabled(port))
return;
__team_queue_override_port_del(team, port);
__team_queue_override_port_add(team, port);
struct team_port *port,
u16 new_queue_id)
{
- if (team_port_enabled(port)) {
+ if (team_port_tx_enabled(port)) {
__team_queue_override_port_del(team, port);
port->queue_id = new_queue_id;
__team_queue_override_port_add(team, port);
return false;
}
+static void __team_port_enable_rx(struct team *team,
+ struct team_port *port)
+{
+ team->rx_en_port_count++;
+ WRITE_ONCE(port->rx_enabled, true);
+}
+
+static void __team_port_disable_rx(struct team *team,
+ struct team_port *port)
+{
+ team->rx_en_port_count--;
+ WRITE_ONCE(port->rx_enabled, false);
+}
+
/*
- * Enable/disable port by adding to enabled port hashlist and setting
- * port->tx_index (Might be racy so reader could see incorrect ifindex when
- * processing a flying packet, but that is not a problem). Write guarded
- * by RTNL.
+ * Enable just TX on the port by adding to tx-enabled port hashlist and
+ * setting port->tx_index (Might be racy so reader could see incorrect
+ * ifindex when processing a flying packet, but that is not a problem).
+ * Write guarded by RTNL.
*/
-static void team_port_enable(struct team *team,
- struct team_port *port)
+static void __team_port_enable_tx(struct team *team,
+ struct team_port *port)
{
- if (team_port_enabled(port))
- return;
WRITE_ONCE(port->tx_index, team->tx_en_port_count);
WRITE_ONCE(team->tx_en_port_count, team->tx_en_port_count + 1);
hlist_add_head_rcu(&port->tx_hlist,
team_tx_port_index_hash(team, port->tx_index));
- team_adjust_ops(team);
- team_queue_override_port_add(team, port);
- team_notify_peers(team);
- team_mcast_rejoin(team);
- team_lower_state_changed(port);
}
static void __reconstruct_port_hlist(struct team *team, int rm_index)
}
}
-static void team_port_disable(struct team *team,
- struct team_port *port)
+static void __team_port_disable_tx(struct team *team,
+ struct team_port *port)
{
- if (!team_port_enabled(port))
- return;
if (team->ops.port_tx_disabled)
team->ops.port_tx_disabled(team, port);
+
hlist_del_rcu(&port->tx_hlist);
__reconstruct_port_hlist(team, port->tx_index);
+
WRITE_ONCE(port->tx_index, -1);
WRITE_ONCE(team->tx_en_port_count, team->tx_en_port_count - 1);
- team_queue_override_port_del(team, port);
+}
+
+/*
+ * Enable TX AND RX on the port.
+ */
+static void team_port_enable(struct team *team,
+ struct team_port *port)
+{
+ bool rx_was_enabled;
+ bool tx_was_enabled;
+
+ if (team_port_enabled(port))
+ return;
+
+ rx_was_enabled = team_port_rx_enabled(port);
+ tx_was_enabled = team_port_tx_enabled(port);
+
+ if (!rx_was_enabled)
+ __team_port_enable_rx(team, port);
+ if (!tx_was_enabled)
+ __team_port_enable_tx(team, port);
+
+ team_adjust_ops(team);
+ if (!tx_was_enabled)
+ team_queue_override_port_add(team, port);
+ team_notify_peers(team);
+ if (!rx_was_enabled)
+ team_mcast_rejoin(team);
+ if (!tx_was_enabled)
+ team_lower_state_changed(port);
+}
+
+static void team_port_disable(struct team *team,
+ struct team_port *port)
+{
+ bool rx_was_enabled = team_port_rx_enabled(port);
+ bool tx_was_enabled = team_port_tx_enabled(port);
+
+ if (!tx_was_enabled && !rx_was_enabled)
+ return;
+
+ if (tx_was_enabled) {
+ __team_port_disable_tx(team, port);
+ team_queue_override_port_del(team, port);
+ }
+ if (rx_was_enabled)
+ __team_port_disable_rx(team, port);
+
team_adjust_ops(team);
- team_lower_state_changed(port);
+
+ if (tx_was_enabled)
+ team_lower_state_changed(port);
}
static int team_port_enter(struct team *team, struct team_port *port)