Skip to content

Commit 492b200

Browse files
jpirkodavem330
authored andcommitted
team: add support for sending multicast rejoins
Similar to what is implemented in bonding. User is able to ask team driver to send IGMP rejoins in case port is enabled or disabled. Using previously introduced netdev notifier. Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 4aa5dee commit 492b200

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

drivers/net/team/team.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,46 @@ static void team_notify_peers_fini(struct team *team)
662662
}
663663

664664

665+
/*******************************
666+
* Send multicast group rejoins
667+
*******************************/
668+
669+
static 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+
686+
static 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+
694+
static void team_mcast_rejoin_init(struct team *team)
695+
{
696+
INIT_DELAYED_WORK(&team->mcast_rejoin.dw, team_mcast_rejoin_work);
697+
}
698+
699+
static void team_mcast_rejoin_fini(struct team *team)
700+
{
701+
cancel_delayed_work_sync(&team->mcast_rejoin.dw);
702+
}
703+
704+
665705
/************************
666706
* Rx path frame handler
667707
************************/
@@ -887,6 +927,7 @@ static void team_port_enable(struct team *team,
887927
if (team->ops.port_enabled)
888928
team->ops.port_enabled(team, port);
889929
team_notify_peers(team);
930+
team_mcast_rejoin(team);
890931
}
891932

892933
static void __reconstruct_port_hlist(struct team *team, int rm_index)
@@ -917,6 +958,7 @@ static void team_port_disable(struct team *team,
917958
team_queue_override_port_del(team, port);
918959
team_adjust_ops(team);
919960
team_notify_peers(team);
961+
team_mcast_rejoin(team);
920962
}
921963

922964
#define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
@@ -1275,6 +1317,34 @@ static int team_notify_peers_interval_set(struct team *team,
12751317
return 0;
12761318
}
12771319

1320+
static int team_mcast_rejoin_count_get(struct team *team,
1321+
struct team_gsetter_ctx *ctx)
1322+
{
1323+
ctx->data.u32_val = team->mcast_rejoin.count;
1324+
return 0;
1325+
}
1326+
1327+
static int team_mcast_rejoin_count_set(struct team *team,
1328+
struct team_gsetter_ctx *ctx)
1329+
{
1330+
team->mcast_rejoin.count = ctx->data.u32_val;
1331+
return 0;
1332+
}
1333+
1334+
static int team_mcast_rejoin_interval_get(struct team *team,
1335+
struct team_gsetter_ctx *ctx)
1336+
{
1337+
ctx->data.u32_val = team->mcast_rejoin.interval;
1338+
return 0;
1339+
}
1340+
1341+
static int team_mcast_rejoin_interval_set(struct team *team,
1342+
struct team_gsetter_ctx *ctx)
1343+
{
1344+
team->mcast_rejoin.interval = ctx->data.u32_val;
1345+
return 0;
1346+
}
1347+
12781348
static int team_port_en_option_get(struct team *team,
12791349
struct team_gsetter_ctx *ctx)
12801350
{
@@ -1398,6 +1468,18 @@ static const struct team_option team_options[] = {
13981468
.getter = team_notify_peers_interval_get,
13991469
.setter = team_notify_peers_interval_set,
14001470
},
1471+
{
1472+
.name = "mcast_rejoin_count",
1473+
.type = TEAM_OPTION_TYPE_U32,
1474+
.getter = team_mcast_rejoin_count_get,
1475+
.setter = team_mcast_rejoin_count_set,
1476+
},
1477+
{
1478+
.name = "mcast_rejoin_interval",
1479+
.type = TEAM_OPTION_TYPE_U32,
1480+
.getter = team_mcast_rejoin_interval_get,
1481+
.setter = team_mcast_rejoin_interval_set,
1482+
},
14011483
{
14021484
.name = "enabled",
14031485
.type = TEAM_OPTION_TYPE_BOOL,
@@ -1480,6 +1562,7 @@ static int team_init(struct net_device *dev)
14801562
INIT_LIST_HEAD(&team->option_inst_list);
14811563

14821564
team_notify_peers_init(team);
1565+
team_mcast_rejoin_init(team);
14831566

14841567
err = team_options_register(team, team_options, ARRAY_SIZE(team_options));
14851568
if (err)
@@ -1491,6 +1574,7 @@ static int team_init(struct net_device *dev)
14911574
return 0;
14921575

14931576
err_options_register:
1577+
team_mcast_rejoin_fini(team);
14941578
team_notify_peers_fini(team);
14951579
team_queue_override_fini(team);
14961580
err_team_queue_override_init:
@@ -1511,6 +1595,7 @@ static void team_uninit(struct net_device *dev)
15111595

15121596
__team_change_mode(team, NULL); /* cleanup */
15131597
__team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
1598+
team_mcast_rejoin_fini(team);
15141599
team_notify_peers_fini(team);
15151600
team_queue_override_fini(team);
15161601
mutex_unlock(&team->lock);

include/linux/if_team.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,12 @@ struct team {
200200
atomic_t count_pending;
201201
struct delayed_work dw;
202202
} notify_peers;
203+
struct {
204+
unsigned int count;
205+
unsigned int interval; /* in ms */
206+
atomic_t count_pending;
207+
struct delayed_work dw;
208+
} mcast_rejoin;
203209
long mode_priv[TEAM_MODE_PRIV_LONGS];
204210
};
205211

0 commit comments

Comments
 (0)