diff options
author | Jiri Pirko <jpirko@redhat.com> | 2012-04-20 00:42:05 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-04-21 16:26:33 -0400 |
commit | 19a0b58e506b06fd41659d8734bba6a3e87980f4 (patch) | |
tree | f9844eaf9d1471c6fcd98c850b1ed6cd57f2bce3 /drivers | |
parent | 4c78bb845bd2aaf1f7136e75314c7d034cfd120f (diff) |
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: Jiri Pirko <jpirko@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/team/team.c | 51 | ||||
-rw-r--r-- | drivers/net/team/team_mode_loadbalance.c | 2 | ||||
-rw-r--r-- | drivers/net/team/team_mode_roundrobin.c | 2 |
3 files changed, 37 insertions, 18 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 153a62d03c9f..fe7ca40284fa 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c | |||
@@ -559,6 +559,8 @@ static int team_change_mode(struct team *team, const char *kind) | |||
559 | * Rx path frame handler | 559 | * Rx path frame handler |
560 | ************************/ | 560 | ************************/ |
561 | 561 | ||
562 | static bool team_port_enabled(struct team_port *port); | ||
563 | |||
562 | /* note: already called with rcu_read_lock */ | 564 | /* note: already called with rcu_read_lock */ |
563 | static rx_handler_result_t team_handle_frame(struct sk_buff **pskb) | 565 | static rx_handler_result_t team_handle_frame(struct sk_buff **pskb) |
564 | { | 566 | { |
@@ -575,8 +577,12 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb) | |||
575 | 577 | ||
576 | port = team_port_get_rcu(skb->dev); | 578 | port = team_port_get_rcu(skb->dev); |
577 | team = port->team; | 579 | team = port->team; |
578 | 580 | if (!team_port_enabled(port)) { | |
579 | res = team->ops.receive(team, port, skb); | 581 | /* allow exact match delivery for disabled ports */ |
582 | res = RX_HANDLER_EXACT; | ||
583 | } else { | ||
584 | res = team->ops.receive(team, port, skb); | ||
585 | } | ||
580 | if (res == RX_HANDLER_ANOTHER) { | 586 | if (res == RX_HANDLER_ANOTHER) { |
581 | struct team_pcpu_stats *pcpu_stats; | 587 | struct team_pcpu_stats *pcpu_stats; |
582 | 588 | ||
@@ -612,17 +618,25 @@ static bool team_port_find(const struct team *team, | |||
612 | return false; | 618 | return false; |
613 | } | 619 | } |
614 | 620 | ||
621 | static bool team_port_enabled(struct team_port *port) | ||
622 | { | ||
623 | return port->index != -1; | ||
624 | } | ||
625 | |||
615 | /* | 626 | /* |
616 | * Add/delete port to the team port list. Write guarded by rtnl_lock. | 627 | * Enable/disable port by adding to enabled port hashlist and setting |
617 | * Takes care of correct port->index setup (might be racy). | 628 | * port->index (Might be racy so reader could see incorrect ifindex when |
629 | * processing a flying packet, but that is not a problem). Write guarded | ||
630 | * by team->lock. | ||
618 | */ | 631 | */ |
619 | static void team_port_list_add_port(struct team *team, | 632 | static void team_port_enable(struct team *team, |
620 | struct team_port *port) | 633 | struct team_port *port) |
621 | { | 634 | { |
622 | port->index = team->port_count++; | 635 | if (team_port_enabled(port)) |
636 | return; | ||
637 | port->index = team->en_port_count++; | ||
623 | hlist_add_head_rcu(&port->hlist, | 638 | hlist_add_head_rcu(&port->hlist, |
624 | team_port_index_hash(team, port->index)); | 639 | team_port_index_hash(team, port->index)); |
625 | list_add_tail_rcu(&port->list, &team->port_list); | ||
626 | } | 640 | } |
627 | 641 | ||
628 | static void __reconstruct_port_hlist(struct team *team, int rm_index) | 642 | 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 | int i; | 644 | int i; |
631 | struct team_port *port; | 645 | struct team_port *port; |
632 | 646 | ||
633 | for (i = rm_index + 1; i < team->port_count; i++) { | 647 | for (i = rm_index + 1; i < team->en_port_count; i++) { |
634 | port = team_get_port_by_index(team, i); | 648 | port = team_get_port_by_index(team, i); |
635 | hlist_del_rcu(&port->hlist); | 649 | hlist_del_rcu(&port->hlist); |
636 | port->index--; | 650 | port->index--; |
@@ -639,15 +653,17 @@ static void __reconstruct_port_hlist(struct team *team, int rm_index) | |||
639 | } | 653 | } |
640 | } | 654 | } |
641 | 655 | ||
642 | static void team_port_list_del_port(struct team *team, | 656 | static void team_port_disable(struct team *team, |
643 | struct team_port *port) | 657 | struct team_port *port) |
644 | { | 658 | { |
645 | int rm_index = port->index; | 659 | int rm_index = port->index; |
646 | 660 | ||
661 | if (!team_port_enabled(port)) | ||
662 | return; | ||
647 | hlist_del_rcu(&port->hlist); | 663 | hlist_del_rcu(&port->hlist); |
648 | list_del_rcu(&port->list); | ||
649 | __reconstruct_port_hlist(team, rm_index); | 664 | __reconstruct_port_hlist(team, rm_index); |
650 | team->port_count--; | 665 | team->en_port_count--; |
666 | port->index = -1; | ||
651 | } | 667 | } |
652 | 668 | ||
653 | #define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \ | 669 | #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 | goto err_option_port_add; | 816 | goto err_option_port_add; |
801 | } | 817 | } |
802 | 818 | ||
803 | team_port_list_add_port(team, port); | 819 | port->index = -1; |
820 | team_port_enable(team, port); | ||
821 | list_add_tail_rcu(&port->list, &team->port_list); | ||
804 | team_adjust_ops(team); | 822 | team_adjust_ops(team); |
805 | __team_compute_features(team); | 823 | __team_compute_features(team); |
806 | __team_port_change_check(port, !!netif_carrier_ok(port_dev)); | 824 | __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 | 867 | ||
850 | port->removed = true; | 868 | port->removed = true; |
851 | __team_port_change_check(port, false); | 869 | __team_port_change_check(port, false); |
852 | team_port_list_del_port(team, port); | 870 | team_port_disable(team, port); |
871 | list_del_rcu(&port->list); | ||
853 | team_adjust_ops(team); | 872 | team_adjust_ops(team); |
854 | team_option_port_del(team, port); | 873 | team_option_port_del(team, port); |
855 | netdev_rx_handler_unregister(port_dev); | 874 | netdev_rx_handler_unregister(port_dev); |
@@ -956,7 +975,7 @@ static int team_init(struct net_device *dev) | |||
956 | return -ENOMEM; | 975 | return -ENOMEM; |
957 | 976 | ||
958 | for (i = 0; i < TEAM_PORT_HASHENTRIES; i++) | 977 | for (i = 0; i < TEAM_PORT_HASHENTRIES; i++) |
959 | INIT_HLIST_HEAD(&team->port_hlist[i]); | 978 | INIT_HLIST_HEAD(&team->en_port_hlist[i]); |
960 | INIT_LIST_HEAD(&team->port_list); | 979 | INIT_LIST_HEAD(&team->port_list); |
961 | 980 | ||
962 | team_adjust_ops(team); | 981 | team_adjust_ops(team); |
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c index 438d5b871630..86e8183c8e3d 100644 --- a/drivers/net/team/team_mode_loadbalance.c +++ b/drivers/net/team/team_mode_loadbalance.c | |||
@@ -38,7 +38,7 @@ static bool lb_transmit(struct team *team, struct sk_buff *skb) | |||
38 | if (unlikely(!fp)) | 38 | if (unlikely(!fp)) |
39 | goto drop; | 39 | goto drop; |
40 | hash = SK_RUN_FILTER(fp, skb); | 40 | hash = SK_RUN_FILTER(fp, skb); |
41 | port_index = hash % team->port_count; | 41 | port_index = hash % team->en_port_count; |
42 | port = team_get_port_by_index_rcu(team, port_index); | 42 | port = team_get_port_by_index_rcu(team, port_index); |
43 | if (unlikely(!port)) | 43 | if (unlikely(!port)) |
44 | goto drop; | 44 | goto drop; |
diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c index a0e8f806331a..6abfbdc96be5 100644 --- a/drivers/net/team/team_mode_roundrobin.c +++ b/drivers/net/team/team_mode_roundrobin.c | |||
@@ -50,7 +50,7 @@ static bool rr_transmit(struct team *team, struct sk_buff *skb) | |||
50 | struct team_port *port; | 50 | struct team_port *port; |
51 | int port_index; | 51 | int port_index; |
52 | 52 | ||
53 | port_index = rr_priv(team)->sent_packets++ % team->port_count; | 53 | port_index = rr_priv(team)->sent_packets++ % team->en_port_count; |
54 | port = team_get_port_by_index_rcu(team, port_index); | 54 | port = team_get_port_by_index_rcu(team, port_index); |
55 | port = __get_first_port_up(team, port); | 55 | port = __get_first_port_up(team, port); |
56 | if (unlikely(!port)) | 56 | if (unlikely(!port)) |