All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit fc423ff0 authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller

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: default avatarJiri Pirko <jiri@resnulli.us>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ab2cfbb2
......@@ -622,6 +622,46 @@ static int team_change_mode(struct team *team, const char *kind)
}
/*********************
* Peers notification
*********************/
static void team_notify_peers_work(struct work_struct *work)
{
struct team *team;
team = container_of(work, struct team, notify_peers.dw.work);
if (!rtnl_trylock()) {
schedule_delayed_work(&team->notify_peers.dw, 0);
return;
}
call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, team->dev);
rtnl_unlock();
if (!atomic_dec_and_test(&team->notify_peers.count_pending))
schedule_delayed_work(&team->notify_peers.dw,
msecs_to_jiffies(team->notify_peers.interval));
}
static void team_notify_peers(struct team *team)
{
if (!team->notify_peers.count || !netif_running(team->dev))
return;
atomic_set(&team->notify_peers.count_pending, team->notify_peers.count);
schedule_delayed_work(&team->notify_peers.dw, 0);
}
static void team_notify_peers_init(struct team *team)
{
INIT_DELAYED_WORK(&team->notify_peers.dw, team_notify_peers_work);
}
static void team_notify_peers_fini(struct team *team)
{
cancel_delayed_work_sync(&team->notify_peers.dw);
}
/************************
* Rx path frame handler
************************/
......@@ -846,6 +886,7 @@ static void team_port_enable(struct team *team,
team_queue_override_port_add(team, port);
if (team->ops.port_enabled)
team->ops.port_enabled(team, port);
team_notify_peers(team);
}
static void __reconstruct_port_hlist(struct team *team, int rm_index)
......@@ -875,6 +916,7 @@ static void team_port_disable(struct team *team,
team->en_port_count--;
team_queue_override_port_del(team, port);
team_adjust_ops(team);
team_notify_peers(team);
}
#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)
return team_change_mode(team, ctx->data.str_val);
}
static int team_notify_peers_count_get(struct team *team,
struct team_gsetter_ctx *ctx)
{
ctx->data.u32_val = team->notify_peers.count;
return 0;
}
static int team_notify_peers_count_set(struct team *team,
struct team_gsetter_ctx *ctx)
{
team->notify_peers.count = ctx->data.u32_val;
return 0;
}
static int team_notify_peers_interval_get(struct team *team,
struct team_gsetter_ctx *ctx)
{
ctx->data.u32_val = team->notify_peers.interval;
return 0;
}
static int team_notify_peers_interval_set(struct team *team,
struct team_gsetter_ctx *ctx)
{
team->notify_peers.interval = ctx->data.u32_val;
return 0;
}
static int team_port_en_option_get(struct team *team,
struct team_gsetter_ctx *ctx)
{
......@@ -1316,6 +1386,18 @@ static const struct team_option team_options[] = {
.getter = team_mode_option_get,
.setter = team_mode_option_set,
},
{
.name = "notify_peers_count",
.type = TEAM_OPTION_TYPE_U32,
.getter = team_notify_peers_count_get,
.setter = team_notify_peers_count_set,
},
{
.name = "notify_peers_interval",
.type = TEAM_OPTION_TYPE_U32,
.getter = team_notify_peers_interval_get,
.setter = team_notify_peers_interval_set,
},
{
.name = "enabled",
.type = TEAM_OPTION_TYPE_BOOL,
......@@ -1396,6 +1478,9 @@ static int team_init(struct net_device *dev)
INIT_LIST_HEAD(&team->option_list);
INIT_LIST_HEAD(&team->option_inst_list);
team_notify_peers_init(team);
err = team_options_register(team, team_options, ARRAY_SIZE(team_options));
if (err)
goto err_options_register;
......@@ -1406,6 +1491,7 @@ static int team_init(struct net_device *dev)
return 0;
err_options_register:
team_notify_peers_fini(team);
team_queue_override_fini(team);
err_team_queue_override_init:
free_percpu(team->pcpu_stats);
......@@ -1425,6 +1511,7 @@ static void team_uninit(struct net_device *dev)
__team_change_mode(team, NULL); /* cleanup */
__team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
team_notify_peers_fini(team);
team_queue_override_fini(team);
mutex_unlock(&team->lock);
}
......
......@@ -10,9 +10,9 @@
#ifndef _LINUX_IF_TEAM_H_
#define _LINUX_IF_TEAM_H_
#include <linux/netpoll.h>
#include <net/sch_generic.h>
#include <linux/types.h>
#include <uapi/linux/if_team.h>
struct team_pcpu_stats {
......@@ -194,6 +194,12 @@ struct team {
bool user_carrier_enabled;
bool queue_override_enabled;
struct list_head *qom_lists; /* array of queue override mapping lists */
struct {
unsigned int count;
unsigned int interval; /* in ms */
atomic_t count_pending;
struct delayed_work dw;
} notify_peers;
long mode_priv[TEAM_MODE_PRIV_LONGS];
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment