* [patch net-next 0/5] team: add some features and fixes
@ 2012-04-10 15:15 Jiri Pirko
2012-04-10 15:15 ` [patch net-next 1/5] team: add support for per-port options Jiri Pirko
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Jiri Pirko @ 2012-04-10 15:15 UTC (permalink / raw)
To: netdev; +Cc: davem, eric.dumazet
Jiri Pirko (5):
team: add support for per-port options
team: add bool option type
team: add user_linkup and user_linkup_enabled per-port option
team: ab: walk through port list non-rcu
team: add missed "statics"
drivers/net/team/team.c | 402 +++++++++++++++++++++++------
drivers/net/team/team_mode_activebackup.c | 20 +-
drivers/net/team/team_mode_loadbalance.c | 32 +--
include/linux/if_team.h | 58 +++--
4 files changed, 387 insertions(+), 125 deletions(-)
--
1.7.9.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [patch net-next 1/5] team: add support for per-port options
2012-04-10 15:15 [patch net-next 0/5] team: add some features and fixes Jiri Pirko
@ 2012-04-10 15:15 ` Jiri Pirko
2012-04-10 18:33 ` David Miller
2012-04-10 15:15 ` [patch net-next 2/5] team: add bool option type Jiri Pirko
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Jiri Pirko @ 2012-04-10 15:15 UTC (permalink / raw)
To: netdev; +Cc: davem, eric.dumazet
This patch allows to create per-port options. That becomes handy for all
sorts of stuff, for example for userspace driven link-state, 802.3ad
implementation and so on.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/team/team.c | 306 +++++++++++++++++++++++------
drivers/net/team/team_mode_activebackup.c | 14 +-
drivers/net/team/team_mode_loadbalance.c | 28 ++--
include/linux/if_team.h | 30 ++--
4 files changed, 278 insertions(+), 100 deletions(-)
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index ea96f82..eaf8441 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -81,7 +81,16 @@ EXPORT_SYMBOL(team_port_set_team_mac);
* Options handling
*******************/
-struct team_option *__team_find_option(struct team *team, const char *opt_name)
+struct team_option_inst { /* One for each option instance */
+ struct list_head list;
+ struct team_option *option;
+ struct team_port *port; /* != NULL if per-port */
+ bool changed;
+ bool removed;
+};
+
+static struct team_option *__team_find_option(struct team *team,
+ const char *opt_name)
{
struct team_option *option;
@@ -92,9 +101,121 @@ struct team_option *__team_find_option(struct team *team, const char *opt_name)
return NULL;
}
-int __team_options_register(struct team *team,
- const struct team_option *option,
- size_t option_count)
+static int __team_option_inst_add(struct team *team, struct team_option *option,
+ struct team_port *port)
+{
+ struct team_option_inst *opt_inst;
+
+ opt_inst = kmalloc(sizeof(*opt_inst), GFP_KERNEL);
+ if (!opt_inst)
+ return -ENOMEM;
+ opt_inst->option = option;
+ opt_inst->port = port;
+ opt_inst->changed = true;
+ opt_inst->removed = false;
+ list_add_tail(&opt_inst->list, &team->option_inst_list);
+ return 0;
+}
+
+static void __team_option_inst_del(struct team_option_inst *opt_inst)
+{
+ list_del(&opt_inst->list);
+ kfree(opt_inst);
+}
+
+static void __team_option_inst_del_option(struct team *team,
+ struct team_option *option)
+{
+ struct team_option_inst *opt_inst, *tmp;
+
+ list_for_each_entry_safe(opt_inst, tmp, &team->option_inst_list, list) {
+ if (opt_inst->option == option)
+ __team_option_inst_del(opt_inst);
+ }
+}
+
+static int __team_option_inst_add_option(struct team *team,
+ struct team_option *option)
+{
+ struct team_port *port;
+ int err;
+
+ if (!option->per_port)
+ return __team_option_inst_add(team, option, 0);
+
+ list_for_each_entry(port, &team->port_list, list) {
+ err = __team_option_inst_add(team, option, port);
+ if (err)
+ goto inst_del_option;
+ }
+ return 0;
+
+inst_del_option:
+ __team_option_inst_del_option(team, option);
+ return err;
+}
+
+static void __team_option_inst_mark_removed_option(struct team *team,
+ struct team_option *option)
+{
+ struct team_option_inst *opt_inst;
+
+ list_for_each_entry(opt_inst, &team->option_inst_list, list) {
+ if (opt_inst->option == option) {
+ opt_inst->changed = true;
+ opt_inst->removed = true;
+ }
+ }
+}
+
+static void __team_option_inst_del_port(struct team *team,
+ struct team_port *port)
+{
+ struct team_option_inst *opt_inst, *tmp;
+
+ list_for_each_entry_safe(opt_inst, tmp, &team->option_inst_list, list) {
+ if (opt_inst->option->per_port &&
+ opt_inst->port == port)
+ __team_option_inst_del(opt_inst);
+ }
+}
+
+static int __team_option_inst_add_port(struct team *team,
+ struct team_port *port)
+{
+ struct team_option *option;
+ int err;
+
+ list_for_each_entry(option, &team->option_list, list) {
+ if (!option->per_port)
+ continue;
+ err = __team_option_inst_add(team, option, port);
+ if (err)
+ goto inst_del_port;
+ }
+ return 0;
+
+inst_del_port:
+ __team_option_inst_del_port(team, port);
+ return err;
+}
+
+static void __team_option_inst_mark_removed_port(struct team *team,
+ struct team_port *port)
+{
+ struct team_option_inst *opt_inst;
+
+ list_for_each_entry(opt_inst, &team->option_inst_list, list) {
+ if (opt_inst->port == port) {
+ opt_inst->changed = true;
+ opt_inst->removed = true;
+ }
+ }
+}
+
+static int __team_options_register(struct team *team,
+ const struct team_option *option,
+ size_t option_count)
{
int i;
struct team_option **dst_opts;
@@ -107,26 +228,32 @@ int __team_options_register(struct team *team,
for (i = 0; i < option_count; i++, option++) {
if (__team_find_option(team, option->name)) {
err = -EEXIST;
- goto rollback;
+ goto alloc_rollback;
}
dst_opts[i] = kmemdup(option, sizeof(*option), GFP_KERNEL);
if (!dst_opts[i]) {
err = -ENOMEM;
- goto rollback;
+ goto alloc_rollback;
}
}
for (i = 0; i < option_count; i++) {
- dst_opts[i]->changed = true;
- dst_opts[i]->removed = false;
+ err = __team_option_inst_add_option(team, dst_opts[i]);
+ if (err)
+ goto inst_rollback;
list_add_tail(&dst_opts[i]->list, &team->option_list);
}
kfree(dst_opts);
return 0;
-rollback:
- for (i = 0; i < option_count; i++)
+inst_rollback:
+ for (i--; i >= 0; i--)
+ __team_option_inst_del_option(team, dst_opts[i]);
+
+ i = option_count - 1;
+alloc_rollback:
+ for (i--; i >= 0; i--)
kfree(dst_opts[i]);
kfree(dst_opts);
@@ -143,10 +270,8 @@ static void __team_options_mark_removed(struct team *team,
struct team_option *del_opt;
del_opt = __team_find_option(team, option->name);
- if (del_opt) {
- del_opt->changed = true;
- del_opt->removed = true;
- }
+ if (del_opt)
+ __team_option_inst_mark_removed_option(team, del_opt);
}
}
@@ -161,6 +286,7 @@ static void __team_options_unregister(struct team *team,
del_opt = __team_find_option(team, option->name);
if (del_opt) {
+ __team_option_inst_del_option(team, del_opt);
list_del(&del_opt->list);
kfree(del_opt);
}
@@ -193,22 +319,42 @@ void team_options_unregister(struct team *team,
}
EXPORT_SYMBOL(team_options_unregister);
-static int team_option_get(struct team *team, struct team_option *option,
- void *arg)
+static int team_option_port_add(struct team *team, struct team_port *port)
{
- return option->getter(team, arg);
+ int err;
+
+ err = __team_option_inst_add_port(team, port);
+ if (err)
+ return err;
+ __team_options_change_check(team);
+ return 0;
}
-static int team_option_set(struct team *team, struct team_option *option,
- void *arg)
+static void team_option_port_del(struct team *team, struct team_port *port)
+{
+ __team_option_inst_mark_removed_port(team, port);
+ __team_options_change_check(team);
+ __team_option_inst_del_port(team, port);
+}
+
+static int team_option_get(struct team *team,
+ struct team_option_inst *opt_inst,
+ struct team_gsetter_ctx *ctx)
+{
+ return opt_inst->option->getter(team, ctx);
+}
+
+static int team_option_set(struct team *team,
+ struct team_option_inst *opt_inst,
+ struct team_gsetter_ctx *ctx)
{
int err;
- err = option->setter(team, arg);
+ err = opt_inst->option->setter(team, ctx);
if (err)
return err;
- option->changed = true;
+ opt_inst->changed = true;
__team_options_change_check(team);
return err;
}
@@ -642,6 +788,13 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
goto err_handler_register;
}
+ err = team_option_port_add(team, port);
+ if (err) {
+ netdev_err(dev, "Device %s failed to add per-port options\n",
+ portname);
+ goto err_option_port_add;
+ }
+
team_port_list_add_port(team, port);
team_adjust_ops(team);
__team_compute_features(team);
@@ -651,6 +804,9 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
return 0;
+err_option_port_add:
+ netdev_rx_handler_unregister(port_dev);
+
err_handler_register:
netdev_set_master(port_dev, NULL);
@@ -690,6 +846,7 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
__team_port_change_check(port, false);
team_port_list_del_port(team, port);
team_adjust_ops(team);
+ team_option_port_del(team, port);
netdev_rx_handler_unregister(port_dev);
netdev_set_master(port_dev, NULL);
vlan_vids_del_by_dev(port_dev, dev);
@@ -712,19 +869,15 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
static const char team_no_mode_kind[] = "*NOMODE*";
-static int team_mode_option_get(struct team *team, void *arg)
+static int team_mode_option_get(struct team *team, struct team_gsetter_ctx *ctx)
{
- const char **str = arg;
-
- *str = team->mode ? team->mode->kind : team_no_mode_kind;
+ ctx->data.str_val = team->mode ? team->mode->kind : team_no_mode_kind;
return 0;
}
-static int team_mode_option_set(struct team *team, void *arg)
+static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx)
{
- const char **str = arg;
-
- return team_change_mode(team, *str);
+ return team_change_mode(team, ctx->data.str_val);
}
static const struct team_option team_options[] = {
@@ -756,6 +909,7 @@ static int team_init(struct net_device *dev)
team_adjust_ops(team);
INIT_LIST_HEAD(&team->option_list);
+ INIT_LIST_HEAD(&team->option_inst_list);
err = team_options_register(team, team_options, ARRAY_SIZE(team_options));
if (err)
goto err_options_register;
@@ -1238,7 +1392,8 @@ static int team_nl_fill_options_get(struct sk_buff *skb,
{
struct nlattr *option_list;
void *hdr;
- struct team_option *option;
+ struct team_option_inst *opt_inst;
+ int err;
hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
TEAM_CMD_OPTIONS_GET);
@@ -1251,50 +1406,61 @@ static int team_nl_fill_options_get(struct sk_buff *skb,
if (!option_list)
return -EMSGSIZE;
- list_for_each_entry(option, &team->option_list, list) {
+ list_for_each_entry(opt_inst, &team->option_inst_list, list) {
struct nlattr *option_item;
- long arg;
- struct team_option_binary tbinary;
+ struct team_option *option = opt_inst->option;
+ struct team_gsetter_ctx ctx;
/* Include only changed options if fill all mode is not on */
- if (!fillall && !option->changed)
+ if (!fillall && !opt_inst->changed)
continue;
option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION);
if (!option_item)
goto nla_put_failure;
if (nla_put_string(skb, TEAM_ATTR_OPTION_NAME, option->name))
goto nla_put_failure;
- if (option->changed) {
+ if (opt_inst->changed) {
if (nla_put_flag(skb, TEAM_ATTR_OPTION_CHANGED))
goto nla_put_failure;
- option->changed = false;
+ opt_inst->changed = false;
}
- if (option->removed &&
+ if (opt_inst->removed &&
nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED))
goto nla_put_failure;
+ if (opt_inst->port &&
+ nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX,
+ opt_inst->port->dev->ifindex))
+ goto nla_put_failure;
+ ctx.port = opt_inst->port;
switch (option->type) {
case TEAM_OPTION_TYPE_U32:
if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32))
goto nla_put_failure;
- team_option_get(team, option, &arg);
- if (nla_put_u32(skb, TEAM_ATTR_OPTION_DATA, arg))
+ err = team_option_get(team, opt_inst, &ctx);
+ if (err)
+ goto errout;
+ if (nla_put_u32(skb, TEAM_ATTR_OPTION_DATA,
+ ctx.data.u32_val))
goto nla_put_failure;
break;
case TEAM_OPTION_TYPE_STRING:
if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING))
goto nla_put_failure;
- team_option_get(team, option, &arg);
+ err = team_option_get(team, opt_inst, &ctx);
+ if (err)
+ goto errout;
if (nla_put_string(skb, TEAM_ATTR_OPTION_DATA,
- (char *) arg))
+ ctx.data.str_val))
goto nla_put_failure;
break;
case TEAM_OPTION_TYPE_BINARY:
if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_BINARY))
goto nla_put_failure;
- arg = (long) &tbinary;
- team_option_get(team, option, &arg);
+ err = team_option_get(team, opt_inst, &ctx);
+ if (err)
+ goto errout;
if (nla_put(skb, TEAM_ATTR_OPTION_DATA,
- tbinary.data_len, tbinary.data))
+ ctx.data.bin_val.len, ctx.data.bin_val.ptr))
goto nla_put_failure;
break;
default:
@@ -1307,8 +1473,10 @@ static int team_nl_fill_options_get(struct sk_buff *skb,
return genlmsg_end(skb, hdr);
nla_put_failure:
+ err = -EMSGSIZE;
+errout:
genlmsg_cancel(skb, hdr);
- return -EMSGSIZE;
+ return err;
}
static int team_nl_fill_options_get_all(struct sk_buff *skb,
@@ -1354,9 +1522,11 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
}
nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) {
- struct nlattr *mode_attrs[TEAM_ATTR_OPTION_MAX + 1];
+ struct nlattr *opt_attrs[TEAM_ATTR_OPTION_MAX + 1];
+ struct nlattr *attr_port_ifindex;
enum team_option_type opt_type;
- struct team_option *option;
+ int opt_port_ifindex = 0; /* != 0 for per-port options */
+ struct team_option_inst *opt_inst;
char *opt_name;
bool opt_found = false;
@@ -1364,17 +1534,17 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
err = -EINVAL;
goto team_put;
}
- err = nla_parse_nested(mode_attrs, TEAM_ATTR_OPTION_MAX,
+ err = nla_parse_nested(opt_attrs, TEAM_ATTR_OPTION_MAX,
nl_option, team_nl_option_policy);
if (err)
goto team_put;
- if (!mode_attrs[TEAM_ATTR_OPTION_NAME] ||
- !mode_attrs[TEAM_ATTR_OPTION_TYPE] ||
- !mode_attrs[TEAM_ATTR_OPTION_DATA]) {
+ if (!opt_attrs[TEAM_ATTR_OPTION_NAME] ||
+ !opt_attrs[TEAM_ATTR_OPTION_TYPE] ||
+ !opt_attrs[TEAM_ATTR_OPTION_DATA]) {
err = -EINVAL;
goto team_put;
}
- switch (nla_get_u8(mode_attrs[TEAM_ATTR_OPTION_TYPE])) {
+ switch (nla_get_u8(opt_attrs[TEAM_ATTR_OPTION_TYPE])) {
case NLA_U32:
opt_type = TEAM_OPTION_TYPE_U32;
break;
@@ -1388,39 +1558,47 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
goto team_put;
}
- opt_name = nla_data(mode_attrs[TEAM_ATTR_OPTION_NAME]);
- list_for_each_entry(option, &team->option_list, list) {
- long arg;
+ opt_name = nla_data(opt_attrs[TEAM_ATTR_OPTION_NAME]);
+ attr_port_ifindex = opt_attrs[TEAM_ATTR_OPTION_PORT_IFINDEX];
+ if (attr_port_ifindex)
+ opt_port_ifindex = nla_get_u32(attr_port_ifindex);
+
+ list_for_each_entry(opt_inst, &team->option_inst_list, list) {
+ struct team_option *option = opt_inst->option;
struct nlattr *opt_data_attr;
- struct team_option_binary tbinary;
+ struct team_gsetter_ctx ctx;
int data_len;
+ int tmp_ifindex;
+ tmp_ifindex = opt_inst->port ?
+ opt_inst->port->dev->ifindex : 0;
if (option->type != opt_type ||
- strcmp(option->name, opt_name))
+ strcmp(option->name, opt_name) ||
+ tmp_ifindex != opt_port_ifindex)
continue;
opt_found = true;
- opt_data_attr = mode_attrs[TEAM_ATTR_OPTION_DATA];
+ opt_data_attr = opt_attrs[TEAM_ATTR_OPTION_DATA];
data_len = nla_len(opt_data_attr);
+ ctx.port = opt_inst->port;
switch (opt_type) {
case TEAM_OPTION_TYPE_U32:
- arg = nla_get_u32(opt_data_attr);
+ ctx.data.u32_val = nla_get_u32(opt_data_attr);
break;
case TEAM_OPTION_TYPE_STRING:
if (data_len > TEAM_STRING_MAX_LEN) {
err = -EINVAL;
goto team_put;
}
- arg = (long) nla_data(opt_data_attr);
+ ctx.data.str_val = nla_data(opt_data_attr);
break;
case TEAM_OPTION_TYPE_BINARY:
- tbinary.data_len = data_len;
- tbinary.data = nla_data(opt_data_attr);
- arg = (long) &tbinary;
+ ctx.data.bin_val.len = data_len;
+ ctx.data.bin_val.ptr = nla_data(opt_data_attr);
break;
default:
BUG();
}
- err = team_option_set(team, option, &arg);
+ err = team_option_set(team, opt_inst, &ctx);
if (err)
goto team_put;
}
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
index f4d960e..6cde1ab 100644
--- a/drivers/net/team/team_mode_activebackup.c
+++ b/drivers/net/team/team_mode_activebackup.c
@@ -59,23 +59,21 @@ static void ab_port_leave(struct team *team, struct team_port *port)
RCU_INIT_POINTER(ab_priv(team)->active_port, NULL);
}
-static int ab_active_port_get(struct team *team, void *arg)
+static int ab_active_port_get(struct team *team, struct team_gsetter_ctx *ctx)
{
- u32 *ifindex = arg;
-
- *ifindex = 0;
if (ab_priv(team)->active_port)
- *ifindex = ab_priv(team)->active_port->dev->ifindex;
+ ctx->data.u32_val = ab_priv(team)->active_port->dev->ifindex;
+ else
+ ctx->data.u32_val = 0;
return 0;
}
-static int ab_active_port_set(struct team *team, void *arg)
+static int ab_active_port_set(struct team *team, struct team_gsetter_ctx *ctx)
{
- u32 *ifindex = arg;
struct team_port *port;
list_for_each_entry_rcu(port, &team->port_list, list) {
- if (port->dev->ifindex == *ifindex) {
+ if (port->dev->ifindex == ctx->data.u32_val) {
rcu_assign_pointer(ab_priv(team)->active_port, port);
return 0;
}
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index ed20f39..167cdb4 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -52,22 +52,21 @@ drop:
return false;
}
-static int lb_bpf_func_get(struct team *team, void *arg)
+static int lb_bpf_func_get(struct team *team, struct team_gsetter_ctx *ctx)
{
- struct team_option_binary *tbinary = team_optarg_tbinary(arg);
-
- memset(tbinary, 0, sizeof(*tbinary));
- if (!lb_priv(team)->orig_fprog)
+ if (!lb_priv(team)->orig_fprog) {
+ ctx->data.bin_val.len = 0;
+ ctx->data.bin_val.ptr = NULL;
return 0;
-
- tbinary->data_len = lb_priv(team)->orig_fprog->len *
- sizeof(struct sock_filter);
- tbinary->data = lb_priv(team)->orig_fprog->filter;
+ }
+ ctx->data.bin_val.len = lb_priv(team)->orig_fprog->len *
+ sizeof(struct sock_filter);
+ ctx->data.bin_val.ptr = lb_priv(team)->orig_fprog->filter;
return 0;
}
static int __fprog_create(struct sock_fprog **pfprog, u32 data_len,
- void *data)
+ const void *data)
{
struct sock_fprog *fprog;
struct sock_filter *filter = (struct sock_filter *) data;
@@ -93,16 +92,15 @@ static void __fprog_destroy(struct sock_fprog *fprog)
kfree(fprog);
}
-static int lb_bpf_func_set(struct team *team, void *arg)
+static int lb_bpf_func_set(struct team *team, struct team_gsetter_ctx *ctx)
{
- struct team_option_binary *tbinary = team_optarg_tbinary(arg);
struct sk_filter *fp = NULL;
struct sock_fprog *fprog = NULL;
int err;
- if (tbinary->data_len) {
- err = __fprog_create(&fprog, tbinary->data_len,
- tbinary->data);
+ if (ctx->data.bin_val.len) {
+ err = __fprog_create(&fprog, ctx->data.bin_val.len,
+ ctx->data.bin_val.ptr);
if (err)
return err;
err = sk_unattached_filter_create(&fp, fprog);
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index 41163ac..6f27c84 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -71,25 +71,27 @@ enum team_option_type {
TEAM_OPTION_TYPE_BINARY,
};
+struct team_gsetter_ctx {
+ union {
+ u32 u32_val;
+ const char *str_val;
+ struct {
+ const void *ptr;
+ u32 len;
+ } bin_val;
+ } data;
+ struct team_port *port;
+};
+
struct team_option {
struct list_head list;
const char *name;
+ bool per_port;
enum team_option_type type;
- int (*getter)(struct team *team, void *arg);
- int (*setter)(struct team *team, void *arg);
-
- /* Custom gennetlink interface related flags */
- bool changed;
- bool removed;
+ int (*getter)(struct team *team, struct team_gsetter_ctx *ctx);
+ int (*setter)(struct team *team, struct team_gsetter_ctx *ctx);
};
-struct team_option_binary {
- u32 data_len;
- void *data;
-};
-
-#define team_optarg_tbinary(arg) (*((struct team_option_binary **) arg))
-
struct team_mode {
struct list_head list;
const char *kind;
@@ -118,6 +120,7 @@ struct team {
struct list_head port_list;
struct list_head option_list;
+ struct list_head option_inst_list; /* list of option instances */
const struct team_mode *mode;
struct team_mode_ops ops;
@@ -224,6 +227,7 @@ enum {
TEAM_ATTR_OPTION_TYPE, /* u8 */
TEAM_ATTR_OPTION_DATA, /* dynamic */
TEAM_ATTR_OPTION_REMOVED, /* flag */
+ TEAM_ATTR_OPTION_PORT_IFINDEX, /* u32 */ /* for per-port options */
__TEAM_ATTR_OPTION_MAX,
TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1,
--
1.7.9.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [patch net-next 2/5] team: add bool option type
2012-04-10 15:15 [patch net-next 0/5] team: add some features and fixes Jiri Pirko
2012-04-10 15:15 ` [patch net-next 1/5] team: add support for per-port options Jiri Pirko
@ 2012-04-10 15:15 ` Jiri Pirko
2012-04-10 15:15 ` [patch net-next 3/5] team: add user_linkup and user_linkup_enabled per-port option Jiri Pirko
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Jiri Pirko @ 2012-04-10 15:15 UTC (permalink / raw)
To: netdev; +Cc: davem, eric.dumazet
Add another (hopefully last) option type. Use NLA_FLAG to implement
that.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/team/team.c | 40 +++++++++++++++++++++++++++++-----------
include/linux/if_team.h | 2 ++
2 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index eaf8441..2645fae 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1463,6 +1463,16 @@ static int team_nl_fill_options_get(struct sk_buff *skb,
ctx.data.bin_val.len, ctx.data.bin_val.ptr))
goto nla_put_failure;
break;
+ case TEAM_OPTION_TYPE_BOOL:
+ if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_FLAG))
+ goto nla_put_failure;
+ err = team_option_get(team, opt_inst, &ctx);
+ if (err)
+ goto errout;
+ if (ctx.data.bool_val &&
+ nla_put_flag(skb, TEAM_ATTR_OPTION_DATA))
+ goto nla_put_failure;
+ break;
default:
BUG();
}
@@ -1524,6 +1534,7 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) {
struct nlattr *opt_attrs[TEAM_ATTR_OPTION_MAX + 1];
struct nlattr *attr_port_ifindex;
+ struct nlattr *attr_data;
enum team_option_type opt_type;
int opt_port_ifindex = 0; /* != 0 for per-port options */
struct team_option_inst *opt_inst;
@@ -1539,8 +1550,7 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
if (err)
goto team_put;
if (!opt_attrs[TEAM_ATTR_OPTION_NAME] ||
- !opt_attrs[TEAM_ATTR_OPTION_TYPE] ||
- !opt_attrs[TEAM_ATTR_OPTION_DATA]) {
+ !opt_attrs[TEAM_ATTR_OPTION_TYPE]) {
err = -EINVAL;
goto team_put;
}
@@ -1554,10 +1564,19 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
case NLA_BINARY:
opt_type = TEAM_OPTION_TYPE_BINARY;
break;
+ case NLA_FLAG:
+ opt_type = TEAM_OPTION_TYPE_BOOL;
+ break;
default:
goto team_put;
}
+ attr_data = opt_attrs[TEAM_ATTR_OPTION_DATA];
+ if (opt_type != TEAM_OPTION_TYPE_BOOL && !attr_data) {
+ err = -EINVAL;
+ goto team_put;
+ }
+
opt_name = nla_data(opt_attrs[TEAM_ATTR_OPTION_NAME]);
attr_port_ifindex = opt_attrs[TEAM_ATTR_OPTION_PORT_IFINDEX];
if (attr_port_ifindex)
@@ -1565,9 +1584,7 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
list_for_each_entry(opt_inst, &team->option_inst_list, list) {
struct team_option *option = opt_inst->option;
- struct nlattr *opt_data_attr;
struct team_gsetter_ctx ctx;
- int data_len;
int tmp_ifindex;
tmp_ifindex = opt_inst->port ?
@@ -1577,23 +1594,24 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
tmp_ifindex != opt_port_ifindex)
continue;
opt_found = true;
- opt_data_attr = opt_attrs[TEAM_ATTR_OPTION_DATA];
- data_len = nla_len(opt_data_attr);
ctx.port = opt_inst->port;
switch (opt_type) {
case TEAM_OPTION_TYPE_U32:
- ctx.data.u32_val = nla_get_u32(opt_data_attr);
+ ctx.data.u32_val = nla_get_u32(attr_data);
break;
case TEAM_OPTION_TYPE_STRING:
- if (data_len > TEAM_STRING_MAX_LEN) {
+ if (nla_len(attr_data) > TEAM_STRING_MAX_LEN) {
err = -EINVAL;
goto team_put;
}
- ctx.data.str_val = nla_data(opt_data_attr);
+ ctx.data.str_val = nla_data(attr_data);
break;
case TEAM_OPTION_TYPE_BINARY:
- ctx.data.bin_val.len = data_len;
- ctx.data.bin_val.ptr = nla_data(opt_data_attr);
+ ctx.data.bin_val.len = nla_len(attr_data);
+ ctx.data.bin_val.ptr = nla_data(attr_data);
+ break;
+ case TEAM_OPTION_TYPE_BOOL:
+ ctx.data.bool_val = attr_data ? true : false;
break;
default:
BUG();
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index 6f27c84..78c84fd 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -69,6 +69,7 @@ enum team_option_type {
TEAM_OPTION_TYPE_U32,
TEAM_OPTION_TYPE_STRING,
TEAM_OPTION_TYPE_BINARY,
+ TEAM_OPTION_TYPE_BOOL,
};
struct team_gsetter_ctx {
@@ -79,6 +80,7 @@ struct team_gsetter_ctx {
const void *ptr;
u32 len;
} bin_val;
+ bool bool_val;
} data;
struct team_port *port;
};
--
1.7.9.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [patch net-next 3/5] team: add user_linkup and user_linkup_enabled per-port option
2012-04-10 15:15 [patch net-next 0/5] team: add some features and fixes Jiri Pirko
2012-04-10 15:15 ` [patch net-next 1/5] team: add support for per-port options Jiri Pirko
2012-04-10 15:15 ` [patch net-next 2/5] team: add bool option type Jiri Pirko
@ 2012-04-10 15:15 ` Jiri Pirko
2012-04-10 15:15 ` [patch net-next 4/5] team: ab: walk through port list non-rcu Jiri Pirko
2012-04-10 15:15 ` [patch net-next 5/5] team: add missed "statics" Jiri Pirko
4 siblings, 0 replies; 9+ messages in thread
From: Jiri Pirko @ 2012-04-10 15:15 UTC (permalink / raw)
To: netdev; +Cc: davem, eric.dumazet
Allows userspace to setup linkup for ports. Default is to take linkup
directly from ethtool state.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/team/team.c | 72 +++++++++++++++++++++++++++++++++++++++++------
include/linux/if_team.h | 26 ++++++++++++-----
2 files changed, 81 insertions(+), 17 deletions(-)
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 2645fae..e639abe 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -76,6 +76,11 @@ int team_port_set_team_mac(struct team_port *port)
}
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
@@ -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);
}
+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[] = {
{
.name = "mode",
@@ -887,6 +926,20 @@ static const struct team_option team_options[] = {
.getter = team_mode_option_get,
.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)
@@ -1670,10 +1723,10 @@ static int team_nl_fill_port_list_get(struct sk_buff *skb,
}
if ((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_u32(skb, TEAM_ATTR_PORT_SPEED, port->speed) ||
- nla_put_u8(skb, TEAM_ATTR_PORT_DUPLEX, port->duplex))
+ nla_put_u32(skb, TEAM_ATTR_PORT_SPEED, port->state.speed) ||
+ nla_put_u8(skb, TEAM_ATTR_PORT_DUPLEX, port->state.duplex))
goto nla_put_failure;
nla_nest_end(skb, port_item);
}
@@ -1833,23 +1886,24 @@ static void __team_port_change_check(struct team_port *port, bool linkup)
{
int err;
- if (!port->removed && port->linkup == linkup)
+ if (!port->removed && port->state.linkup == linkup)
return;
port->changed = true;
- port->linkup = linkup;
+ port->state.linkup = linkup;
+ team_refresh_port_linkup(port);
if (linkup) {
struct ethtool_cmd ecmd;
err = __ethtool_get_settings(port->dev, &ecmd);
if (!err) {
- port->speed = ethtool_cmd_speed(&ecmd);
- port->duplex = ecmd.duplex;
+ port->state.speed = ethtool_cmd_speed(&ecmd);
+ port->state.duplex = ecmd.duplex;
goto send_event;
}
}
- port->speed = 0;
- port->duplex = 0;
+ port->state.speed = 0;
+ port->state.duplex = 0;
send_event:
err = team_nl_send_event_port_list_get(port->team);
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index 78c84fd..5fd5ab1 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -33,6 +33,24 @@ struct team_port {
struct team *team;
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
* become a port.
@@ -42,14 +60,6 @@ struct team_port {
unsigned int mtu;
} orig;
- bool linkup;
- u32 speed;
- u8 duplex;
-
- /* Custom gennetlink interface related flags */
- bool changed;
- bool removed;
-
struct rcu_head rcu;
};
--
1.7.9.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [patch net-next 4/5] team: ab: walk through port list non-rcu
2012-04-10 15:15 [patch net-next 0/5] team: add some features and fixes Jiri Pirko
` (2 preceding siblings ...)
2012-04-10 15:15 ` [patch net-next 3/5] team: add user_linkup and user_linkup_enabled per-port option Jiri Pirko
@ 2012-04-10 15:15 ` Jiri Pirko
2012-04-10 15:15 ` [patch net-next 5/5] team: add missed "statics" Jiri Pirko
4 siblings, 0 replies; 9+ messages in thread
From: Jiri Pirko @ 2012-04-10 15:15 UTC (permalink / raw)
To: netdev; +Cc: davem, eric.dumazet
Since team->lock is being held, _rcu variant make no sense.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/team/team_mode_activebackup.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
index 6cde1ab..a715c40 100644
--- a/drivers/net/team/team_mode_activebackup.c
+++ b/drivers/net/team/team_mode_activebackup.c
@@ -72,7 +72,7 @@ static int ab_active_port_set(struct team *team, struct team_gsetter_ctx *ctx)
{
struct team_port *port;
- list_for_each_entry_rcu(port, &team->port_list, list) {
+ list_for_each_entry(port, &team->port_list, list) {
if (port->dev->ifindex == ctx->data.u32_val) {
rcu_assign_pointer(ab_priv(team)->active_port, port);
return 0;
--
1.7.9.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [patch net-next 5/5] team: add missed "statics"
2012-04-10 15:15 [patch net-next 0/5] team: add some features and fixes Jiri Pirko
` (3 preceding siblings ...)
2012-04-10 15:15 ` [patch net-next 4/5] team: ab: walk through port list non-rcu Jiri Pirko
@ 2012-04-10 15:15 ` Jiri Pirko
4 siblings, 0 replies; 9+ messages in thread
From: Jiri Pirko @ 2012-04-10 15:15 UTC (permalink / raw)
To: netdev; +Cc: davem, eric.dumazet
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/team/team.c | 2 +-
drivers/net/team/team_mode_activebackup.c | 4 ++--
drivers/net/team/team_mode_loadbalance.c | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index e639abe..153a62d 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -65,7 +65,7 @@ static int __set_port_mac(struct net_device *port_dev,
return dev_set_mac_address(port_dev, &addr);
}
-int team_port_set_orig_mac(struct team_port *port)
+static int team_port_set_orig_mac(struct team_port *port)
{
return __set_port_mac(port->dev, port->orig.dev_addr);
}
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
index a715c40..fd6bd03 100644
--- a/drivers/net/team/team_mode_activebackup.c
+++ b/drivers/net/team/team_mode_activebackup.c
@@ -90,12 +90,12 @@ static const struct team_option ab_options[] = {
},
};
-int ab_init(struct team *team)
+static int ab_init(struct team *team)
{
return team_options_register(team, ab_options, ARRAY_SIZE(ab_options));
}
-void ab_exit(struct team *team)
+static void ab_exit(struct team *team)
{
team_options_unregister(team, ab_options, ARRAY_SIZE(ab_options));
}
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index 167cdb4..2b506b2 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -130,13 +130,13 @@ static const struct team_option lb_options[] = {
},
};
-int lb_init(struct team *team)
+static int lb_init(struct team *team)
{
return team_options_register(team, lb_options,
ARRAY_SIZE(lb_options));
}
-void lb_exit(struct team *team)
+static void lb_exit(struct team *team)
{
team_options_unregister(team, lb_options,
ARRAY_SIZE(lb_options));
--
1.7.9.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [patch net-next 1/5] team: add support for per-port options
2012-04-10 15:15 ` [patch net-next 1/5] team: add support for per-port options Jiri Pirko
@ 2012-04-10 18:33 ` David Miller
2012-04-11 5:43 ` Jiri Pirko
0 siblings, 1 reply; 9+ messages in thread
From: David Miller @ 2012-04-10 18:33 UTC (permalink / raw)
To: jpirko; +Cc: netdev, eric.dumazet
From: Jiri Pirko <jpirko@redhat.com>
Date: Tue, 10 Apr 2012 17:15:42 +0200
> @@ -81,7 +81,16 @@ EXPORT_SYMBOL(team_port_set_team_mac);
> * Options handling
> *******************/
>
> -struct team_option *__team_find_option(struct team *team, const char *opt_name)
> +struct team_option_inst { /* One for each option instance */
> + struct list_head list;
> + struct team_option *option;
> + struct team_port *port; /* != NULL if per-port */
> + bool changed;
> + bool removed;
> +};
> +
All this indirection... just simply embed struct team_option into
struct team_option_inst instead of using a pointer, and allocate a
full team_option_inst where you currently memdup in the options.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch net-next 1/5] team: add support for per-port options
2012-04-10 18:33 ` David Miller
@ 2012-04-11 5:43 ` Jiri Pirko
2012-04-11 13:58 ` David Miller
0 siblings, 1 reply; 9+ messages in thread
From: Jiri Pirko @ 2012-04-11 5:43 UTC (permalink / raw)
To: David Miller; +Cc: netdev, eric.dumazet
Tue, Apr 10, 2012 at 08:33:56PM CEST, davem@davemloft.net wrote:
>From: Jiri Pirko <jpirko@redhat.com>
>Date: Tue, 10 Apr 2012 17:15:42 +0200
>
>> @@ -81,7 +81,16 @@ EXPORT_SYMBOL(team_port_set_team_mac);
>> * Options handling
>> *******************/
>>
>> -struct team_option *__team_find_option(struct team *team, const char *opt_name)
>> +struct team_option_inst { /* One for each option instance */
>> + struct list_head list;
>> + struct team_option *option;
>> + struct team_port *port; /* != NULL if per-port */
>> + bool changed;
>> + bool removed;
>> +};
>> +
>
>All this indirection... just simply embed struct team_option into
>struct team_option_inst instead of using a pointer, and allocate a
>full team_option_inst where you currently memdup in the options.
Well the list of options is needed alone. When port is added/removed, this list
gets iterated over and instances are created/deleted. Therefore I put
pointer to option to option instance struct to save memory (and also to
be nicer)
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch net-next 1/5] team: add support for per-port options
2012-04-11 5:43 ` Jiri Pirko
@ 2012-04-11 13:58 ` David Miller
0 siblings, 0 replies; 9+ messages in thread
From: David Miller @ 2012-04-11 13:58 UTC (permalink / raw)
To: jpirko; +Cc: netdev, eric.dumazet
From: Jiri Pirko <jpirko@redhat.com>
Date: Wed, 11 Apr 2012 07:43:51 +0200
> Tue, Apr 10, 2012 at 08:33:56PM CEST, davem@davemloft.net wrote:
>>From: Jiri Pirko <jpirko@redhat.com>
>>Date: Tue, 10 Apr 2012 17:15:42 +0200
>>
>>> @@ -81,7 +81,16 @@ EXPORT_SYMBOL(team_port_set_team_mac);
>>> * Options handling
>>> *******************/
>>>
>>> -struct team_option *__team_find_option(struct team *team, const char *opt_name)
>>> +struct team_option_inst { /* One for each option instance */
>>> + struct list_head list;
>>> + struct team_option *option;
>>> + struct team_port *port; /* != NULL if per-port */
>>> + bool changed;
>>> + bool removed;
>>> +};
>>> +
>>
>>All this indirection... just simply embed struct team_option into
>>struct team_option_inst instead of using a pointer, and allocate a
>>full team_option_inst where you currently memdup in the options.
>
> Well the list of options is needed alone. When port is added/removed, this list
> gets iterated over and instances are created/deleted. Therefore I put
> pointer to option to option instance struct to save memory (and also to
> be nicer)
Fair enough, I'll apply this series, thanks.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2012-04-11 13:58 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-04-10 15:15 [patch net-next 0/5] team: add some features and fixes Jiri Pirko
2012-04-10 15:15 ` [patch net-next 1/5] team: add support for per-port options Jiri Pirko
2012-04-10 18:33 ` David Miller
2012-04-11 5:43 ` Jiri Pirko
2012-04-11 13:58 ` David Miller
2012-04-10 15:15 ` [patch net-next 2/5] team: add bool option type Jiri Pirko
2012-04-10 15:15 ` [patch net-next 3/5] team: add user_linkup and user_linkup_enabled per-port option Jiri Pirko
2012-04-10 15:15 ` [patch net-next 4/5] team: ab: walk through port list non-rcu Jiri Pirko
2012-04-10 15:15 ` [patch net-next 5/5] team: add missed "statics" Jiri Pirko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).