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

team: add user_linkup and user_linkup_enabled per-port option

Allows userspace to setup linkup for ports. Default is to take linkup
directly from ethtool state.
Signed-off-by: default avatarJiri Pirko <jpirko@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 14f066ba
...@@ -76,6 +76,11 @@ int team_port_set_team_mac(struct team_port *port) ...@@ -76,6 +76,11 @@ int team_port_set_team_mac(struct team_port *port)
} }
EXPORT_SYMBOL(team_port_set_team_mac); EXPORT_SYMBOL(team_port_set_team_mac);
static void team_refresh_port_linkup(struct team_port *port)
{
port->linkup = port->user.linkup_enabled ? port->user.linkup :
port->state.linkup;
}
/******************* /*******************
* Options handling * Options handling
...@@ -880,6 +885,40 @@ static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx) ...@@ -880,6 +885,40 @@ static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx)
return team_change_mode(team, ctx->data.str_val); return team_change_mode(team, ctx->data.str_val);
} }
static int team_user_linkup_option_get(struct team *team,
struct team_gsetter_ctx *ctx)
{
ctx->data.bool_val = ctx->port->user.linkup;
return 0;
}
static int team_user_linkup_option_set(struct team *team,
struct team_gsetter_ctx *ctx)
{
ctx->port->user.linkup = ctx->data.bool_val;
team_refresh_port_linkup(ctx->port);
return 0;
}
static int team_user_linkup_en_option_get(struct team *team,
struct team_gsetter_ctx *ctx)
{
struct team_port *port = ctx->port;
ctx->data.bool_val = port->user.linkup_enabled;
return 0;
}
static int team_user_linkup_en_option_set(struct team *team,
struct team_gsetter_ctx *ctx)
{
struct team_port *port = ctx->port;
port->user.linkup_enabled = ctx->data.bool_val;
team_refresh_port_linkup(ctx->port);
return 0;
}
static const struct team_option team_options[] = { static const struct team_option team_options[] = {
{ {
.name = "mode", .name = "mode",
...@@ -887,6 +926,20 @@ static const struct team_option team_options[] = { ...@@ -887,6 +926,20 @@ static const struct team_option team_options[] = {
.getter = team_mode_option_get, .getter = team_mode_option_get,
.setter = team_mode_option_set, .setter = team_mode_option_set,
}, },
{
.name = "user_linkup",
.type = TEAM_OPTION_TYPE_BOOL,
.per_port = true,
.getter = team_user_linkup_option_get,
.setter = team_user_linkup_option_set,
},
{
.name = "user_linkup_enabled",
.type = TEAM_OPTION_TYPE_BOOL,
.per_port = true,
.getter = team_user_linkup_en_option_get,
.setter = team_user_linkup_en_option_set,
},
}; };
static int team_init(struct net_device *dev) static int team_init(struct net_device *dev)
...@@ -1670,10 +1723,10 @@ static int team_nl_fill_port_list_get(struct sk_buff *skb, ...@@ -1670,10 +1723,10 @@ static int team_nl_fill_port_list_get(struct sk_buff *skb,
} }
if ((port->removed && if ((port->removed &&
nla_put_flag(skb, TEAM_ATTR_PORT_REMOVED)) || nla_put_flag(skb, TEAM_ATTR_PORT_REMOVED)) ||
(port->linkup && (port->state.linkup &&
nla_put_flag(skb, TEAM_ATTR_PORT_LINKUP)) || nla_put_flag(skb, TEAM_ATTR_PORT_LINKUP)) ||
nla_put_u32(skb, TEAM_ATTR_PORT_SPEED, port->speed) || nla_put_u32(skb, TEAM_ATTR_PORT_SPEED, port->state.speed) ||
nla_put_u8(skb, TEAM_ATTR_PORT_DUPLEX, port->duplex)) nla_put_u8(skb, TEAM_ATTR_PORT_DUPLEX, port->state.duplex))
goto nla_put_failure; goto nla_put_failure;
nla_nest_end(skb, port_item); nla_nest_end(skb, port_item);
} }
...@@ -1833,23 +1886,24 @@ static void __team_port_change_check(struct team_port *port, bool linkup) ...@@ -1833,23 +1886,24 @@ static void __team_port_change_check(struct team_port *port, bool linkup)
{ {
int err; int err;
if (!port->removed && port->linkup == linkup) if (!port->removed && port->state.linkup == linkup)
return; return;
port->changed = true; port->changed = true;
port->linkup = linkup; port->state.linkup = linkup;
team_refresh_port_linkup(port);
if (linkup) { if (linkup) {
struct ethtool_cmd ecmd; struct ethtool_cmd ecmd;
err = __ethtool_get_settings(port->dev, &ecmd); err = __ethtool_get_settings(port->dev, &ecmd);
if (!err) { if (!err) {
port->speed = ethtool_cmd_speed(&ecmd); port->state.speed = ethtool_cmd_speed(&ecmd);
port->duplex = ecmd.duplex; port->state.duplex = ecmd.duplex;
goto send_event; goto send_event;
} }
} }
port->speed = 0; port->state.speed = 0;
port->duplex = 0; port->state.duplex = 0;
send_event: send_event:
err = team_nl_send_event_port_list_get(port->team); err = team_nl_send_event_port_list_get(port->team);
......
...@@ -33,6 +33,24 @@ struct team_port { ...@@ -33,6 +33,24 @@ struct team_port {
struct team *team; struct team *team;
int index; int index;
bool linkup; /* either state.linkup or user.linkup */
struct {
bool linkup;
u32 speed;
u8 duplex;
} state;
/* Values set by userspace */
struct {
bool linkup;
bool linkup_enabled;
} user;
/* Custom gennetlink interface related flags */
bool changed;
bool removed;
/* /*
* A place for storing original values of the device before it * A place for storing original values of the device before it
* become a port. * become a port.
...@@ -42,14 +60,6 @@ struct team_port { ...@@ -42,14 +60,6 @@ struct team_port {
unsigned int mtu; unsigned int mtu;
} orig; } orig;
bool linkup;
u32 speed;
u8 duplex;
/* Custom gennetlink interface related flags */
bool changed;
bool removed;
struct rcu_head rcu; struct rcu_head rcu;
}; };
......
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