Skip to content

Commit

Permalink
team: introduce array options
Browse files Browse the repository at this point in the history
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jiri Pirko authored and David S. Miller committed Jun 19, 2012
1 parent f82b959 commit b130332
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 23 deletions.
75 changes: 52 additions & 23 deletions drivers/net/team/team.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions include/linux/if_team.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,15 @@ struct team_gsetter_ctx {
} bin_val;
bool bool_val;
} data;
u32 array_index;
struct team_port *port;
};

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);
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit b130332

Please sign in to comment.