Commit 19a0b58e authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller

team: allow to enable/disable ports

This patch changes content of hashlist (used to get port struct by
computed index (0...en_port_count-1)). Now the hash list contains only
enabled ports so userspace will be able to say what ports can be used
for tx/rx. This becomes handy when userspace will need to disable ports
which does not belong to active aggregator. By default, newly added port
is enabled.
Signed-off-by: default avatarJiri Pirko <jpirko@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4c78bb84
...@@ -559,6 +559,8 @@ static int team_change_mode(struct team *team, const char *kind) ...@@ -559,6 +559,8 @@ static int team_change_mode(struct team *team, const char *kind)
* Rx path frame handler * Rx path frame handler
************************/ ************************/
static bool team_port_enabled(struct team_port *port);
/* note: already called with rcu_read_lock */ /* note: already called with rcu_read_lock */
static rx_handler_result_t team_handle_frame(struct sk_buff **pskb) static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
{ {
...@@ -575,8 +577,12 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb) ...@@ -575,8 +577,12 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
port = team_port_get_rcu(skb->dev); port = team_port_get_rcu(skb->dev);
team = port->team; team = port->team;
if (!team_port_enabled(port)) {
res = team->ops.receive(team, port, skb); /* allow exact match delivery for disabled ports */
res = RX_HANDLER_EXACT;
} else {
res = team->ops.receive(team, port, skb);
}
if (res == RX_HANDLER_ANOTHER) { if (res == RX_HANDLER_ANOTHER) {
struct team_pcpu_stats *pcpu_stats; struct team_pcpu_stats *pcpu_stats;
...@@ -612,17 +618,25 @@ static bool team_port_find(const struct team *team, ...@@ -612,17 +618,25 @@ static bool team_port_find(const struct team *team,
return false; return false;
} }
static bool team_port_enabled(struct team_port *port)
{
return port->index != -1;
}
/* /*
* Add/delete port to the team port list. Write guarded by rtnl_lock. * Enable/disable port by adding to enabled port hashlist and setting
* Takes care of correct port->index setup (might be racy). * port->index (Might be racy so reader could see incorrect ifindex when
* processing a flying packet, but that is not a problem). Write guarded
* by team->lock.
*/ */
static void team_port_list_add_port(struct team *team, static void team_port_enable(struct team *team,
struct team_port *port) struct team_port *port)
{ {
port->index = team->port_count++; if (team_port_enabled(port))
return;
port->index = team->en_port_count++;
hlist_add_head_rcu(&port->hlist, hlist_add_head_rcu(&port->hlist,
team_port_index_hash(team, port->index)); team_port_index_hash(team, port->index));
list_add_tail_rcu(&port->list, &team->port_list);
} }
static void __reconstruct_port_hlist(struct team *team, int rm_index) static void __reconstruct_port_hlist(struct team *team, int rm_index)
...@@ -630,7 +644,7 @@ static void __reconstruct_port_hlist(struct team *team, int rm_index) ...@@ -630,7 +644,7 @@ static void __reconstruct_port_hlist(struct team *team, int rm_index)
int i; int i;
struct team_port *port; struct team_port *port;
for (i = rm_index + 1; i < team->port_count; i++) { for (i = rm_index + 1; i < team->en_port_count; i++) {
port = team_get_port_by_index(team, i); port = team_get_port_by_index(team, i);
hlist_del_rcu(&port->hlist); hlist_del_rcu(&port->hlist);
port->index--; port->index--;
...@@ -639,15 +653,17 @@ static void __reconstruct_port_hlist(struct team *team, int rm_index) ...@@ -639,15 +653,17 @@ static void __reconstruct_port_hlist(struct team *team, int rm_index)
} }
} }
static void team_port_list_del_port(struct team *team, static void team_port_disable(struct team *team,
struct team_port *port) struct team_port *port)
{ {
int rm_index = port->index; int rm_index = port->index;
if (!team_port_enabled(port))
return;
hlist_del_rcu(&port->hlist); hlist_del_rcu(&port->hlist);
list_del_rcu(&port->list);
__reconstruct_port_hlist(team, rm_index); __reconstruct_port_hlist(team, rm_index);
team->port_count--; team->en_port_count--;
port->index = -1;
} }
#define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \ #define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
...@@ -800,7 +816,9 @@ static int team_port_add(struct team *team, struct net_device *port_dev) ...@@ -800,7 +816,9 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
goto err_option_port_add; goto err_option_port_add;
} }
team_port_list_add_port(team, port); port->index = -1;
team_port_enable(team, port);
list_add_tail_rcu(&port->list, &team->port_list);
team_adjust_ops(team); team_adjust_ops(team);
__team_compute_features(team); __team_compute_features(team);
__team_port_change_check(port, !!netif_carrier_ok(port_dev)); __team_port_change_check(port, !!netif_carrier_ok(port_dev));
...@@ -849,7 +867,8 @@ static int team_port_del(struct team *team, struct net_device *port_dev) ...@@ -849,7 +867,8 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
port->removed = true; port->removed = true;
__team_port_change_check(port, false); __team_port_change_check(port, false);
team_port_list_del_port(team, port); team_port_disable(team, port);
list_del_rcu(&port->list);
team_adjust_ops(team); team_adjust_ops(team);
team_option_port_del(team, port); team_option_port_del(team, port);
netdev_rx_handler_unregister(port_dev); netdev_rx_handler_unregister(port_dev);
...@@ -956,7 +975,7 @@ static int team_init(struct net_device *dev) ...@@ -956,7 +975,7 @@ static int team_init(struct net_device *dev)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < TEAM_PORT_HASHENTRIES; i++) for (i = 0; i < TEAM_PORT_HASHENTRIES; i++)
INIT_HLIST_HEAD(&team->port_hlist[i]); INIT_HLIST_HEAD(&team->en_port_hlist[i]);
INIT_LIST_HEAD(&team->port_list); INIT_LIST_HEAD(&team->port_list);
team_adjust_ops(team); team_adjust_ops(team);
......
...@@ -38,7 +38,7 @@ static bool lb_transmit(struct team *team, struct sk_buff *skb) ...@@ -38,7 +38,7 @@ static bool lb_transmit(struct team *team, struct sk_buff *skb)
if (unlikely(!fp)) if (unlikely(!fp))
goto drop; goto drop;
hash = SK_RUN_FILTER(fp, skb); hash = SK_RUN_FILTER(fp, skb);
port_index = hash % team->port_count; port_index = hash % team->en_port_count;
port = team_get_port_by_index_rcu(team, port_index); port = team_get_port_by_index_rcu(team, port_index);
if (unlikely(!port)) if (unlikely(!port))
goto drop; goto drop;
......
...@@ -50,7 +50,7 @@ static bool rr_transmit(struct team *team, struct sk_buff *skb) ...@@ -50,7 +50,7 @@ static bool rr_transmit(struct team *team, struct sk_buff *skb)
struct team_port *port; struct team_port *port;
int port_index; int port_index;
port_index = rr_priv(team)->sent_packets++ % team->port_count; port_index = rr_priv(team)->sent_packets++ % team->en_port_count;
port = team_get_port_by_index_rcu(team, port_index); port = team_get_port_by_index_rcu(team, port_index);
port = __get_first_port_up(team, port); port = __get_first_port_up(team, port);
if (unlikely(!port)) if (unlikely(!port))
......
...@@ -28,10 +28,10 @@ struct team; ...@@ -28,10 +28,10 @@ struct team;
struct team_port { struct team_port {
struct net_device *dev; struct net_device *dev;
struct hlist_node hlist; /* node in hash list */ struct hlist_node hlist; /* node in enabled ports hash list */
struct list_head list; /* node in ordinary list */ struct list_head list; /* node in ordinary list */
struct team *team; struct team *team;
int index; int index; /* index of enabled port. If disabled, it's set to -1 */
bool linkup; /* either state.linkup or user.linkup */ bool linkup; /* either state.linkup or user.linkup */
...@@ -125,11 +125,12 @@ struct team { ...@@ -125,11 +125,12 @@ struct team {
struct mutex lock; /* used for overall locking, e.g. port lists write */ struct mutex lock; /* used for overall locking, e.g. port lists write */
/* /*
* port lists with port count * List of enabled ports and their count
*/ */
int port_count; int en_port_count;
struct hlist_head port_hlist[TEAM_PORT_HASHENTRIES]; struct hlist_head en_port_hlist[TEAM_PORT_HASHENTRIES];
struct list_head port_list;
struct list_head port_list; /* list of all ports */
struct list_head option_list; struct list_head option_list;
struct list_head option_inst_list; /* list of option instances */ struct list_head option_inst_list; /* list of option instances */
...@@ -142,7 +143,7 @@ struct team { ...@@ -142,7 +143,7 @@ struct team {
static inline struct hlist_head *team_port_index_hash(struct team *team, static inline struct hlist_head *team_port_index_hash(struct team *team,
int port_index) int port_index)
{ {
return &team->port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)]; return &team->en_port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)];
} }
static inline struct team_port *team_get_port_by_index(struct team *team, static inline struct team_port *team_get_port_by_index(struct team *team,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment