netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).