aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/team/team.c113
-rw-r--r--drivers/net/team/team_mode_activebackup.c3
-rw-r--r--drivers/net/team/team_mode_broadcast.c7
-rw-r--r--drivers/net/team/team_mode_loadbalance.c3
-rw-r--r--drivers/net/team/team_mode_roundrobin.c3
-rw-r--r--include/linux/if_team.h33
6 files changed, 152 insertions, 10 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 3620c63f9345..1a13470dee07 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -18,6 +18,7 @@
18#include <linux/ctype.h> 18#include <linux/ctype.h>
19#include <linux/notifier.h> 19#include <linux/notifier.h>
20#include <linux/netdevice.h> 20#include <linux/netdevice.h>
21#include <linux/netpoll.h>
21#include <linux/if_vlan.h> 22#include <linux/if_vlan.h>
22#include <linux/if_arp.h> 23#include <linux/if_arp.h>
23#include <linux/socket.h> 24#include <linux/socket.h>
@@ -787,6 +788,58 @@ static void team_port_leave(struct team *team, struct team_port *port)
787 dev_put(team->dev); 788 dev_put(team->dev);
788} 789}
789 790
791#ifdef CONFIG_NET_POLL_CONTROLLER
792static int team_port_enable_netpoll(struct team *team, struct team_port *port)
793{
794 struct netpoll *np;
795 int err;
796
797 np = kzalloc(sizeof(*np), GFP_KERNEL);
798 if (!np)
799 return -ENOMEM;
800
801 err = __netpoll_setup(np, port->dev);
802 if (err) {
803 kfree(np);
804 return err;
805 }
806 port->np = np;
807 return err;
808}
809
810static void team_port_disable_netpoll(struct team_port *port)
811{
812 struct netpoll *np = port->np;
813
814 if (!np)
815 return;
816 port->np = NULL;
817
818 /* Wait for transmitting packets to finish before freeing. */
819 synchronize_rcu_bh();
820 __netpoll_cleanup(np);
821 kfree(np);
822}
823
824static struct netpoll_info *team_netpoll_info(struct team *team)
825{
826 return team->dev->npinfo;
827}
828
829#else
830static int team_port_enable_netpoll(struct team *team, struct team_port *port)
831{
832 return 0;
833}
834static void team_port_disable_netpoll(struct team_port *port)
835{
836}
837static struct netpoll_info *team_netpoll_info(struct team *team)
838{
839 return NULL;
840}
841#endif
842
790static void __team_port_change_check(struct team_port *port, bool linkup); 843static void __team_port_change_check(struct team_port *port, bool linkup);
791 844
792static int team_port_add(struct team *team, struct net_device *port_dev) 845static int team_port_add(struct team *team, struct net_device *port_dev)
@@ -853,6 +906,15 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
853 goto err_vids_add; 906 goto err_vids_add;
854 } 907 }
855 908
909 if (team_netpoll_info(team)) {
910 err = team_port_enable_netpoll(team, port);
911 if (err) {
912 netdev_err(dev, "Failed to enable netpoll on device %s\n",
913 portname);
914 goto err_enable_netpoll;
915 }
916 }
917
856 err = netdev_set_master(port_dev, dev); 918 err = netdev_set_master(port_dev, dev);
857 if (err) { 919 if (err) {
858 netdev_err(dev, "Device %s failed to set master\n", portname); 920 netdev_err(dev, "Device %s failed to set master\n", portname);
@@ -892,6 +954,9 @@ err_handler_register:
892 netdev_set_master(port_dev, NULL); 954 netdev_set_master(port_dev, NULL);
893 955
894err_set_master: 956err_set_master:
957 team_port_disable_netpoll(port);
958
959err_enable_netpoll:
895 vlan_vids_del_by_dev(port_dev, dev); 960 vlan_vids_del_by_dev(port_dev, dev);
896 961
897err_vids_add: 962err_vids_add:
@@ -932,6 +997,7 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
932 list_del_rcu(&port->list); 997 list_del_rcu(&port->list);
933 netdev_rx_handler_unregister(port_dev); 998 netdev_rx_handler_unregister(port_dev);
934 netdev_set_master(port_dev, NULL); 999 netdev_set_master(port_dev, NULL);
1000 team_port_disable_netpoll(port);
935 vlan_vids_del_by_dev(port_dev, dev); 1001 vlan_vids_del_by_dev(port_dev, dev);
936 dev_close(port_dev); 1002 dev_close(port_dev);
937 team_port_leave(team, port); 1003 team_port_leave(team, port);
@@ -1307,6 +1373,48 @@ static int team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
1307 return 0; 1373 return 0;
1308} 1374}
1309 1375
1376#ifdef CONFIG_NET_POLL_CONTROLLER
1377static void team_poll_controller(struct net_device *dev)
1378{
1379}
1380
1381static void __team_netpoll_cleanup(struct team *team)
1382{
1383 struct team_port *port;
1384
1385 list_for_each_entry(port, &team->port_list, list)
1386 team_port_disable_netpoll(port);
1387}
1388
1389static void team_netpoll_cleanup(struct net_device *dev)
1390{
1391 struct team *team = netdev_priv(dev);
1392
1393 mutex_lock(&team->lock);
1394 __team_netpoll_cleanup(team);
1395 mutex_unlock(&team->lock);
1396}
1397
1398static int team_netpoll_setup(struct net_device *dev,
1399 struct netpoll_info *npifo)
1400{
1401 struct team *team = netdev_priv(dev);
1402 struct team_port *port;
1403 int err;
1404
1405 mutex_lock(&team->lock);
1406 list_for_each_entry(port, &team->port_list, list) {
1407 err = team_port_enable_netpoll(team, port);
1408 if (err) {
1409 __team_netpoll_cleanup(team);
1410 break;
1411 }
1412 }
1413 mutex_unlock(&team->lock);
1414 return err;
1415}
1416#endif
1417
1310static int team_add_slave(struct net_device *dev, struct net_device *port_dev) 1418static int team_add_slave(struct net_device *dev, struct net_device *port_dev)
1311{ 1419{
1312 struct team *team = netdev_priv(dev); 1420 struct team *team = netdev_priv(dev);
@@ -1363,6 +1471,11 @@ static const struct net_device_ops team_netdev_ops = {
1363 .ndo_get_stats64 = team_get_stats64, 1471 .ndo_get_stats64 = team_get_stats64,
1364 .ndo_vlan_rx_add_vid = team_vlan_rx_add_vid, 1472 .ndo_vlan_rx_add_vid = team_vlan_rx_add_vid,
1365 .ndo_vlan_rx_kill_vid = team_vlan_rx_kill_vid, 1473 .ndo_vlan_rx_kill_vid = team_vlan_rx_kill_vid,
1474#ifdef CONFIG_NET_POLL_CONTROLLER
1475 .ndo_poll_controller = team_poll_controller,
1476 .ndo_netpoll_setup = team_netpoll_setup,
1477 .ndo_netpoll_cleanup = team_netpoll_cleanup,
1478#endif
1366 .ndo_add_slave = team_add_slave, 1479 .ndo_add_slave = team_add_slave,
1367 .ndo_del_slave = team_del_slave, 1480 .ndo_del_slave = team_del_slave,
1368 .ndo_fix_features = team_fix_features, 1481 .ndo_fix_features = team_fix_features,
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
index 253b8a5f3427..6262b4defd93 100644
--- a/drivers/net/team/team_mode_activebackup.c
+++ b/drivers/net/team/team_mode_activebackup.c
@@ -43,8 +43,7 @@ static bool ab_transmit(struct team *team, struct sk_buff *skb)
43 active_port = rcu_dereference_bh(ab_priv(team)->active_port); 43 active_port = rcu_dereference_bh(ab_priv(team)->active_port);
44 if (unlikely(!active_port)) 44 if (unlikely(!active_port))
45 goto drop; 45 goto drop;
46 skb->dev = active_port->dev; 46 if (team_dev_queue_xmit(team, active_port, skb))
47 if (dev_queue_xmit(skb))
48 return false; 47 return false;
49 return true; 48 return true;
50 49
diff --git a/drivers/net/team/team_mode_broadcast.c b/drivers/net/team/team_mode_broadcast.c
index 5562345e9cef..c96e4d2967f0 100644
--- a/drivers/net/team/team_mode_broadcast.c
+++ b/drivers/net/team/team_mode_broadcast.c
@@ -29,8 +29,8 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb)
29 if (last) { 29 if (last) {
30 skb2 = skb_clone(skb, GFP_ATOMIC); 30 skb2 = skb_clone(skb, GFP_ATOMIC);
31 if (skb2) { 31 if (skb2) {
32 skb2->dev = last->dev; 32 ret = team_dev_queue_xmit(team, last,
33 ret = dev_queue_xmit(skb2); 33 skb2);
34 if (!sum_ret) 34 if (!sum_ret)
35 sum_ret = ret; 35 sum_ret = ret;
36 } 36 }
@@ -39,8 +39,7 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb)
39 } 39 }
40 } 40 }
41 if (last) { 41 if (last) {
42 skb->dev = last->dev; 42 ret = team_dev_queue_xmit(team, last, skb);
43 ret = dev_queue_xmit(skb);
44 if (!sum_ret) 43 if (!sum_ret)
45 sum_ret = ret; 44 sum_ret = ret;
46 } 45 }
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index 51a4b199c75c..cdc31b5ea15e 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -217,8 +217,7 @@ static bool lb_transmit(struct team *team, struct sk_buff *skb)
217 port = select_tx_port_func(team, lb_priv, skb, hash); 217 port = select_tx_port_func(team, lb_priv, skb, hash);
218 if (unlikely(!port)) 218 if (unlikely(!port))
219 goto drop; 219 goto drop;
220 skb->dev = port->dev; 220 if (team_dev_queue_xmit(team, port, skb))
221 if (dev_queue_xmit(skb))
222 return false; 221 return false;
223 lb_update_tx_stats(tx_bytes, lb_priv, get_lb_port_priv(port), hash); 222 lb_update_tx_stats(tx_bytes, lb_priv, get_lb_port_priv(port), hash);
224 return true; 223 return true;
diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c
index 0cf38e9b9d26..ad7ed0ec544c 100644
--- a/drivers/net/team/team_mode_roundrobin.c
+++ b/drivers/net/team/team_mode_roundrobin.c
@@ -55,8 +55,7 @@ static bool rr_transmit(struct team *team, struct sk_buff *skb)
55 port = __get_first_port_up(team, port); 55 port = __get_first_port_up(team, port);
56 if (unlikely(!port)) 56 if (unlikely(!port))
57 goto drop; 57 goto drop;
58 skb->dev = port->dev; 58 if (team_dev_queue_xmit(team, port, skb))
59 if (dev_queue_xmit(skb))
60 return false; 59 return false;
61 return true; 60 return true;
62 61
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index dfa0c8e0ab84..7fd0cdeb9444 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -13,6 +13,8 @@
13 13
14#ifdef __KERNEL__ 14#ifdef __KERNEL__
15 15
16#include <linux/netpoll.h>
17
16struct team_pcpu_stats { 18struct team_pcpu_stats {
17 u64 rx_packets; 19 u64 rx_packets;
18 u64 rx_bytes; 20 u64 rx_bytes;
@@ -60,6 +62,10 @@ struct team_port {
60 unsigned int mtu; 62 unsigned int mtu;
61 } orig; 63 } orig;
62 64
65#ifdef CONFIG_NET_POLL_CONTROLLER
66 struct netpoll *np;
67#endif
68
63 long mode_priv[0]; 69 long mode_priv[0];
64}; 70};
65 71
@@ -73,6 +79,33 @@ static inline bool team_port_txable(struct team_port *port)
73 return port->linkup && team_port_enabled(port); 79 return port->linkup && team_port_enabled(port);
74} 80}
75 81
82#ifdef CONFIG_NET_POLL_CONTROLLER
83static inline void team_netpoll_send_skb(struct team_port *port,
84 struct sk_buff *skb)
85{
86 struct netpoll *np = port->np;
87
88 if (np)
89 netpoll_send_skb(np, skb);
90}
91#else
92static inline void team_netpoll_send_skb(struct team_port *port,
93 struct sk_buff *skb)
94{
95}
96#endif
97
98static inline int team_dev_queue_xmit(struct team *team, struct team_port *port,
99 struct sk_buff *skb)
100{
101 skb->dev = port->dev;
102 if (unlikely(netpoll_tx_running(port->dev))) {
103 team_netpoll_send_skb(port, skb);
104 return 0;
105 }
106 return dev_queue_xmit(skb);
107}
108
76struct team_mode_ops { 109struct team_mode_ops {
77 int (*init)(struct team *team); 110 int (*init)(struct team *team);
78 void (*exit)(struct team *team); 111 void (*exit)(struct team *team);