team: introduce array options
authorJiri Pirko <jpirko@redhat.com>
Tue, 19 Jun 2012 05:54:08 +0000 (05:54 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 19 Jun 2012 22:00:23 +0000 (15:00 -0700)
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/team/team.c
include/linux/if_team.h

index f50b8ca8dc949d63a53cabf6b872c3713314bff1..32cb290fb8008377c42a4dd8dde6874cd2d3fcac 100644 (file)
@@ -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);
index 54af95f5d58b7903eb8832a57a8bc82a410c4aad..b1719e239a0b5b450637988cf5a02addd5190848 100644 (file)
@@ -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,