Skip to content

Commit

Permalink
team: allow to specify one option instance to be send to userspace
Browse files Browse the repository at this point in the history
No need to walk through option instance list and look for ->changed ==
true when called knows exactly what one option instance changed.

Also use lists to pass option instances needed to be present in netlink
message.

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 3221c64 commit 01048d9
Showing 1 changed file with 124 additions and 86 deletions.
210 changes: 124 additions & 86 deletions drivers/net/team/team.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ static void team_refresh_port_linkup(struct team_port *port)

struct team_option_inst { /* One for each option instance */
struct list_head list;
struct list_head tmp_list;
struct team_option *option;
struct team_option_inst_info info;
bool changed;
Expand Down Expand Up @@ -319,6 +320,8 @@ static void __team_options_unregister(struct team *team,
}

static void __team_options_change_check(struct team *team);
static void __team_option_inst_change(struct team *team,
struct team_option_inst *opt_inst);

int team_options_register(struct team *team,
const struct team_option *option,
Expand Down Expand Up @@ -383,8 +386,7 @@ static int team_option_set(struct team *team,
if (err)
return err;

opt_inst->changed = true;
__team_options_change_check(team);
__team_option_inst_change(team, opt_inst);
return err;
}

Expand Down Expand Up @@ -1565,9 +1567,95 @@ static int team_nl_send_generic(struct genl_info *info, struct team *team,
return err;
}

static int team_nl_fill_one_option_get(struct sk_buff *skb, struct team *team,
struct team_option_inst *opt_inst)
{
struct nlattr *option_item;
struct team_option *option = opt_inst->option;
struct team_option_inst_info *opt_inst_info;
struct team_gsetter_ctx ctx;
int err;

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 (opt_inst->changed) {
if (nla_put_flag(skb, TEAM_ATTR_OPTION_CHANGED))
goto nla_put_failure;
opt_inst->changed = false;
}
if (opt_inst->removed && nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED))
goto nla_put_failure;

opt_inst_info = &opt_inst->info;
if (opt_inst_info->port &&
nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX,
opt_inst_info->port->dev->ifindex))
goto nla_put_failure;
if (opt_inst->option->array_size &&
nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX,
opt_inst_info->array_index))
goto nla_put_failure;
ctx.info = opt_inst_info;

switch (option->type) {
case TEAM_OPTION_TYPE_U32:
if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32))
goto nla_put_failure;
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;
err = team_option_get(team, opt_inst, &ctx);
if (err)
goto errout;
if (nla_put_string(skb, TEAM_ATTR_OPTION_DATA,
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;
err = team_option_get(team, opt_inst, &ctx);
if (err)
goto errout;
if (nla_put(skb, TEAM_ATTR_OPTION_DATA, 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();
}
nla_nest_end(skb, option_item);
return 0;

nla_put_failure:
err = -EMSGSIZE;
errout:
return err;
}

static int team_nl_fill_options_get(struct sk_buff *skb,
u32 pid, u32 seq, int flags,
struct team *team, bool fillall)
struct team *team,
struct list_head *sel_opt_inst_list)
{
struct nlattr *option_list;
void *hdr;
Expand All @@ -1585,85 +1673,10 @@ static int team_nl_fill_options_get(struct sk_buff *skb,
if (!option_list)
goto nla_put_failure;

list_for_each_entry(opt_inst, &team->option_inst_list, list) {
struct nlattr *option_item;
struct team_option *option = opt_inst->option;
struct team_option_inst_info *opt_inst_info;
struct team_gsetter_ctx ctx;

/* Include only changed options if fill all mode is not on */
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 (opt_inst->changed) {
if (nla_put_flag(skb, TEAM_ATTR_OPTION_CHANGED))
goto nla_put_failure;
opt_inst->changed = false;
}
if (opt_inst->removed &&
nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED))
goto nla_put_failure;

opt_inst_info = &opt_inst->info;
if (opt_inst_info->port &&
nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX,
opt_inst_info->port->dev->ifindex))
goto nla_put_failure;
if (opt_inst->option->array_size &&
nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX,
opt_inst_info->array_index))
goto nla_put_failure;
ctx.info = opt_inst_info;

switch (option->type) {
case TEAM_OPTION_TYPE_U32:
if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32))
goto nla_put_failure;
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;
err = team_option_get(team, opt_inst, &ctx);
if (err)
goto errout;
if (nla_put_string(skb, TEAM_ATTR_OPTION_DATA,
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;
err = team_option_get(team, opt_inst, &ctx);
if (err)
goto errout;
if (nla_put(skb, TEAM_ATTR_OPTION_DATA,
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();
}
nla_nest_end(skb, option_item);
list_for_each_entry(opt_inst, sel_opt_inst_list, tmp_list) {
err = team_nl_fill_one_option_get(skb, team, opt_inst);
if (err)
goto errout;
}

nla_nest_end(skb, option_list);
Expand All @@ -1680,9 +1693,14 @@ static int team_nl_fill_options_get_all(struct sk_buff *skb,
struct genl_info *info, int flags,
struct team *team)
{
struct team_option_inst *opt_inst;
LIST_HEAD(sel_opt_inst_list);

list_for_each_entry(opt_inst, &team->option_inst_list, list)
list_add_tail(&opt_inst->tmp_list, &sel_opt_inst_list);
return team_nl_fill_options_get(skb, info->snd_pid,
info->snd_seq, NLM_F_ACK,
team, true);
team, &sel_opt_inst_list);
}

static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info)
Expand Down Expand Up @@ -1941,7 +1959,8 @@ static struct genl_multicast_group team_change_event_mcgrp = {
.name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME,
};

static int team_nl_send_event_options_get(struct team *team)
static int team_nl_send_event_options_get(struct team *team,
struct list_head *sel_opt_inst_list)
{
struct sk_buff *skb;
int err;
Expand All @@ -1951,7 +1970,7 @@ static int team_nl_send_event_options_get(struct team *team)
if (!skb)
return -ENOMEM;

err = team_nl_fill_options_get(skb, 0, 0, 0, team, false);
err = team_nl_fill_options_get(skb, 0, 0, 0, team, sel_opt_inst_list);
if (err < 0)
goto err_fill;

Expand Down Expand Up @@ -2021,12 +2040,31 @@ static void team_nl_fini(void)
static void __team_options_change_check(struct team *team)
{
int err;
struct team_option_inst *opt_inst;
LIST_HEAD(sel_opt_inst_list);

err = team_nl_send_event_options_get(team);
list_for_each_entry(opt_inst, &team->option_inst_list, list) {
if (opt_inst->changed)
list_add_tail(&opt_inst->tmp_list, &sel_opt_inst_list);
}
err = team_nl_send_event_options_get(team, &sel_opt_inst_list);
if (err)
netdev_warn(team->dev, "Failed to send options change via netlink\n");
}

static void __team_option_inst_change(struct team *team,
struct team_option_inst *sel_opt_inst)
{
int err;
LIST_HEAD(sel_opt_inst_list);

sel_opt_inst->changed = true;
list_add(&sel_opt_inst->tmp_list, &sel_opt_inst_list);
err = team_nl_send_event_options_get(team, &sel_opt_inst_list);
if (err)
netdev_warn(team->dev, "Failed to send option change via netlink\n");
}

/* rtnl lock is held */
static void __team_port_change_check(struct team_port *port, bool linkup)
{
Expand Down

0 comments on commit 01048d9

Please sign in to comment.