Skip to content

Commit fc423ff

Browse files
jpirkodavem330
authored andcommitted
team: add peer notification
When port is enabled or disabled, allow to notify peers by unsolicitated NAs or gratuitous ARPs. Disabled by default. Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ab2cfbb commit fc423ff

File tree

2 files changed

+94
-1
lines changed

2 files changed

+94
-1
lines changed

drivers/net/team/team.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,46 @@ static int team_change_mode(struct team *team, const char *kind)
622622
}
623623

624624

625+
/*********************
626+
* Peers notification
627+
*********************/
628+
629+
static 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+
646+
static 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+
654+
static void team_notify_peers_init(struct team *team)
655+
{
656+
INIT_DELAYED_WORK(&team->notify_peers.dw, team_notify_peers_work);
657+
}
658+
659+
static void team_notify_peers_fini(struct team *team)
660+
{
661+
cancel_delayed_work_sync(&team->notify_peers.dw);
662+
}
663+
664+
625665
/************************
626666
* Rx path frame handler
627667
************************/
@@ -846,6 +886,7 @@ static void team_port_enable(struct team *team,
846886
team_queue_override_port_add(team, port);
847887
if (team->ops.port_enabled)
848888
team->ops.port_enabled(team, port);
889+
team_notify_peers(team);
849890
}
850891

851892
static void __reconstruct_port_hlist(struct team *team, int rm_index)
@@ -875,6 +916,7 @@ static void team_port_disable(struct team *team,
875916
team->en_port_count--;
876917
team_queue_override_port_del(team, port);
877918
team_adjust_ops(team);
919+
team_notify_peers(team);
878920
}
879921

880922
#define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
@@ -1205,6 +1247,34 @@ static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx)
12051247
return team_change_mode(team, ctx->data.str_val);
12061248
}
12071249

1250+
static int team_notify_peers_count_get(struct team *team,
1251+
struct team_gsetter_ctx *ctx)
1252+
{
1253+
ctx->data.u32_val = team->notify_peers.count;
1254+
return 0;
1255+
}
1256+
1257+
static int team_notify_peers_count_set(struct team *team,
1258+
struct team_gsetter_ctx *ctx)
1259+
{
1260+
team->notify_peers.count = ctx->data.u32_val;
1261+
return 0;
1262+
}
1263+
1264+
static int team_notify_peers_interval_get(struct team *team,
1265+
struct team_gsetter_ctx *ctx)
1266+
{
1267+
ctx->data.u32_val = team->notify_peers.interval;
1268+
return 0;
1269+
}
1270+
1271+
static int team_notify_peers_interval_set(struct team *team,
1272+
struct team_gsetter_ctx *ctx)
1273+
{
1274+
team->notify_peers.interval = ctx->data.u32_val;
1275+
return 0;
1276+
}
1277+
12081278
static int team_port_en_option_get(struct team *team,
12091279
struct team_gsetter_ctx *ctx)
12101280
{
@@ -1316,6 +1386,18 @@ static const struct team_option team_options[] = {
13161386
.getter = team_mode_option_get,
13171387
.setter = team_mode_option_set,
13181388
},
1389+
{
1390+
.name = "notify_peers_count",
1391+
.type = TEAM_OPTION_TYPE_U32,
1392+
.getter = team_notify_peers_count_get,
1393+
.setter = team_notify_peers_count_set,
1394+
},
1395+
{
1396+
.name = "notify_peers_interval",
1397+
.type = TEAM_OPTION_TYPE_U32,
1398+
.getter = team_notify_peers_interval_get,
1399+
.setter = team_notify_peers_interval_set,
1400+
},
13191401
{
13201402
.name = "enabled",
13211403
.type = TEAM_OPTION_TYPE_BOOL,
@@ -1396,6 +1478,9 @@ static int team_init(struct net_device *dev)
13961478

13971479
INIT_LIST_HEAD(&team->option_list);
13981480
INIT_LIST_HEAD(&team->option_inst_list);
1481+
1482+
team_notify_peers_init(team);
1483+
13991484
err = team_options_register(team, team_options, ARRAY_SIZE(team_options));
14001485
if (err)
14011486
goto err_options_register;
@@ -1406,6 +1491,7 @@ static int team_init(struct net_device *dev)
14061491
return 0;
14071492

14081493
err_options_register:
1494+
team_notify_peers_fini(team);
14091495
team_queue_override_fini(team);
14101496
err_team_queue_override_init:
14111497
free_percpu(team->pcpu_stats);
@@ -1425,6 +1511,7 @@ static void team_uninit(struct net_device *dev)
14251511

14261512
__team_change_mode(team, NULL); /* cleanup */
14271513
__team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
1514+
team_notify_peers_fini(team);
14281515
team_queue_override_fini(team);
14291516
mutex_unlock(&team->lock);
14301517
}

include/linux/if_team.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
#ifndef _LINUX_IF_TEAM_H_
1111
#define _LINUX_IF_TEAM_H_
1212

13-
1413
#include <linux/netpoll.h>
1514
#include <net/sch_generic.h>
15+
#include <linux/types.h>
1616
#include <uapi/linux/if_team.h>
1717

1818
struct team_pcpu_stats {
@@ -194,6 +194,12 @@ struct team {
194194
bool user_carrier_enabled;
195195
bool queue_override_enabled;
196196
struct list_head *qom_lists; /* array of queue override mapping lists */
197+
struct {
198+
unsigned int count;
199+
unsigned int interval; /* in ms */
200+
atomic_t count_pending;
201+
struct delayed_work dw;
202+
} notify_peers;
197203
long mode_priv[TEAM_MODE_PRIV_LONGS];
198204
};
199205

0 commit comments

Comments
 (0)