diff options
-rw-r--r-- | drivers/net/team/team.c | 68 | ||||
-rw-r--r-- | include/linux/if_team.h | 9 |
2 files changed, 50 insertions, 27 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 7ec53f81c1c..cff8e253df7 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c | |||
@@ -89,8 +89,7 @@ static void team_refresh_port_linkup(struct team_port *port) | |||
89 | struct team_option_inst { /* One for each option instance */ | 89 | 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_option_inst_info info; |
93 | u32 array_index; | ||
94 | bool changed; | 93 | bool changed; |
95 | bool removed; | 94 | bool removed; |
96 | }; | 95 | }; |
@@ -130,6 +129,7 @@ static int __team_option_inst_add(struct team *team, struct team_option *option, | |||
130 | struct team_option_inst *opt_inst; | 129 | struct team_option_inst *opt_inst; |
131 | unsigned int array_size; | 130 | unsigned int array_size; |
132 | unsigned int i; | 131 | unsigned int i; |
132 | int err; | ||
133 | 133 | ||
134 | array_size = option->array_size; | 134 | array_size = option->array_size; |
135 | if (!array_size) | 135 | if (!array_size) |
@@ -140,11 +140,17 @@ static int __team_option_inst_add(struct team *team, struct team_option *option, | |||
140 | if (!opt_inst) | 140 | if (!opt_inst) |
141 | return -ENOMEM; | 141 | return -ENOMEM; |
142 | opt_inst->option = option; | 142 | opt_inst->option = option; |
143 | opt_inst->port = port; | 143 | opt_inst->info.port = port; |
144 | opt_inst->array_index = i; | 144 | opt_inst->info.array_index = i; |
145 | opt_inst->changed = true; | 145 | opt_inst->changed = true; |
146 | opt_inst->removed = false; | 146 | opt_inst->removed = false; |
147 | list_add_tail(&opt_inst->list, &team->option_inst_list); | 147 | list_add_tail(&opt_inst->list, &team->option_inst_list); |
148 | if (option->init) { | ||
149 | err = option->init(team, &opt_inst->info); | ||
150 | if (err) | ||
151 | return err; | ||
152 | } | ||
153 | |||
148 | } | 154 | } |
149 | return 0; | 155 | return 0; |
150 | } | 156 | } |
@@ -193,7 +199,7 @@ static void __team_option_inst_del_port(struct team *team, | |||
193 | 199 | ||
194 | list_for_each_entry_safe(opt_inst, tmp, &team->option_inst_list, list) { | 200 | list_for_each_entry_safe(opt_inst, tmp, &team->option_inst_list, list) { |
195 | if (opt_inst->option->per_port && | 201 | if (opt_inst->option->per_port && |
196 | opt_inst->port == port) | 202 | opt_inst->info.port == port) |
197 | __team_option_inst_del(opt_inst); | 203 | __team_option_inst_del(opt_inst); |
198 | } | 204 | } |
199 | } | 205 | } |
@@ -224,7 +230,7 @@ static void __team_option_inst_mark_removed_port(struct team *team, | |||
224 | struct team_option_inst *opt_inst; | 230 | struct team_option_inst *opt_inst; |
225 | 231 | ||
226 | list_for_each_entry(opt_inst, &team->option_inst_list, list) { | 232 | list_for_each_entry(opt_inst, &team->option_inst_list, list) { |
227 | if (opt_inst->port == port) { | 233 | if (opt_inst->info.port == port) { |
228 | opt_inst->changed = true; | 234 | opt_inst->changed = true; |
229 | opt_inst->removed = true; | 235 | opt_inst->removed = true; |
230 | } | 236 | } |
@@ -958,39 +964,47 @@ static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx) | |||
958 | static int team_port_en_option_get(struct team *team, | 964 | static int team_port_en_option_get(struct team *team, |
959 | struct team_gsetter_ctx *ctx) | 965 | struct team_gsetter_ctx *ctx) |
960 | { | 966 | { |
961 | ctx->data.bool_val = team_port_enabled(ctx->port); | 967 | struct team_port *port = ctx->info->port; |
968 | |||
969 | ctx->data.bool_val = team_port_enabled(port); | ||
962 | return 0; | 970 | return 0; |
963 | } | 971 | } |
964 | 972 | ||
965 | static int team_port_en_option_set(struct team *team, | 973 | static int team_port_en_option_set(struct team *team, |
966 | struct team_gsetter_ctx *ctx) | 974 | struct team_gsetter_ctx *ctx) |
967 | { | 975 | { |
976 | struct team_port *port = ctx->info->port; | ||
977 | |||
968 | if (ctx->data.bool_val) | 978 | if (ctx->data.bool_val) |
969 | team_port_enable(team, ctx->port); | 979 | team_port_enable(team, port); |
970 | else | 980 | else |
971 | team_port_disable(team, ctx->port); | 981 | team_port_disable(team, port); |
972 | return 0; | 982 | return 0; |
973 | } | 983 | } |
974 | 984 | ||
975 | static int team_user_linkup_option_get(struct team *team, | 985 | static int team_user_linkup_option_get(struct team *team, |
976 | struct team_gsetter_ctx *ctx) | 986 | struct team_gsetter_ctx *ctx) |
977 | { | 987 | { |
978 | ctx->data.bool_val = ctx->port->user.linkup; | 988 | struct team_port *port = ctx->info->port; |
989 | |||
990 | ctx->data.bool_val = port->user.linkup; | ||
979 | return 0; | 991 | return 0; |
980 | } | 992 | } |
981 | 993 | ||
982 | static int team_user_linkup_option_set(struct team *team, | 994 | static int team_user_linkup_option_set(struct team *team, |
983 | struct team_gsetter_ctx *ctx) | 995 | struct team_gsetter_ctx *ctx) |
984 | { | 996 | { |
985 | ctx->port->user.linkup = ctx->data.bool_val; | 997 | struct team_port *port = ctx->info->port; |
986 | team_refresh_port_linkup(ctx->port); | 998 | |
999 | port->user.linkup = ctx->data.bool_val; | ||
1000 | team_refresh_port_linkup(port); | ||
987 | return 0; | 1001 | return 0; |
988 | } | 1002 | } |
989 | 1003 | ||
990 | static int team_user_linkup_en_option_get(struct team *team, | 1004 | static int team_user_linkup_en_option_get(struct team *team, |
991 | struct team_gsetter_ctx *ctx) | 1005 | struct team_gsetter_ctx *ctx) |
992 | { | 1006 | { |
993 | struct team_port *port = ctx->port; | 1007 | struct team_port *port = ctx->info->port; |
994 | 1008 | ||
995 | ctx->data.bool_val = port->user.linkup_enabled; | 1009 | ctx->data.bool_val = port->user.linkup_enabled; |
996 | return 0; | 1010 | return 0; |
@@ -999,10 +1013,10 @@ static int team_user_linkup_en_option_get(struct team *team, | |||
999 | static int team_user_linkup_en_option_set(struct team *team, | 1013 | static int team_user_linkup_en_option_set(struct team *team, |
1000 | struct team_gsetter_ctx *ctx) | 1014 | struct team_gsetter_ctx *ctx) |
1001 | { | 1015 | { |
1002 | struct team_port *port = ctx->port; | 1016 | struct team_port *port = ctx->info->port; |
1003 | 1017 | ||
1004 | port->user.linkup_enabled = ctx->data.bool_val; | 1018 | port->user.linkup_enabled = ctx->data.bool_val; |
1005 | team_refresh_port_linkup(ctx->port); | 1019 | team_refresh_port_linkup(port); |
1006 | return 0; | 1020 | return 0; |
1007 | } | 1021 | } |
1008 | 1022 | ||
@@ -1557,6 +1571,7 @@ static int team_nl_fill_options_get(struct sk_buff *skb, | |||
1557 | list_for_each_entry(opt_inst, &team->option_inst_list, list) { | 1571 | list_for_each_entry(opt_inst, &team->option_inst_list, list) { |
1558 | struct nlattr *option_item; | 1572 | struct nlattr *option_item; |
1559 | struct team_option *option = opt_inst->option; | 1573 | struct team_option *option = opt_inst->option; |
1574 | struct team_option_inst_info *opt_inst_info; | ||
1560 | struct team_gsetter_ctx ctx; | 1575 | struct team_gsetter_ctx ctx; |
1561 | 1576 | ||
1562 | /* Include only changed options if fill all mode is not on */ | 1577 | /* Include only changed options if fill all mode is not on */ |
@@ -1575,16 +1590,18 @@ static int team_nl_fill_options_get(struct sk_buff *skb, | |||
1575 | if (opt_inst->removed && | 1590 | if (opt_inst->removed && |
1576 | nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED)) | 1591 | nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED)) |
1577 | goto nla_put_failure; | 1592 | goto nla_put_failure; |
1578 | if (opt_inst->port && | 1593 | |
1594 | opt_inst_info = &opt_inst->info; | ||
1595 | if (opt_inst_info->port && | ||
1579 | nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX, | 1596 | nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX, |
1580 | opt_inst->port->dev->ifindex)) | 1597 | opt_inst_info->port->dev->ifindex)) |
1581 | goto nla_put_failure; | 1598 | goto nla_put_failure; |
1582 | ctx.port = opt_inst->port; | ||
1583 | if (opt_inst->option->array_size && | 1599 | if (opt_inst->option->array_size && |
1584 | nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX, | 1600 | nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX, |
1585 | opt_inst->array_index)) | 1601 | opt_inst_info->array_index)) |
1586 | goto nla_put_failure; | 1602 | goto nla_put_failure; |
1587 | ctx.array_index = opt_inst->array_index; | 1603 | ctx.info = opt_inst_info; |
1604 | |||
1588 | switch (option->type) { | 1605 | switch (option->type) { |
1589 | case TEAM_OPTION_TYPE_U32: | 1606 | case TEAM_OPTION_TYPE_U32: |
1590 | if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32)) | 1607 | if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32)) |
@@ -1746,19 +1763,20 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) | |||
1746 | list_for_each_entry(opt_inst, &team->option_inst_list, list) { | 1763 | list_for_each_entry(opt_inst, &team->option_inst_list, list) { |
1747 | struct team_option *option = opt_inst->option; | 1764 | struct team_option *option = opt_inst->option; |
1748 | struct team_gsetter_ctx ctx; | 1765 | struct team_gsetter_ctx ctx; |
1766 | struct team_option_inst_info *opt_inst_info; | ||
1749 | int tmp_ifindex; | 1767 | int tmp_ifindex; |
1750 | 1768 | ||
1751 | tmp_ifindex = opt_inst->port ? | 1769 | opt_inst_info = &opt_inst->info; |
1752 | opt_inst->port->dev->ifindex : 0; | 1770 | tmp_ifindex = opt_inst_info->port ? |
1771 | opt_inst_info->port->dev->ifindex : 0; | ||
1753 | if (option->type != opt_type || | 1772 | if (option->type != opt_type || |
1754 | strcmp(option->name, opt_name) || | 1773 | strcmp(option->name, opt_name) || |
1755 | tmp_ifindex != opt_port_ifindex || | 1774 | tmp_ifindex != opt_port_ifindex || |
1756 | (option->array_size && !opt_is_array) || | 1775 | (option->array_size && !opt_is_array) || |
1757 | opt_inst->array_index != opt_array_index) | 1776 | opt_inst_info->array_index != opt_array_index) |
1758 | continue; | 1777 | continue; |
1759 | opt_found = true; | 1778 | opt_found = true; |
1760 | ctx.port = opt_inst->port; | 1779 | ctx.info = opt_inst_info; |
1761 | ctx.array_index = opt_inst->array_index; | ||
1762 | switch (opt_type) { | 1780 | switch (opt_type) { |
1763 | case TEAM_OPTION_TYPE_U32: | 1781 | case TEAM_OPTION_TYPE_U32: |
1764 | ctx.data.u32_val = nla_get_u32(attr_data); | 1782 | ctx.data.u32_val = nla_get_u32(attr_data); |
diff --git a/include/linux/if_team.h b/include/linux/if_team.h index b1719e239a0..30854cb0c85 100644 --- a/include/linux/if_team.h +++ b/include/linux/if_team.h | |||
@@ -83,6 +83,11 @@ enum team_option_type { | |||
83 | TEAM_OPTION_TYPE_BOOL, | 83 | TEAM_OPTION_TYPE_BOOL, |
84 | }; | 84 | }; |
85 | 85 | ||
86 | struct team_option_inst_info { | ||
87 | u32 array_index; | ||
88 | struct team_port *port; /* != NULL if per-port */ | ||
89 | }; | ||
90 | |||
86 | struct team_gsetter_ctx { | 91 | struct team_gsetter_ctx { |
87 | union { | 92 | union { |
88 | u32 u32_val; | 93 | u32 u32_val; |
@@ -93,8 +98,7 @@ struct team_gsetter_ctx { | |||
93 | } bin_val; | 98 | } bin_val; |
94 | bool bool_val; | 99 | bool bool_val; |
95 | } data; | 100 | } data; |
96 | u32 array_index; | 101 | struct team_option_inst_info *info; |
97 | struct team_port *port; | ||
98 | }; | 102 | }; |
99 | 103 | ||
100 | struct team_option { | 104 | struct team_option { |
@@ -103,6 +107,7 @@ struct team_option { | |||
103 | bool per_port; | 107 | bool per_port; |
104 | unsigned int array_size; /* != 0 means the option is array */ | 108 | unsigned int array_size; /* != 0 means the option is array */ |
105 | enum team_option_type type; | 109 | enum team_option_type type; |
110 | int (*init)(struct team *team, struct team_option_inst_info *info); | ||
106 | int (*getter)(struct team *team, struct team_gsetter_ctx *ctx); | 111 | int (*getter)(struct team *team, struct team_gsetter_ctx *ctx); |
107 | int (*setter)(struct team *team, struct team_gsetter_ctx *ctx); | 112 | int (*setter)(struct team *team, struct team_gsetter_ctx *ctx); |
108 | }; | 113 | }; |