]>
Commit | Line | Data |
---|---|---|
230ead01 AS |
1 | /* |
2 | * drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c | |
3 | * Copyright (c) 2017 Mellanox Technologies. All rights reserved. | |
4 | * Copyright (c) 2017 Arkadi Sharshevsky <arakdis@mellanox.com> | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions are met: | |
8 | * | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. Neither the names of the copyright holders nor the names of its | |
15 | * contributors may be used to endorse or promote products derived from | |
16 | * this software without specific prior written permission. | |
17 | * | |
18 | * Alternatively, this software may be distributed under the terms of the | |
19 | * GNU General Public License ("GPL") version 2 as published by the Free | |
20 | * Software Foundation. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
32 | * POSSIBILITY OF SUCH DAMAGE. | |
33 | */ | |
34 | ||
35 | #include <linux/kernel.h> | |
36 | #include <net/devlink.h> | |
37 | ||
38 | #include "spectrum.h" | |
39 | #include "spectrum_dpipe.h" | |
2ba5999f | 40 | #include "spectrum_router.h" |
230ead01 | 41 | |
d54b70fe AS |
42 | enum mlxsw_sp_field_metadata_id { |
43 | MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT, | |
44 | MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD, | |
45 | MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP, | |
46 | }; | |
47 | ||
48 | static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = { | |
49 | { .name = "erif_port", | |
50 | .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT, | |
51 | .bitwidth = 32, | |
52 | .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX, | |
53 | }, | |
54 | { .name = "l3_forward", | |
55 | .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD, | |
56 | .bitwidth = 1, | |
57 | }, | |
58 | { .name = "l3_drop", | |
59 | .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP, | |
60 | .bitwidth = 1, | |
61 | }, | |
62 | }; | |
63 | ||
64 | enum mlxsw_sp_dpipe_header_id { | |
65 | MLXSW_SP_DPIPE_HEADER_METADATA, | |
66 | }; | |
67 | ||
68 | static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = { | |
69 | .name = "mlxsw_meta", | |
70 | .id = MLXSW_SP_DPIPE_HEADER_METADATA, | |
71 | .fields = mlxsw_sp_dpipe_fields_metadata, | |
72 | .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata), | |
73 | }; | |
74 | ||
75 | static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = { | |
76 | &mlxsw_sp_dpipe_header_metadata, | |
77 | }; | |
230ead01 AS |
78 | |
79 | static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = { | |
80 | .headers = mlxsw_dpipe_headers, | |
81 | .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers), | |
82 | }; | |
83 | ||
d54b70fe AS |
84 | static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv, |
85 | struct sk_buff *skb) | |
86 | { | |
87 | struct devlink_dpipe_action action = {0}; | |
88 | int err; | |
89 | ||
90 | action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; | |
91 | action.header = &mlxsw_sp_dpipe_header_metadata; | |
92 | action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD; | |
93 | ||
94 | err = devlink_dpipe_action_put(skb, &action); | |
95 | if (err) | |
96 | return err; | |
97 | ||
98 | action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; | |
99 | action.header = &mlxsw_sp_dpipe_header_metadata; | |
100 | action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP; | |
101 | ||
102 | return devlink_dpipe_action_put(skb, &action); | |
103 | } | |
104 | ||
105 | static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv, | |
106 | struct sk_buff *skb) | |
107 | { | |
108 | struct devlink_dpipe_match match = {0}; | |
109 | ||
110 | match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; | |
111 | match.header = &mlxsw_sp_dpipe_header_metadata; | |
112 | match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; | |
113 | ||
114 | return devlink_dpipe_match_put(skb, &match); | |
115 | } | |
116 | ||
2ba5999f AS |
117 | static void mlxsw_sp_erif_entry_clear(struct devlink_dpipe_entry *entry) |
118 | { | |
119 | unsigned int value_count, value_index; | |
120 | struct devlink_dpipe_value *value; | |
121 | ||
122 | value = entry->action_values; | |
123 | value_count = entry->action_values_count; | |
124 | for (value_index = 0; value_index < value_count; value_index++) { | |
125 | kfree(value[value_index].value); | |
126 | kfree(value[value_index].mask); | |
127 | } | |
128 | ||
129 | value = entry->match_values; | |
130 | value_count = entry->match_values_count; | |
131 | for (value_index = 0; value_index < value_count; value_index++) { | |
132 | kfree(value[value_index].value); | |
133 | kfree(value[value_index].mask); | |
134 | } | |
135 | } | |
136 | ||
137 | static void | |
138 | mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match, | |
139 | struct devlink_dpipe_action *action) | |
140 | { | |
141 | action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; | |
142 | action->header = &mlxsw_sp_dpipe_header_metadata; | |
143 | action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD; | |
144 | ||
145 | match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; | |
146 | match->header = &mlxsw_sp_dpipe_header_metadata; | |
147 | match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; | |
148 | } | |
149 | ||
150 | static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry, | |
151 | struct devlink_dpipe_value *match_value, | |
152 | struct devlink_dpipe_match *match, | |
153 | struct devlink_dpipe_value *action_value, | |
154 | struct devlink_dpipe_action *action) | |
155 | { | |
156 | entry->match_values = match_value; | |
157 | entry->match_values_count = 1; | |
158 | ||
159 | entry->action_values = action_value; | |
160 | entry->action_values_count = 1; | |
161 | ||
162 | match_value->match = match; | |
163 | match_value->value_size = sizeof(u32); | |
164 | match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); | |
165 | if (!match_value->value) | |
166 | return -ENOMEM; | |
167 | ||
168 | action_value->action = action; | |
169 | action_value->value_size = sizeof(u32); | |
170 | action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); | |
171 | if (!action_value->value) | |
172 | goto err_action_alloc; | |
173 | return 0; | |
174 | ||
175 | err_action_alloc: | |
176 | kfree(match_value->value); | |
177 | return -ENOMEM; | |
178 | } | |
179 | ||
180 | static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp, | |
181 | struct devlink_dpipe_entry *entry, | |
182 | struct mlxsw_sp_rif *rif, | |
183 | bool counters_enabled) | |
184 | { | |
185 | u32 *action_value; | |
186 | u32 *rif_value; | |
187 | u64 cnt; | |
188 | int err; | |
189 | ||
190 | /* Set Match RIF index */ | |
191 | rif_value = entry->match_values->value; | |
192 | *rif_value = mlxsw_sp_rif_index(rif); | |
193 | entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif); | |
194 | entry->match_values->mapping_valid = true; | |
195 | ||
196 | /* Set Action Forwarding */ | |
197 | action_value = entry->action_values->value; | |
198 | *action_value = 1; | |
199 | ||
200 | entry->counter_valid = false; | |
201 | entry->counter = 0; | |
6dd4aba3 AS |
202 | entry->index = mlxsw_sp_rif_index(rif); |
203 | ||
2ba5999f AS |
204 | if (!counters_enabled) |
205 | return 0; | |
206 | ||
2ba5999f AS |
207 | err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif, |
208 | MLXSW_SP_RIF_COUNTER_EGRESS, | |
209 | &cnt); | |
210 | if (!err) { | |
211 | entry->counter = cnt; | |
212 | entry->counter_valid = true; | |
213 | } | |
214 | return 0; | |
215 | } | |
216 | ||
217 | static int | |
218 | mlxsw_sp_table_erif_entries_dump(void *priv, bool counters_enabled, | |
219 | struct devlink_dpipe_dump_ctx *dump_ctx) | |
220 | { | |
221 | struct devlink_dpipe_value match_value = {{0}}, action_value = {{0}}; | |
222 | struct devlink_dpipe_action action = {0}; | |
223 | struct devlink_dpipe_match match = {0}; | |
224 | struct devlink_dpipe_entry entry = {0}; | |
225 | struct mlxsw_sp *mlxsw_sp = priv; | |
226 | unsigned int rif_count; | |
227 | int i, j; | |
228 | int err; | |
229 | ||
230 | mlxsw_sp_erif_match_action_prepare(&match, &action); | |
231 | err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match, | |
232 | &action_value, &action); | |
233 | if (err) | |
234 | return err; | |
235 | ||
236 | rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); | |
237 | rtnl_lock(); | |
238 | i = 0; | |
239 | start_again: | |
240 | err = devlink_dpipe_entry_ctx_prepare(dump_ctx); | |
241 | if (err) | |
242 | return err; | |
243 | j = 0; | |
244 | for (; i < rif_count; i++) { | |
245 | if (!mlxsw_sp->rifs[i]) | |
246 | continue; | |
247 | err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, | |
248 | mlxsw_sp->rifs[i], | |
249 | counters_enabled); | |
250 | if (err) | |
251 | goto err_entry_get; | |
252 | err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry); | |
253 | if (err) { | |
254 | if (err == -EMSGSIZE) { | |
255 | if (!j) | |
256 | goto err_entry_append; | |
257 | break; | |
258 | } | |
259 | goto err_entry_append; | |
260 | } | |
261 | j++; | |
262 | } | |
263 | ||
264 | devlink_dpipe_entry_ctx_close(dump_ctx); | |
265 | if (i != rif_count) | |
266 | goto start_again; | |
267 | rtnl_unlock(); | |
268 | ||
269 | mlxsw_sp_erif_entry_clear(&entry); | |
270 | return 0; | |
271 | err_entry_append: | |
272 | err_entry_get: | |
273 | rtnl_unlock(); | |
274 | mlxsw_sp_erif_entry_clear(&entry); | |
275 | return err; | |
276 | } | |
277 | ||
278 | static int mlxsw_sp_table_erif_counters_update(void *priv, bool enable) | |
279 | { | |
280 | struct mlxsw_sp *mlxsw_sp = priv; | |
281 | int i; | |
282 | ||
283 | rtnl_lock(); | |
284 | for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { | |
285 | if (!mlxsw_sp->rifs[i]) | |
286 | continue; | |
287 | if (enable) | |
288 | mlxsw_sp_rif_counter_alloc(mlxsw_sp, | |
289 | mlxsw_sp->rifs[i], | |
290 | MLXSW_SP_RIF_COUNTER_EGRESS); | |
291 | else | |
292 | mlxsw_sp_rif_counter_free(mlxsw_sp, | |
293 | mlxsw_sp->rifs[i], | |
294 | MLXSW_SP_RIF_COUNTER_EGRESS); | |
295 | } | |
296 | rtnl_unlock(); | |
297 | return 0; | |
298 | } | |
299 | ||
d54b70fe AS |
300 | static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = { |
301 | .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump, | |
302 | .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump, | |
2ba5999f AS |
303 | .entries_dump = mlxsw_sp_table_erif_entries_dump, |
304 | .counters_set_update = mlxsw_sp_table_erif_counters_update, | |
d54b70fe AS |
305 | }; |
306 | ||
307 | static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp) | |
308 | { | |
309 | struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); | |
310 | u64 table_size; | |
311 | ||
312 | table_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); | |
313 | return devlink_dpipe_table_register(devlink, | |
314 | MLXSW_SP_DPIPE_TABLE_NAME_ERIF, | |
315 | &mlxsw_sp_erif_ops, | |
316 | mlxsw_sp, table_size, | |
317 | false); | |
318 | } | |
319 | ||
320 | static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp) | |
321 | { | |
322 | struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); | |
323 | ||
324 | devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF); | |
325 | } | |
326 | ||
230ead01 AS |
327 | int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp) |
328 | { | |
d54b70fe AS |
329 | struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); |
330 | int err; | |
331 | ||
332 | err = devlink_dpipe_headers_register(devlink, | |
333 | &mlxsw_sp_dpipe_headers); | |
334 | if (err) | |
335 | return err; | |
336 | err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp); | |
337 | if (err) | |
338 | goto err_erif_register; | |
339 | return 0; | |
340 | ||
341 | err_erif_register: | |
342 | devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core)); | |
343 | return err; | |
230ead01 AS |
344 | } |
345 | ||
346 | void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp) | |
347 | { | |
d54b70fe AS |
348 | struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); |
349 | ||
350 | mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp); | |
351 | devlink_dpipe_headers_unregister(devlink); | |
230ead01 | 352 | } |