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

team: introduce array options

Signed-off-by: default avatarJiri Pirko <jpirko@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f82b959d
...@@ -90,6 +90,7 @@ struct team_option_inst { /* One for each option instance */ ...@@ -90,6 +90,7 @@ struct team_option_inst { /* One for each option instance */
struct list_head list; struct list_head list;
struct team_option *option; struct team_option *option;
struct team_port *port; /* != NULL if per-port */ struct team_port *port; /* != NULL if per-port */
u32 array_index;
bool changed; bool changed;
bool removed; bool removed;
}; };
...@@ -106,22 +107,6 @@ static struct team_option *__team_find_option(struct team *team, ...@@ -106,22 +107,6 @@ static struct team_option *__team_find_option(struct team *team,
return NULL; return NULL;
} }
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) static void __team_option_inst_del(struct team_option_inst *opt_inst)
{ {
list_del(&opt_inst->list); list_del(&opt_inst->list);
...@@ -139,14 +124,42 @@ static void __team_option_inst_del_option(struct team *team, ...@@ -139,14 +124,42 @@ static void __team_option_inst_del_option(struct team *team,
} }
} }
static int __team_option_inst_add(struct team *team, struct team_option *option,
struct team_port *port)
{
struct team_option_inst *opt_inst;
unsigned int array_size;
unsigned int i;
array_size = option->array_size;
if (!array_size)
array_size = 1; /* No array but still need one instance */
for (i = 0; i < array_size; i++) {
opt_inst = kmalloc(sizeof(*opt_inst), GFP_KERNEL);
if (!opt_inst)
return -ENOMEM;
opt_inst->option = option;
opt_inst->port = port;
opt_inst->array_index = i;
opt_inst->changed = true;
opt_inst->removed = false;
list_add_tail(&opt_inst->list, &team->option_inst_list);
}
return 0;
}
static int __team_option_inst_add_option(struct team *team, static int __team_option_inst_add_option(struct team *team,
struct team_option *option) struct team_option *option)
{ {
struct team_port *port; struct team_port *port;
int err; int err;
if (!option->per_port) if (!option->per_port) {
return __team_option_inst_add(team, option, 0); err = __team_option_inst_add(team, option, 0);
if (err)
goto inst_del_option;
}
list_for_each_entry(port, &team->port_list, list) { list_for_each_entry(port, &team->port_list, list) {
err = __team_option_inst_add(team, option, port); err = __team_option_inst_add(team, option, port);
...@@ -1567,6 +1580,11 @@ static int team_nl_fill_options_get(struct sk_buff *skb, ...@@ -1567,6 +1580,11 @@ static int team_nl_fill_options_get(struct sk_buff *skb,
opt_inst->port->dev->ifindex)) opt_inst->port->dev->ifindex))
goto nla_put_failure; goto nla_put_failure;
ctx.port = opt_inst->port; ctx.port = opt_inst->port;
if (opt_inst->option->array_size &&
nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX,
opt_inst->array_index))
goto nla_put_failure;
ctx.array_index = opt_inst->array_index;
switch (option->type) { switch (option->type) {
case TEAM_OPTION_TYPE_U32: case TEAM_OPTION_TYPE_U32:
if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32)) if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32))
...@@ -1668,10 +1686,12 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) ...@@ -1668,10 +1686,12 @@ 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) { nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) {
struct nlattr *opt_attrs[TEAM_ATTR_OPTION_MAX + 1]; struct nlattr *opt_attrs[TEAM_ATTR_OPTION_MAX + 1];
struct nlattr *attr_port_ifindex; struct nlattr *attr;
struct nlattr *attr_data; struct nlattr *attr_data;
enum team_option_type opt_type; enum team_option_type opt_type;
int opt_port_ifindex = 0; /* != 0 for per-port options */ int opt_port_ifindex = 0; /* != 0 for per-port options */
u32 opt_array_index = 0;
bool opt_is_array = false;
struct team_option_inst *opt_inst; struct team_option_inst *opt_inst;
char *opt_name; char *opt_name;
bool opt_found = false; bool opt_found = false;
...@@ -1713,9 +1733,15 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) ...@@ -1713,9 +1733,15 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
} }
opt_name = nla_data(opt_attrs[TEAM_ATTR_OPTION_NAME]); opt_name = nla_data(opt_attrs[TEAM_ATTR_OPTION_NAME]);
attr_port_ifindex = opt_attrs[TEAM_ATTR_OPTION_PORT_IFINDEX]; attr = opt_attrs[TEAM_ATTR_OPTION_PORT_IFINDEX];
if (attr_port_ifindex) if (attr)
opt_port_ifindex = nla_get_u32(attr_port_ifindex); opt_port_ifindex = nla_get_u32(attr);
attr = opt_attrs[TEAM_ATTR_OPTION_ARRAY_INDEX];
if (attr) {
opt_is_array = true;
opt_array_index = nla_get_u32(attr);
}
list_for_each_entry(opt_inst, &team->option_inst_list, list) { list_for_each_entry(opt_inst, &team->option_inst_list, list) {
struct team_option *option = opt_inst->option; struct team_option *option = opt_inst->option;
...@@ -1726,10 +1752,13 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) ...@@ -1726,10 +1752,13 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
opt_inst->port->dev->ifindex : 0; opt_inst->port->dev->ifindex : 0;
if (option->type != opt_type || if (option->type != opt_type ||
strcmp(option->name, opt_name) || strcmp(option->name, opt_name) ||
tmp_ifindex != opt_port_ifindex) tmp_ifindex != opt_port_ifindex ||
(option->array_size && !opt_is_array) ||
opt_inst->array_index != opt_array_index)
continue; continue;
opt_found = true; opt_found = true;
ctx.port = opt_inst->port; ctx.port = opt_inst->port;
ctx.array_index = opt_inst->array_index;
switch (opt_type) { switch (opt_type) {
case TEAM_OPTION_TYPE_U32: case TEAM_OPTION_TYPE_U32:
ctx.data.u32_val = nla_get_u32(attr_data); ctx.data.u32_val = nla_get_u32(attr_data);
......
...@@ -93,6 +93,7 @@ struct team_gsetter_ctx { ...@@ -93,6 +93,7 @@ struct team_gsetter_ctx {
} bin_val; } bin_val;
bool bool_val; bool bool_val;
} data; } data;
u32 array_index;
struct team_port *port; struct team_port *port;
}; };
...@@ -100,6 +101,7 @@ struct team_option { ...@@ -100,6 +101,7 @@ struct team_option {
struct list_head list; struct list_head list;
const char *name; const char *name;
bool per_port; bool per_port;
unsigned int array_size; /* != 0 means the option is array */
enum team_option_type type; enum team_option_type type;
int (*getter)(struct team *team, struct team_gsetter_ctx *ctx); int (*getter)(struct team *team, struct team_gsetter_ctx *ctx);
int (*setter)(struct team *team, struct team_gsetter_ctx *ctx); int (*setter)(struct team *team, struct team_gsetter_ctx *ctx);
...@@ -242,6 +244,7 @@ enum { ...@@ -242,6 +244,7 @@ enum {
TEAM_ATTR_OPTION_DATA, /* dynamic */ TEAM_ATTR_OPTION_DATA, /* dynamic */
TEAM_ATTR_OPTION_REMOVED, /* flag */ TEAM_ATTR_OPTION_REMOVED, /* flag */
TEAM_ATTR_OPTION_PORT_IFINDEX, /* u32 */ /* for per-port options */ TEAM_ATTR_OPTION_PORT_IFINDEX, /* u32 */ /* for per-port options */
TEAM_ATTR_OPTION_ARRAY_INDEX, /* u32 */ /* for array options */
__TEAM_ATTR_OPTION_MAX, __TEAM_ATTR_OPTION_MAX,
TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1, TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1,
......
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