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 */
struct list_head list;
struct team_option *option;
struct team_port *port; /* != NULL if per-port */
u32 array_index;
bool changed;
bool removed;
};
......@@ -106,22 +107,6 @@ static struct team_option *__team_find_option(struct team *team,
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)
{
list_del(&opt_inst->list);
......@@ -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,
struct team_option *option)
{
struct team_port *port;
int err;
if (!option->per_port)
return __team_option_inst_add(team, option, 0);
if (!option->per_port) {
err = __team_option_inst_add(team, option, 0);
if (err)
goto inst_del_option;
}
list_for_each_entry(port, &team->port_list, list) {
err = __team_option_inst_add(team, option, port);
......@@ -1567,6 +1580,11 @@ static int team_nl_fill_options_get(struct sk_buff *skb,
opt_inst->port->dev->ifindex))
goto nla_put_failure;
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) {
case TEAM_OPTION_TYPE_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)
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;
struct nlattr *attr_data;
enum team_option_type opt_type;
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;
char *opt_name;
bool opt_found = false;
......@@ -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]);
attr_port_ifindex = opt_attrs[TEAM_ATTR_OPTION_PORT_IFINDEX];
if (attr_port_ifindex)
opt_port_ifindex = nla_get_u32(attr_port_ifindex);
attr = opt_attrs[TEAM_ATTR_OPTION_PORT_IFINDEX];
if (attr)
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) {
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)
opt_inst->port->dev->ifindex : 0;
if (option->type != opt_type ||
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;
opt_found = true;
ctx.port = opt_inst->port;
ctx.array_index = opt_inst->array_index;
switch (opt_type) {
case TEAM_OPTION_TYPE_U32:
ctx.data.u32_val = nla_get_u32(attr_data);
......
......@@ -93,6 +93,7 @@ struct team_gsetter_ctx {
} bin_val;
bool bool_val;
} data;
u32 array_index;
struct team_port *port;
};
......@@ -100,6 +101,7 @@ struct team_option {
struct list_head list;
const char *name;
bool per_port;
unsigned int array_size; /* != 0 means the option is array */
enum team_option_type type;
int (*getter)(struct team *team, struct team_gsetter_ctx *ctx);
int (*setter)(struct team *team, struct team_gsetter_ctx *ctx);
......@@ -242,6 +244,7 @@ enum {
TEAM_ATTR_OPTION_DATA, /* dynamic */
TEAM_ATTR_OPTION_REMOVED, /* flag */
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 - 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