aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/team/team.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/team/team.c')
-rw-r--r--drivers/net/team/team.c203
1 files changed, 185 insertions, 18 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index bff7e0b0b4e7..50e43e64d51d 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -622,6 +622,86 @@ static int team_change_mode(struct team *team, const char *kind)
622} 622}
623 623
624 624
625/*********************
626 * Peers notification
627 *********************/
628
629static void team_notify_peers_work(struct work_struct *work)
630{
631 struct team *team;
632
633 team = container_of(work, struct team, notify_peers.dw.work);
634
635 if (!rtnl_trylock()) {
636 schedule_delayed_work(&team->notify_peers.dw, 0);
637 return;
638 }
639 call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, team->dev);
640 rtnl_unlock();
641 if (!atomic_dec_and_test(&team->notify_peers.count_pending))
642 schedule_delayed_work(&team->notify_peers.dw,
643 msecs_to_jiffies(team->notify_peers.interval));
644}
645
646static void team_notify_peers(struct team *team)
647{
648 if (!team->notify_peers.count || !netif_running(team->dev))
649 return;
650 atomic_set(&team->notify_peers.count_pending, team->notify_peers.count);
651 schedule_delayed_work(&team->notify_peers.dw, 0);
652}
653
654static void team_notify_peers_init(struct team *team)
655{
656 INIT_DELAYED_WORK(&team->notify_peers.dw, team_notify_peers_work);
657}
658
659static void team_notify_peers_fini(struct team *team)
660{
661 cancel_delayed_work_sync(&team->notify_peers.dw);
662}
663
664
665/*******************************
666 * Send multicast group rejoins
667 *******************************/
668
669static void team_mcast_rejoin_work(struct work_struct *work)
670{
671 struct team *team;
672
673 team = container_of(work, struct team, mcast_rejoin.dw.work);
674
675 if (!rtnl_trylock()) {
676 schedule_delayed_work(&team->mcast_rejoin.dw, 0);
677 return;
678 }
679 call_netdevice_notifiers(NETDEV_RESEND_IGMP, team->dev);
680 rtnl_unlock();
681 if (!atomic_dec_and_test(&team->mcast_rejoin.count_pending))
682 schedule_delayed_work(&team->mcast_rejoin.dw,
683 msecs_to_jiffies(team->mcast_rejoin.interval));
684}
685
686static void team_mcast_rejoin(struct team *team)
687{
688 if (!team->mcast_rejoin.count || !netif_running(team->dev))
689 return;
690 atomic_set(&team->mcast_rejoin.count_pending, team->mcast_rejoin.count);
691 schedule_delayed_work(&team->mcast_rejoin.dw, 0);
692}
693
694static void team_mcast_rejoin_init(struct team *team)
695{
696 INIT_DELAYED_WORK(&team->mcast_rejoin.dw, team_mcast_rejoin_work);
697}
698
699static void team_mcast_rejoin_fini(struct team *team)
700{
701 cancel_delayed_work_sync(&team->mcast_rejoin.dw);
702}
703
704
625/************************ 705/************************
626 * Rx path frame handler 706 * Rx path frame handler
627 ************************/ 707 ************************/
@@ -846,6 +926,8 @@ static void team_port_enable(struct team *team,
846 team_queue_override_port_add(team, port); 926 team_queue_override_port_add(team, port);
847 if (team->ops.port_enabled) 927 if (team->ops.port_enabled)
848 team->ops.port_enabled(team, port); 928 team->ops.port_enabled(team, port);
929 team_notify_peers(team);
930 team_mcast_rejoin(team);
849} 931}
850 932
851static void __reconstruct_port_hlist(struct team *team, int rm_index) 933static void __reconstruct_port_hlist(struct team *team, int rm_index)
@@ -875,6 +957,8 @@ static void team_port_disable(struct team *team,
875 team->en_port_count--; 957 team->en_port_count--;
876 team_queue_override_port_del(team, port); 958 team_queue_override_port_del(team, port);
877 team_adjust_ops(team); 959 team_adjust_ops(team);
960 team_notify_peers(team);
961 team_mcast_rejoin(team);
878} 962}
879 963
880#define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \ 964#define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
@@ -953,6 +1037,9 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port,
953 struct netpoll *np; 1037 struct netpoll *np;
954 int err; 1038 int err;
955 1039
1040 if (!team->dev->npinfo)
1041 return 0;
1042
956 np = kzalloc(sizeof(*np), gfp); 1043 np = kzalloc(sizeof(*np), gfp);
957 if (!np) 1044 if (!np)
958 return -ENOMEM; 1045 return -ENOMEM;
@@ -979,12 +1066,6 @@ static void team_port_disable_netpoll(struct team_port *port)
979 __netpoll_cleanup(np); 1066 __netpoll_cleanup(np);
980 kfree(np); 1067 kfree(np);
981} 1068}
982
983static struct netpoll_info *team_netpoll_info(struct team *team)
984{
985 return team->dev->npinfo;
986}
987
988#else 1069#else
989static int team_port_enable_netpoll(struct team *team, struct team_port *port, 1070static int team_port_enable_netpoll(struct team *team, struct team_port *port,
990 gfp_t gfp) 1071 gfp_t gfp)
@@ -994,10 +1075,6 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port,
994static void team_port_disable_netpoll(struct team_port *port) 1075static void team_port_disable_netpoll(struct team_port *port)
995{ 1076{
996} 1077}
997static struct netpoll_info *team_netpoll_info(struct team *team)
998{
999 return NULL;
1000}
1001#endif 1078#endif
1002 1079
1003static void __team_port_change_port_added(struct team_port *port, bool linkup); 1080static void __team_port_change_port_added(struct team_port *port, bool linkup);
@@ -1079,13 +1156,11 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
1079 goto err_vids_add; 1156 goto err_vids_add;
1080 } 1157 }
1081 1158
1082 if (team_netpoll_info(team)) { 1159 err = team_port_enable_netpoll(team, port, GFP_KERNEL);
1083 err = team_port_enable_netpoll(team, port, GFP_KERNEL); 1160 if (err) {
1084 if (err) { 1161 netdev_err(dev, "Failed to enable netpoll on device %s\n",
1085 netdev_err(dev, "Failed to enable netpoll on device %s\n", 1162 portname);
1086 portname); 1163 goto err_enable_netpoll;
1087 goto err_enable_netpoll;
1088 }
1089 } 1164 }
1090 1165
1091 err = netdev_master_upper_dev_link(port_dev, dev); 1166 err = netdev_master_upper_dev_link(port_dev, dev);
@@ -1205,6 +1280,62 @@ static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx)
1205 return team_change_mode(team, ctx->data.str_val); 1280 return team_change_mode(team, ctx->data.str_val);
1206} 1281}
1207 1282
1283static int team_notify_peers_count_get(struct team *team,
1284 struct team_gsetter_ctx *ctx)
1285{
1286 ctx->data.u32_val = team->notify_peers.count;
1287 return 0;
1288}
1289
1290static int team_notify_peers_count_set(struct team *team,
1291 struct team_gsetter_ctx *ctx)
1292{
1293 team->notify_peers.count = ctx->data.u32_val;
1294 return 0;
1295}
1296
1297static int team_notify_peers_interval_get(struct team *team,
1298 struct team_gsetter_ctx *ctx)
1299{
1300 ctx->data.u32_val = team->notify_peers.interval;
1301 return 0;
1302}
1303
1304static int team_notify_peers_interval_set(struct team *team,
1305 struct team_gsetter_ctx *ctx)
1306{
1307 team->notify_peers.interval = ctx->data.u32_val;
1308 return 0;
1309}
1310
1311static int team_mcast_rejoin_count_get(struct team *team,
1312 struct team_gsetter_ctx *ctx)
1313{
1314 ctx->data.u32_val = team->mcast_rejoin.count;
1315 return 0;
1316}
1317
1318static int team_mcast_rejoin_count_set(struct team *team,
1319 struct team_gsetter_ctx *ctx)
1320{
1321 team->mcast_rejoin.count = ctx->data.u32_val;
1322 return 0;
1323}
1324
1325static int team_mcast_rejoin_interval_get(struct team *team,
1326 struct team_gsetter_ctx *ctx)
1327{
1328 ctx->data.u32_val = team->mcast_rejoin.interval;
1329 return 0;
1330}
1331
1332static int team_mcast_rejoin_interval_set(struct team *team,
1333 struct team_gsetter_ctx *ctx)
1334{
1335 team->mcast_rejoin.interval = ctx->data.u32_val;
1336 return 0;
1337}
1338
1208static int team_port_en_option_get(struct team *team, 1339static int team_port_en_option_get(struct team *team,
1209 struct team_gsetter_ctx *ctx) 1340 struct team_gsetter_ctx *ctx)
1210{ 1341{
@@ -1317,6 +1448,30 @@ static const struct team_option team_options[] = {
1317 .setter = team_mode_option_set, 1448 .setter = team_mode_option_set,
1318 }, 1449 },
1319 { 1450 {
1451 .name = "notify_peers_count",
1452 .type = TEAM_OPTION_TYPE_U32,
1453 .getter = team_notify_peers_count_get,
1454 .setter = team_notify_peers_count_set,
1455 },
1456 {
1457 .name = "notify_peers_interval",
1458 .type = TEAM_OPTION_TYPE_U32,
1459 .getter = team_notify_peers_interval_get,
1460 .setter = team_notify_peers_interval_set,
1461 },
1462 {
1463 .name = "mcast_rejoin_count",
1464 .type = TEAM_OPTION_TYPE_U32,
1465 .getter = team_mcast_rejoin_count_get,
1466 .setter = team_mcast_rejoin_count_set,
1467 },
1468 {
1469 .name = "mcast_rejoin_interval",
1470 .type = TEAM_OPTION_TYPE_U32,
1471 .getter = team_mcast_rejoin_interval_get,
1472 .setter = team_mcast_rejoin_interval_set,
1473 },
1474 {
1320 .name = "enabled", 1475 .name = "enabled",
1321 .type = TEAM_OPTION_TYPE_BOOL, 1476 .type = TEAM_OPTION_TYPE_BOOL,
1322 .per_port = true, 1477 .per_port = true,
@@ -1396,6 +1551,10 @@ static int team_init(struct net_device *dev)
1396 1551
1397 INIT_LIST_HEAD(&team->option_list); 1552 INIT_LIST_HEAD(&team->option_list);
1398 INIT_LIST_HEAD(&team->option_inst_list); 1553 INIT_LIST_HEAD(&team->option_inst_list);
1554
1555 team_notify_peers_init(team);
1556 team_mcast_rejoin_init(team);
1557
1399 err = team_options_register(team, team_options, ARRAY_SIZE(team_options)); 1558 err = team_options_register(team, team_options, ARRAY_SIZE(team_options));
1400 if (err) 1559 if (err)
1401 goto err_options_register; 1560 goto err_options_register;
@@ -1406,6 +1565,8 @@ static int team_init(struct net_device *dev)
1406 return 0; 1565 return 0;
1407 1566
1408err_options_register: 1567err_options_register:
1568 team_mcast_rejoin_fini(team);
1569 team_notify_peers_fini(team);
1409 team_queue_override_fini(team); 1570 team_queue_override_fini(team);
1410err_team_queue_override_init: 1571err_team_queue_override_init:
1411 free_percpu(team->pcpu_stats); 1572 free_percpu(team->pcpu_stats);
@@ -1425,6 +1586,8 @@ static void team_uninit(struct net_device *dev)
1425 1586
1426 __team_change_mode(team, NULL); /* cleanup */ 1587 __team_change_mode(team, NULL); /* cleanup */
1427 __team_options_unregister(team, team_options, ARRAY_SIZE(team_options)); 1588 __team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
1589 team_mcast_rejoin_fini(team);
1590 team_notify_peers_fini(team);
1428 team_queue_override_fini(team); 1591 team_queue_override_fini(team);
1429 mutex_unlock(&team->lock); 1592 mutex_unlock(&team->lock);
1430} 1593}
@@ -1811,7 +1974,7 @@ static void team_setup_by_port(struct net_device *dev,
1811 dev->addr_len = port_dev->addr_len; 1974 dev->addr_len = port_dev->addr_len;
1812 dev->mtu = port_dev->mtu; 1975 dev->mtu = port_dev->mtu;
1813 memcpy(dev->broadcast, port_dev->broadcast, port_dev->addr_len); 1976 memcpy(dev->broadcast, port_dev->broadcast, port_dev->addr_len);
1814 memcpy(dev->dev_addr, port_dev->dev_addr, port_dev->addr_len); 1977 eth_hw_addr_inherit(dev, port_dev);
1815} 1978}
1816 1979
1817static int team_dev_type_check_change(struct net_device *dev, 1980static int team_dev_type_check_change(struct net_device *dev,
@@ -2698,6 +2861,10 @@ static int team_device_event(struct notifier_block *unused,
2698 case NETDEV_PRE_TYPE_CHANGE: 2861 case NETDEV_PRE_TYPE_CHANGE:
2699 /* Forbid to change type of underlaying device */ 2862 /* Forbid to change type of underlaying device */
2700 return NOTIFY_BAD; 2863 return NOTIFY_BAD;
2864 case NETDEV_RESEND_IGMP:
2865 /* Propagate to master device */
2866 call_netdevice_notifiers(event, port->team->dev);
2867 break;
2701 } 2868 }
2702 return NOTIFY_DONE; 2869 return NOTIFY_DONE;
2703} 2870}