diff options
author | Jiri Pirko <jpirko@redhat.com> | 2012-06-19 01:54:08 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-06-19 18:00:23 -0400 |
commit | b13033262d2496e271444d5a09226a2be5ceb989 (patch) | |
tree | c5a78a0023f3c28425e7425a91c6fd2ac71d29d9 /drivers | |
parent | f82b959d26557fe4ce283d3b27050d4b8268ef1e (diff) |
team: introduce array options
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/team/team.c | 75 |
1 files changed, 52 insertions, 23 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index f50b8ca8dc94..32cb290fb800 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c | |||
@@ -90,6 +90,7 @@ struct team_option_inst { /* One for each option instance */ | |||
90 | struct list_head list; | 90 | struct list_head list; |
91 | struct team_option *option; | 91 | struct team_option *option; |
92 | struct team_port *port; /* != NULL if per-port */ | 92 | struct team_port *port; /* != NULL if per-port */ |
93 | u32 array_index; | ||
93 | bool changed; | 94 | bool changed; |
94 | bool removed; | 95 | bool removed; |
95 | }; | 96 | }; |
@@ -106,22 +107,6 @@ static struct team_option *__team_find_option(struct team *team, | |||
106 | return NULL; | 107 | return NULL; |
107 | } | 108 | } |
108 | 109 | ||
109 | static int __team_option_inst_add(struct team *team, struct team_option *option, | ||
110 | struct team_port *port) | ||
111 | { | ||
112 | struct team_option_inst *opt_inst; | ||
113 | |||
114 | opt_inst = kmalloc(sizeof(*opt_inst), GFP_KERNEL); | ||
115 | if (!opt_inst) | ||
116 | return -ENOMEM; | ||
117 | opt_inst->option = option; | ||
118 | opt_inst->port = port; | ||
119 | opt_inst->changed = true; | ||
120 | opt_inst->removed = false; | ||
121 | list_add_tail(&opt_inst->list, &team->option_inst_list); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static void __team_option_inst_del(struct team_option_inst *opt_inst) | 110 | static void __team_option_inst_del(struct team_option_inst *opt_inst) |
126 | { | 111 | { |
127 | list_del(&opt_inst->list); | 112 | list_del(&opt_inst->list); |
@@ -139,14 +124,42 @@ static void __team_option_inst_del_option(struct team *team, | |||
139 | } | 124 | } |
140 | } | 125 | } |
141 | 126 | ||
127 | static int __team_option_inst_add(struct team *team, struct team_option *option, | ||
128 | struct team_port *port) | ||
129 | { | ||
130 | struct team_option_inst *opt_inst; | ||
131 | unsigned int array_size; | ||
132 | unsigned int i; | ||
133 | |||
134 | array_size = option->array_size; | ||
135 | if (!array_size) | ||
136 | array_size = 1; /* No array but still need one instance */ | ||
137 | |||
138 | for (i = 0; i < array_size; i++) { | ||
139 | opt_inst = kmalloc(sizeof(*opt_inst), GFP_KERNEL); | ||
140 | if (!opt_inst) | ||
141 | return -ENOMEM; | ||
142 | opt_inst->option = option; | ||
143 | opt_inst->port = port; | ||
144 | opt_inst->array_index = i; | ||
145 | opt_inst->changed = true; | ||
146 | opt_inst->removed = false; | ||
147 | list_add_tail(&opt_inst->list, &team->option_inst_list); | ||
148 | } | ||
149 | return 0; | ||
150 | } | ||
151 | |||
142 | static int __team_option_inst_add_option(struct team *team, | 152 | static int __team_option_inst_add_option(struct team *team, |
143 | struct team_option *option) | 153 | struct team_option *option) |
144 | { | 154 | { |
145 | struct team_port *port; | 155 | struct team_port *port; |
146 | int err; | 156 | int err; |
147 | 157 | ||
148 | if (!option->per_port) | 158 | if (!option->per_port) { |
149 | return __team_option_inst_add(team, option, 0); | 159 | err = __team_option_inst_add(team, option, 0); |
160 | if (err) | ||
161 | goto inst_del_option; | ||
162 | } | ||
150 | 163 | ||
151 | list_for_each_entry(port, &team->port_list, list) { | 164 | list_for_each_entry(port, &team->port_list, list) { |
152 | err = __team_option_inst_add(team, option, port); | 165 | err = __team_option_inst_add(team, option, port); |
@@ -1567,6 +1580,11 @@ static int team_nl_fill_options_get(struct sk_buff *skb, | |||
1567 | opt_inst->port->dev->ifindex)) | 1580 | opt_inst->port->dev->ifindex)) |
1568 | goto nla_put_failure; | 1581 | goto nla_put_failure; |
1569 | ctx.port = opt_inst->port; | 1582 | ctx.port = opt_inst->port; |
1583 | if (opt_inst->option->array_size && | ||
1584 | nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX, | ||
1585 | opt_inst->array_index)) | ||
1586 | goto nla_put_failure; | ||
1587 | ctx.array_index = opt_inst->array_index; | ||
1570 | switch (option->type) { | 1588 | switch (option->type) { |
1571 | case TEAM_OPTION_TYPE_U32: | 1589 | case TEAM_OPTION_TYPE_U32: |
1572 | if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32)) | 1590 | 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 | 1686 | ||
1669 | nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) { | 1687 | nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) { |
1670 | struct nlattr *opt_attrs[TEAM_ATTR_OPTION_MAX + 1]; | 1688 | struct nlattr *opt_attrs[TEAM_ATTR_OPTION_MAX + 1]; |
1671 | struct nlattr *attr_port_ifindex; | 1689 | struct nlattr *attr; |
1672 | struct nlattr *attr_data; | 1690 | struct nlattr *attr_data; |
1673 | enum team_option_type opt_type; | 1691 | enum team_option_type opt_type; |
1674 | int opt_port_ifindex = 0; /* != 0 for per-port options */ | 1692 | int opt_port_ifindex = 0; /* != 0 for per-port options */ |
1693 | u32 opt_array_index = 0; | ||
1694 | bool opt_is_array = false; | ||
1675 | struct team_option_inst *opt_inst; | 1695 | struct team_option_inst *opt_inst; |
1676 | char *opt_name; | 1696 | char *opt_name; |
1677 | bool opt_found = false; | 1697 | bool opt_found = false; |
@@ -1713,9 +1733,15 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) | |||
1713 | } | 1733 | } |
1714 | 1734 | ||
1715 | opt_name = nla_data(opt_attrs[TEAM_ATTR_OPTION_NAME]); | 1735 | opt_name = nla_data(opt_attrs[TEAM_ATTR_OPTION_NAME]); |
1716 | attr_port_ifindex = opt_attrs[TEAM_ATTR_OPTION_PORT_IFINDEX]; | 1736 | attr = opt_attrs[TEAM_ATTR_OPTION_PORT_IFINDEX]; |
1717 | if (attr_port_ifindex) | 1737 | if (attr) |
1718 | opt_port_ifindex = nla_get_u32(attr_port_ifindex); | 1738 | opt_port_ifindex = nla_get_u32(attr); |
1739 | |||
1740 | attr = opt_attrs[TEAM_ATTR_OPTION_ARRAY_INDEX]; | ||
1741 | if (attr) { | ||
1742 | opt_is_array = true; | ||
1743 | opt_array_index = nla_get_u32(attr); | ||
1744 | } | ||
1719 | 1745 | ||
1720 | list_for_each_entry(opt_inst, &team->option_inst_list, list) { | 1746 | list_for_each_entry(opt_inst, &team->option_inst_list, list) { |
1721 | struct team_option *option = opt_inst->option; | 1747 | 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 | opt_inst->port->dev->ifindex : 0; | 1752 | opt_inst->port->dev->ifindex : 0; |
1727 | if (option->type != opt_type || | 1753 | if (option->type != opt_type || |
1728 | strcmp(option->name, opt_name) || | 1754 | strcmp(option->name, opt_name) || |
1729 | tmp_ifindex != opt_port_ifindex) | 1755 | tmp_ifindex != opt_port_ifindex || |
1756 | (option->array_size && !opt_is_array) || | ||
1757 | opt_inst->array_index != opt_array_index) | ||
1730 | continue; | 1758 | continue; |
1731 | opt_found = true; | 1759 | opt_found = true; |
1732 | ctx.port = opt_inst->port; | 1760 | ctx.port = opt_inst->port; |
1761 | ctx.array_index = opt_inst->array_index; | ||
1733 | switch (opt_type) { | 1762 | switch (opt_type) { |
1734 | case TEAM_OPTION_TYPE_U32: | 1763 | case TEAM_OPTION_TYPE_U32: |
1735 | ctx.data.u32_val = nla_get_u32(attr_data); | 1764 | ctx.data.u32_val = nla_get_u32(attr_data); |