blob: 491cb8eac385ed8ecf44ab6a2f46ab6bf57a59f9 [file] [log] [blame]
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +03001/*
2 * Copyright 2015 Freescale Semiconductor, Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 *
6 * Ethernet Switch commands
7 */
8
9#include <common.h>
10#include <command.h>
11#include <errno.h>
Codrin Ciubotariu22449852015-09-09 18:00:52 +030012#include <env_flags.h>
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +030013#include <ethsw.h>
14
15static const char *ethsw_name;
16
Codrin Ciubotariu86719f02015-07-24 16:55:29 +030017#define ETHSW_PORT_STATS_HELP "ethsw [port <port_no>] statistics " \
18"{ [help] | [clear] } - show an l2 switch port's statistics"
19
20static int ethsw_port_stats_help_key_func(struct ethsw_command_def *parsed_cmd)
21{
22 printf(ETHSW_PORT_STATS_HELP"\n");
23
24 return CMD_RET_SUCCESS;
25}
26
Codrin Ciubotariu68c929d2015-07-24 16:55:30 +030027#define ETHSW_LEARN_HELP "ethsw [port <port_no>] learning " \
28"{ [help] | show | auto | disable } " \
29"- enable/disable/show learning configuration on a port"
30
31static int ethsw_learn_help_key_func(struct ethsw_command_def *parsed_cmd)
32{
33 printf(ETHSW_LEARN_HELP"\n");
34
35 return CMD_RET_SUCCESS;
36}
37
Codrin Ciubotariu22449852015-09-09 18:00:52 +030038#define ETHSW_FDB_HELP "ethsw [port <port_no>] [vlan <vid>] fdb " \
39"{ [help] | show | flush | { add | del } <mac> } " \
40"- Add/delete a mac entry in FDB; use show to see FDB entries; " \
41"if vlan <vid> is missing, VID 1 will be used"
42
43static int ethsw_fdb_help_key_func(struct ethsw_command_def *parsed_cmd)
44{
45 printf(ETHSW_FDB_HELP"\n");
46
47 return CMD_RET_SUCCESS;
48}
49
Codrin Ciubotariua2477922015-07-24 16:55:33 +030050#define ETHSW_PVID_HELP "ethsw [port <port_no>] " \
51"pvid { [help] | show | <pvid> } " \
52"- set/show PVID (ingress and egress VLAN tagging) for a port"
53
54static int ethsw_pvid_help_key_func(struct ethsw_command_def *parsed_cmd)
55{
56 printf(ETHSW_PVID_HELP"\n");
57
58 return CMD_RET_SUCCESS;
59}
60
61#define ETHSW_VLAN_HELP "ethsw [port <port_no>] vlan " \
62"{ [help] | show | add <vid> | del <vid> } " \
63"- add a VLAN to a port (VLAN members)"
64
65static int ethsw_vlan_help_key_func(struct ethsw_command_def *parsed_cmd)
66{
67 printf(ETHSW_VLAN_HELP"\n");
68
69 return CMD_RET_SUCCESS;
70}
71
72#define ETHSW_PORT_UNTAG_HELP "ethsw [port <port_no>] untagged " \
73"{ [help] | show | all | none | pvid } " \
Codrin Ciubotariubf9f2ed2015-12-15 15:21:05 +020074" - set egress tagging mode for a port"
Codrin Ciubotariua2477922015-07-24 16:55:33 +030075
76static int ethsw_port_untag_help_key_func(struct ethsw_command_def *parsed_cmd)
77{
78 printf(ETHSW_PORT_UNTAG_HELP"\n");
79
80 return CMD_RET_SUCCESS;
81}
82
83#define ETHSW_EGR_VLAN_TAG_HELP "ethsw [port <port_no>] egress tag " \
84"{ [help] | show | pvid | classified } " \
85"- Configure VID source for egress tag. " \
86"Tag's VID could be the frame's classified VID or the PVID of the port"
87
88static int ethsw_egr_tag_help_key_func(struct ethsw_command_def *parsed_cmd)
89{
90 printf(ETHSW_EGR_VLAN_TAG_HELP"\n");
91
92 return CMD_RET_SUCCESS;
93}
94
Codrin Ciubotariu21d214f2015-07-24 16:55:34 +030095#define ETHSW_VLAN_FDB_HELP "ethsw vlan fdb " \
96"{ [help] | show | shared | private } " \
97"- make VLAN learning shared or private"
98
99static int ethsw_vlan_learn_help_key_func(struct ethsw_command_def *parsed_cmd)
100{
101 printf(ETHSW_VLAN_FDB_HELP"\n");
102
103 return CMD_RET_SUCCESS;
104}
105
Codrin Ciubotariu5ed1bac2015-07-24 16:55:35 +0300106#define ETHSW_PORT_INGR_FLTR_HELP "ethsw [port <port_no>] ingress filtering" \
107" { [help] | show | enable | disable } " \
108"- enable/disable VLAN ingress filtering on port"
109
110static int ethsw_ingr_fltr_help_key_func(struct ethsw_command_def *parsed_cmd)
111{
112 printf(ETHSW_PORT_INGR_FLTR_HELP"\n");
113
114 return CMD_RET_SUCCESS;
115}
116
Codrin Ciubotariuaae0e682015-12-15 15:21:06 +0200117#define ETHSW_PORT_AGGR_HELP "ethsw [port <port_no>] aggr" \
118" { [help] | show | <lag_group_no> } " \
119"- get/set LAG group for a port"
120
121static int ethsw_port_aggr_help_key_func(struct ethsw_command_def *parsed_cmd)
122{
123 printf(ETHSW_PORT_AGGR_HELP"\n");
124
125 return CMD_RET_SUCCESS;
126}
127
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +0300128static struct keywords_to_function {
129 enum ethsw_keyword_id cmd_keyword[ETHSW_MAX_CMD_PARAMS];
130 int cmd_func_offset;
131 int (*keyword_function)(struct ethsw_command_def *parsed_cmd);
132} ethsw_cmd_def[] = {
133 {
134 .cmd_keyword = {
135 ethsw_id_enable,
136 ethsw_id_key_end,
137 },
138 .cmd_func_offset = offsetof(struct ethsw_command_func,
139 port_enable),
140 .keyword_function = NULL,
141 }, {
142 .cmd_keyword = {
143 ethsw_id_disable,
144 ethsw_id_key_end,
145 },
146 .cmd_func_offset = offsetof(struct ethsw_command_func,
147 port_disable),
148 .keyword_function = NULL,
149 }, {
150 .cmd_keyword = {
151 ethsw_id_show,
152 ethsw_id_key_end,
153 },
154 .cmd_func_offset = offsetof(struct ethsw_command_func,
155 port_show),
156 .keyword_function = NULL,
Codrin Ciubotariu86719f02015-07-24 16:55:29 +0300157 }, {
158 .cmd_keyword = {
159 ethsw_id_statistics,
160 ethsw_id_help,
161 ethsw_id_key_end,
162 },
163 .cmd_func_offset = -1,
164 .keyword_function = &ethsw_port_stats_help_key_func,
165 }, {
166 .cmd_keyword = {
167 ethsw_id_statistics,
168 ethsw_id_key_end,
169 },
170 .cmd_func_offset = offsetof(struct ethsw_command_func,
171 port_stats),
172 .keyword_function = NULL,
173 }, {
174 .cmd_keyword = {
175 ethsw_id_statistics,
176 ethsw_id_clear,
177 ethsw_id_key_end,
178 },
179 .cmd_func_offset = offsetof(struct ethsw_command_func,
180 port_stats_clear),
181 .keyword_function = NULL,
Codrin Ciubotariu68c929d2015-07-24 16:55:30 +0300182 }, {
183 .cmd_keyword = {
184 ethsw_id_learning,
185 ethsw_id_key_end,
186 },
187 .cmd_func_offset = -1,
188 .keyword_function = &ethsw_learn_help_key_func,
189 }, {
190 .cmd_keyword = {
191 ethsw_id_learning,
192 ethsw_id_help,
193 ethsw_id_key_end,
194 },
195 .cmd_func_offset = -1,
196 .keyword_function = &ethsw_learn_help_key_func,
197 }, {
198 .cmd_keyword = {
199 ethsw_id_learning,
200 ethsw_id_show,
201 ethsw_id_key_end,
202 },
203 .cmd_func_offset = offsetof(struct ethsw_command_func,
204 port_learn_show),
205 .keyword_function = NULL,
206 }, {
207 .cmd_keyword = {
208 ethsw_id_learning,
209 ethsw_id_auto,
210 ethsw_id_key_end,
211 },
212 .cmd_func_offset = offsetof(struct ethsw_command_func,
213 port_learn),
214 .keyword_function = NULL,
215 }, {
216 .cmd_keyword = {
217 ethsw_id_learning,
218 ethsw_id_disable,
219 ethsw_id_key_end,
220 },
221 .cmd_func_offset = offsetof(struct ethsw_command_func,
222 port_learn),
223 .keyword_function = NULL,
Codrin Ciubotariu22449852015-09-09 18:00:52 +0300224 }, {
225 .cmd_keyword = {
226 ethsw_id_fdb,
227 ethsw_id_key_end,
228 },
229 .cmd_func_offset = -1,
230 .keyword_function = &ethsw_fdb_help_key_func,
231 }, {
232 .cmd_keyword = {
233 ethsw_id_fdb,
234 ethsw_id_help,
235 ethsw_id_key_end,
236 },
237 .cmd_func_offset = -1,
238 .keyword_function = &ethsw_fdb_help_key_func,
239 }, {
240 .cmd_keyword = {
241 ethsw_id_fdb,
242 ethsw_id_show,
243 ethsw_id_key_end,
244 },
245 .cmd_func_offset = offsetof(struct ethsw_command_func,
246 fdb_show),
247 .keyword_function = NULL,
248 }, {
249 .cmd_keyword = {
250 ethsw_id_fdb,
251 ethsw_id_flush,
252 ethsw_id_key_end,
253 },
254 .cmd_func_offset = offsetof(struct ethsw_command_func,
255 fdb_flush),
256 .keyword_function = NULL,
257 }, {
258 .cmd_keyword = {
259 ethsw_id_fdb,
260 ethsw_id_add,
261 ethsw_id_add_del_mac,
262 ethsw_id_key_end,
263 },
264 .cmd_func_offset = offsetof(struct ethsw_command_func,
265 fdb_entry_add),
266 .keyword_function = NULL,
267 }, {
268 .cmd_keyword = {
269 ethsw_id_fdb,
270 ethsw_id_del,
271 ethsw_id_add_del_mac,
272 ethsw_id_key_end,
273 },
274 .cmd_func_offset = offsetof(struct ethsw_command_func,
275 fdb_entry_del),
276 .keyword_function = NULL,
Codrin Ciubotariua2477922015-07-24 16:55:33 +0300277 }, {
278 .cmd_keyword = {
279 ethsw_id_pvid,
280 ethsw_id_key_end,
281 },
282 .cmd_func_offset = -1,
283 .keyword_function = &ethsw_pvid_help_key_func,
284 }, {
285 .cmd_keyword = {
286 ethsw_id_pvid,
287 ethsw_id_help,
288 ethsw_id_key_end,
289 },
290 .cmd_func_offset = -1,
291 .keyword_function = &ethsw_pvid_help_key_func,
292 }, {
293 .cmd_keyword = {
294 ethsw_id_pvid,
295 ethsw_id_show,
296 ethsw_id_key_end,
297 },
298 .cmd_func_offset = offsetof(struct ethsw_command_func,
299 pvid_show),
300 .keyword_function = NULL,
301 }, {
302 .cmd_keyword = {
303 ethsw_id_pvid,
304 ethsw_id_pvid_no,
305 ethsw_id_key_end,
306 },
307 .cmd_func_offset = offsetof(struct ethsw_command_func,
308 pvid_set),
309 .keyword_function = NULL,
310 }, {
311 .cmd_keyword = {
312 ethsw_id_vlan,
313 ethsw_id_key_end,
314 },
315 .cmd_func_offset = -1,
316 .keyword_function = &ethsw_vlan_help_key_func,
317 }, {
318 .cmd_keyword = {
319 ethsw_id_vlan,
320 ethsw_id_help,
321 ethsw_id_key_end,
322 },
323 .cmd_func_offset = -1,
324 .keyword_function = &ethsw_vlan_help_key_func,
325 }, {
326 .cmd_keyword = {
327 ethsw_id_vlan,
328 ethsw_id_show,
329 ethsw_id_key_end,
330 },
331 .cmd_func_offset = offsetof(struct ethsw_command_func,
332 vlan_show),
333 .keyword_function = NULL,
334 }, {
335 .cmd_keyword = {
336 ethsw_id_vlan,
337 ethsw_id_add,
338 ethsw_id_add_del_no,
339 ethsw_id_key_end,
340 },
341 .cmd_func_offset = offsetof(struct ethsw_command_func,
342 vlan_set),
343 .keyword_function = NULL,
344 }, {
345 .cmd_keyword = {
346 ethsw_id_vlan,
347 ethsw_id_del,
348 ethsw_id_add_del_no,
349 ethsw_id_key_end,
350 },
351 .cmd_func_offset = offsetof(struct ethsw_command_func,
352 vlan_set),
353 .keyword_function = NULL,
354 }, {
355 .cmd_keyword = {
356 ethsw_id_untagged,
357 ethsw_id_key_end,
358 },
359 .cmd_func_offset = -1,
360 .keyword_function = &ethsw_port_untag_help_key_func,
361 }, {
362 .cmd_keyword = {
363 ethsw_id_untagged,
364 ethsw_id_help,
365 ethsw_id_key_end,
366 },
367 .cmd_func_offset = -1,
368 .keyword_function = &ethsw_port_untag_help_key_func,
369 }, {
370 .cmd_keyword = {
371 ethsw_id_untagged,
372 ethsw_id_show,
373 ethsw_id_key_end,
374 },
375 .cmd_func_offset = offsetof(struct ethsw_command_func,
376 port_untag_show),
377 .keyword_function = NULL,
378 }, {
379 .cmd_keyword = {
380 ethsw_id_untagged,
381 ethsw_id_all,
382 ethsw_id_key_end,
383 },
384 .cmd_func_offset = offsetof(struct ethsw_command_func,
385 port_untag_set),
386 .keyword_function = NULL,
387 }, {
388 .cmd_keyword = {
389 ethsw_id_untagged,
390 ethsw_id_none,
391 ethsw_id_key_end,
392 },
393 .cmd_func_offset = offsetof(struct ethsw_command_func,
394 port_untag_set),
395 .keyword_function = NULL,
396 }, {
397 .cmd_keyword = {
398 ethsw_id_untagged,
399 ethsw_id_pvid,
400 ethsw_id_key_end,
401 },
402 .cmd_func_offset = offsetof(struct ethsw_command_func,
403 port_untag_set),
404 .keyword_function = NULL,
405 }, {
406 .cmd_keyword = {
407 ethsw_id_egress,
408 ethsw_id_tag,
409 ethsw_id_key_end,
410 },
411 .cmd_func_offset = -1,
412 .keyword_function = &ethsw_egr_tag_help_key_func,
413 }, {
414 .cmd_keyword = {
415 ethsw_id_egress,
416 ethsw_id_tag,
417 ethsw_id_help,
418 ethsw_id_key_end,
419 },
420 .cmd_func_offset = -1,
421 .keyword_function = &ethsw_egr_tag_help_key_func,
422 }, {
423 .cmd_keyword = {
424 ethsw_id_egress,
425 ethsw_id_tag,
426 ethsw_id_show,
427 ethsw_id_key_end,
428 },
429 .cmd_func_offset = offsetof(struct ethsw_command_func,
430 port_egr_vlan_show),
431 .keyword_function = NULL,
432 }, {
433 .cmd_keyword = {
434 ethsw_id_egress,
435 ethsw_id_tag,
436 ethsw_id_pvid,
437 ethsw_id_key_end,
438 },
439 .cmd_func_offset = offsetof(struct ethsw_command_func,
440 port_egr_vlan_set),
441 .keyword_function = NULL,
442 }, {
443 .cmd_keyword = {
444 ethsw_id_egress,
445 ethsw_id_tag,
446 ethsw_id_classified,
447 ethsw_id_key_end,
448 },
449 .cmd_func_offset = offsetof(struct ethsw_command_func,
450 port_egr_vlan_set),
451 .keyword_function = NULL,
Codrin Ciubotariu21d214f2015-07-24 16:55:34 +0300452 }, {
453 .cmd_keyword = {
454 ethsw_id_vlan,
455 ethsw_id_fdb,
456 ethsw_id_key_end,
457 },
458 .cmd_func_offset = -1,
459 .keyword_function = &ethsw_vlan_learn_help_key_func,
460 }, {
461 .cmd_keyword = {
462 ethsw_id_vlan,
463 ethsw_id_fdb,
464 ethsw_id_help,
465 ethsw_id_key_end,
466 },
467 .cmd_func_offset = -1,
468 .keyword_function = &ethsw_vlan_learn_help_key_func,
469 }, {
470 .cmd_keyword = {
471 ethsw_id_vlan,
472 ethsw_id_fdb,
473 ethsw_id_show,
474 ethsw_id_key_end,
475 },
476 .cmd_func_offset = offsetof(struct ethsw_command_func,
477 vlan_learn_show),
478 .keyword_function = NULL,
479 }, {
480 .cmd_keyword = {
481 ethsw_id_vlan,
482 ethsw_id_fdb,
483 ethsw_id_shared,
484 ethsw_id_key_end,
485 },
486 .cmd_func_offset = offsetof(struct ethsw_command_func,
487 vlan_learn_set),
488 .keyword_function = NULL,
489 }, {
490 .cmd_keyword = {
491 ethsw_id_vlan,
492 ethsw_id_fdb,
493 ethsw_id_private,
494 ethsw_id_key_end,
495 },
496 .cmd_func_offset = offsetof(struct ethsw_command_func,
497 vlan_learn_set),
498 .keyword_function = NULL,
Codrin Ciubotariu5ed1bac2015-07-24 16:55:35 +0300499 }, {
500 .cmd_keyword = {
501 ethsw_id_ingress,
502 ethsw_id_filtering,
503 ethsw_id_key_end,
504 },
505 .cmd_func_offset = -1,
506 .keyword_function = &ethsw_ingr_fltr_help_key_func,
507 }, {
508 .cmd_keyword = {
509 ethsw_id_ingress,
510 ethsw_id_filtering,
511 ethsw_id_help,
512 ethsw_id_key_end,
513 },
514 .cmd_func_offset = -1,
515 .keyword_function = &ethsw_ingr_fltr_help_key_func,
516 }, {
517 .cmd_keyword = {
518 ethsw_id_ingress,
519 ethsw_id_filtering,
520 ethsw_id_show,
521 ethsw_id_key_end,
522 },
523 .cmd_func_offset = offsetof(struct ethsw_command_func,
524 port_ingr_filt_show),
525 .keyword_function = NULL,
526 }, {
527 .cmd_keyword = {
528 ethsw_id_ingress,
529 ethsw_id_filtering,
530 ethsw_id_enable,
531 ethsw_id_key_end,
532 },
533 .cmd_func_offset = offsetof(struct ethsw_command_func,
534 port_ingr_filt_set),
535 .keyword_function = NULL,
536 }, {
537 .cmd_keyword = {
538 ethsw_id_ingress,
539 ethsw_id_filtering,
540 ethsw_id_disable,
541 ethsw_id_key_end,
542 },
543 .cmd_func_offset = offsetof(struct ethsw_command_func,
544 port_ingr_filt_set),
545 .keyword_function = NULL,
Codrin Ciubotariuaae0e682015-12-15 15:21:06 +0200546 }, {
547 .cmd_keyword = {
548 ethsw_id_aggr,
549 ethsw_id_key_end,
550 },
551 .cmd_func_offset = -1,
552 .keyword_function = &ethsw_port_aggr_help_key_func,
553 }, {
554 .cmd_keyword = {
555 ethsw_id_aggr,
556 ethsw_id_help,
557 ethsw_id_key_end,
558 },
559 .cmd_func_offset = -1,
560 .keyword_function = &ethsw_port_aggr_help_key_func,
561 }, {
562 .cmd_keyword = {
563 ethsw_id_aggr,
564 ethsw_id_show,
565 ethsw_id_key_end,
566 },
567 .cmd_func_offset = offsetof(struct ethsw_command_func,
568 port_aggr_show),
569 .keyword_function = NULL,
570 }, {
571 .cmd_keyword = {
572 ethsw_id_aggr,
573 ethsw_id_aggr_no,
574 ethsw_id_key_end,
575 },
576 .cmd_func_offset = offsetof(struct ethsw_command_func,
577 port_aggr_set),
578 .keyword_function = NULL,
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +0300579 },
580};
581
582struct keywords_optional {
583 int cmd_keyword[ETHSW_MAX_CMD_PARAMS];
584} cmd_opt_def[] = {
585 {
586 .cmd_keyword = {
587 ethsw_id_port,
588 ethsw_id_port_no,
589 ethsw_id_key_end,
590 },
Codrin Ciubotariu22449852015-09-09 18:00:52 +0300591 }, {
592 .cmd_keyword = {
593 ethsw_id_vlan,
594 ethsw_id_vlan_no,
595 ethsw_id_key_end,
596 },
597 }, {
598 .cmd_keyword = {
599 ethsw_id_port,
600 ethsw_id_port_no,
601 ethsw_id_vlan,
602 ethsw_id_vlan_no,
603 ethsw_id_key_end,
604 },
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +0300605 },
606};
607
608static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc, char
609 *const argv[], int *argc_nr,
610 struct ethsw_command_def *parsed_cmd);
611static int keyword_match_port(enum ethsw_keyword_id key_id, int argc,
612 char *const argv[], int *argc_nr,
613 struct ethsw_command_def *parsed_cmd);
Codrin Ciubotariu22449852015-09-09 18:00:52 +0300614static int keyword_match_vlan(enum ethsw_keyword_id key_id, int argc,
615 char *const argv[], int *argc_nr,
616 struct ethsw_command_def *parsed_cmd);
Codrin Ciubotariua2477922015-07-24 16:55:33 +0300617static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
618 char *const argv[], int *argc_nr,
619 struct ethsw_command_def *parsed_cmd);
Codrin Ciubotariu22449852015-09-09 18:00:52 +0300620static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
621 char *const argv[], int *argc_nr,
622 struct ethsw_command_def *parsed_cmd);
Codrin Ciubotariuaae0e682015-12-15 15:21:06 +0200623static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
624 char *const argv[], int *argc_nr,
625 struct ethsw_command_def *parsed_cmd);
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +0300626
627/*
628 * Define properties for each keyword;
629 * keep the order synced with enum ethsw_keyword_id
630 */
631struct keyword_def {
632 const char *keyword_name;
633 int (*match)(enum ethsw_keyword_id key_id, int argc, char *const argv[],
634 int *argc_nr, struct ethsw_command_def *parsed_cmd);
635} keyword[] = {
636 {
637 .keyword_name = "help",
638 .match = &keyword_match_gen,
639 }, {
640 .keyword_name = "show",
641 .match = &keyword_match_gen,
642 }, {
643 .keyword_name = "port",
644 .match = &keyword_match_port
645 }, {
646 .keyword_name = "enable",
647 .match = &keyword_match_gen,
648 }, {
649 .keyword_name = "disable",
650 .match = &keyword_match_gen,
Codrin Ciubotariu86719f02015-07-24 16:55:29 +0300651 }, {
652 .keyword_name = "statistics",
653 .match = &keyword_match_gen,
654 }, {
655 .keyword_name = "clear",
656 .match = &keyword_match_gen,
Codrin Ciubotariu68c929d2015-07-24 16:55:30 +0300657 }, {
658 .keyword_name = "learning",
659 .match = &keyword_match_gen,
660 }, {
661 .keyword_name = "auto",
662 .match = &keyword_match_gen,
Codrin Ciubotariu22449852015-09-09 18:00:52 +0300663 }, {
664 .keyword_name = "vlan",
665 .match = &keyword_match_vlan,
666 }, {
667 .keyword_name = "fdb",
668 .match = &keyword_match_gen,
669 }, {
670 .keyword_name = "add",
671 .match = &keyword_match_mac_addr,
672 }, {
673 .keyword_name = "del",
674 .match = &keyword_match_mac_addr,
675 }, {
676 .keyword_name = "flush",
677 .match = &keyword_match_gen,
Codrin Ciubotariua2477922015-07-24 16:55:33 +0300678 }, {
679 .keyword_name = "pvid",
680 .match = &keyword_match_pvid,
681 }, {
682 .keyword_name = "untagged",
683 .match = &keyword_match_gen,
684 }, {
685 .keyword_name = "all",
686 .match = &keyword_match_gen,
687 }, {
688 .keyword_name = "none",
689 .match = &keyword_match_gen,
690 }, {
691 .keyword_name = "egress",
692 .match = &keyword_match_gen,
693 }, {
694 .keyword_name = "tag",
695 .match = &keyword_match_gen,
696 }, {
697 .keyword_name = "classified",
698 .match = &keyword_match_gen,
Codrin Ciubotariu21d214f2015-07-24 16:55:34 +0300699 }, {
700 .keyword_name = "shared",
701 .match = &keyword_match_gen,
702 }, {
703 .keyword_name = "private",
704 .match = &keyword_match_gen,
Codrin Ciubotariu5ed1bac2015-07-24 16:55:35 +0300705 }, {
706 .keyword_name = "ingress",
707 .match = &keyword_match_gen,
708 }, {
709 .keyword_name = "filtering",
710 .match = &keyword_match_gen,
Codrin Ciubotariuaae0e682015-12-15 15:21:06 +0200711 }, {
712 .keyword_name = "aggr",
713 .match = &keyword_match_aggr,
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +0300714 },
715};
716
717/*
718 * Function used by an Ethernet Switch driver to set the functions
719 * that must be called by the parser when an ethsw command is given
720 */
721int ethsw_define_functions(const struct ethsw_command_func *cmd_func)
722{
723 int i;
724 void **aux_p;
725 int (*cmd_func_aux)(struct ethsw_command_def *);
726
727 if (!cmd_func->ethsw_name)
728 return -EINVAL;
729
730 ethsw_name = cmd_func->ethsw_name;
731
732 for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
733 /*
734 * get the pointer to the function send by the Ethernet Switch
735 * driver that corresponds to the proper ethsw command
736 */
737 if (ethsw_cmd_def[i].keyword_function)
738 continue;
739
740 aux_p = (void *)cmd_func + ethsw_cmd_def[i].cmd_func_offset;
741
742 cmd_func_aux = (int (*)(struct ethsw_command_def *)) *aux_p;
743 ethsw_cmd_def[i].keyword_function = cmd_func_aux;
744 }
745
746 return 0;
747}
748
749/* Generic function used to match a keyword only by a string */
750static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc,
751 char *const argv[], int *argc_nr,
752 struct ethsw_command_def *parsed_cmd)
753{
754 if (strcmp(argv[*argc_nr], keyword[key_id].keyword_name) == 0) {
755 parsed_cmd->cmd_to_keywords[*argc_nr] = key_id;
756
757 return 1;
758 }
759 return 0;
760}
761
762/* Function used to match the command's port */
763static int keyword_match_port(enum ethsw_keyword_id key_id, int argc,
764 char *const argv[], int *argc_nr,
765 struct ethsw_command_def *parsed_cmd)
766{
767 unsigned long val;
768
769 if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
770 return 0;
771
772 if (*argc_nr + 1 >= argc)
773 return 0;
774
775 if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
776 parsed_cmd->port = val;
777 (*argc_nr)++;
778 parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_port_no;
779 return 1;
780 }
781
782 return 0;
783}
784
Codrin Ciubotariu22449852015-09-09 18:00:52 +0300785/* Function used to match the command's vlan */
786static int keyword_match_vlan(enum ethsw_keyword_id key_id, int argc,
787 char *const argv[], int *argc_nr,
788 struct ethsw_command_def *parsed_cmd)
789{
790 unsigned long val;
791 int aux;
792
793 if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
794 return 0;
795
796 if (*argc_nr + 1 >= argc)
797 return 0;
798
799 if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
800 parsed_cmd->vid = val;
801 (*argc_nr)++;
802 parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_vlan_no;
803 return 1;
804 }
805
806 aux = *argc_nr + 1;
807
808 if (keyword_match_gen(ethsw_id_add, argc, argv, &aux, parsed_cmd))
809 parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_add;
810 else if (keyword_match_gen(ethsw_id_del, argc, argv, &aux, parsed_cmd))
811 parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_del;
812 else
813 return 0;
814
815 if (*argc_nr + 2 >= argc)
816 return 0;
817
818 if (strict_strtoul(argv[*argc_nr + 2], 10, &val) != -EINVAL) {
819 parsed_cmd->vid = val;
820 (*argc_nr) += 2;
821 parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_add_del_no;
822 return 1;
823 }
824
825 return 0;
826}
827
Codrin Ciubotariua2477922015-07-24 16:55:33 +0300828/* Function used to match the command's pvid */
829static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
830 char *const argv[], int *argc_nr,
831 struct ethsw_command_def *parsed_cmd)
832{
833 unsigned long val;
834
835 if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
836 return 0;
837
838 if (*argc_nr + 1 >= argc)
839 return 1;
840
841 if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
842 parsed_cmd->vid = val;
843 (*argc_nr)++;
844 parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_pvid_no;
845 }
846
847 return 1;
848}
849
Codrin Ciubotariu22449852015-09-09 18:00:52 +0300850/* Function used to match the command's MAC address */
851static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
852 char *const argv[], int *argc_nr,
853 struct ethsw_command_def *parsed_cmd)
854{
855 if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
856 return 0;
857
858 if ((*argc_nr + 1 >= argc) ||
859 !is_broadcast_ethaddr(parsed_cmd->ethaddr))
860 return 1;
861
862 if (eth_validate_ethaddr_str(argv[*argc_nr + 1])) {
863 printf("Invalid MAC address: %s\n", argv[*argc_nr + 1]);
864 return 0;
865 }
866
867 eth_parse_enetaddr(argv[*argc_nr + 1], parsed_cmd->ethaddr);
868
869 if (is_broadcast_ethaddr(parsed_cmd->ethaddr)) {
870 memset(parsed_cmd->ethaddr, 0xFF, sizeof(parsed_cmd->ethaddr));
871 return 0;
872 }
873
874 parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_add_del_mac;
875
876 return 1;
877}
878
Codrin Ciubotariuaae0e682015-12-15 15:21:06 +0200879/* Function used to match the command's aggregation number */
880static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
881 char *const argv[], int *argc_nr,
882 struct ethsw_command_def *parsed_cmd)
883{
884 unsigned long val;
885
886 if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
887 return 0;
888
889 if (*argc_nr + 1 >= argc)
890 return 1;
891
892 if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
893 parsed_cmd->aggr_grp = val;
894 (*argc_nr)++;
895 parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_aggr_no;
896 }
897
898 return 1;
899}
900
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +0300901/* Finds optional keywords and modifies *argc_va to skip them */
902static void cmd_keywords_opt_check(const struct ethsw_command_def *parsed_cmd,
903 int *argc_val)
904{
905 int i;
906 int keyw_opt_matched;
907 int argc_val_max;
908 int const *cmd_keyw_p;
909 int const *cmd_keyw_opt_p;
910
911 /* remember the best match */
912 argc_val_max = *argc_val;
913
914 /*
915 * check if our command's optional keywords match the optional
916 * keywords of an available command
917 */
918 for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
919 keyw_opt_matched = 0;
920 cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_opt_matched];
921 cmd_keyw_opt_p = &cmd_opt_def[i].cmd_keyword[keyw_opt_matched];
922
923 /*
924 * increase the number of keywords that
925 * matched with a command
926 */
927 while (keyw_opt_matched + *argc_val <
928 parsed_cmd->cmd_keywords_nr &&
929 *cmd_keyw_opt_p != ethsw_id_key_end &&
930 *(cmd_keyw_p + *argc_val) == *cmd_keyw_opt_p) {
931 keyw_opt_matched++;
932 cmd_keyw_p++;
933 cmd_keyw_opt_p++;
934 }
935
936 /*
937 * if all our optional command's keywords perfectly match an
938 * optional pattern, then we can move to the next defined
939 * keywords in our command; remember the one that matched the
940 * greatest number of keywords
941 */
942 if (keyw_opt_matched + *argc_val <=
943 parsed_cmd->cmd_keywords_nr &&
944 *cmd_keyw_opt_p == ethsw_id_key_end &&
945 *argc_val + keyw_opt_matched > argc_val_max)
946 argc_val_max = *argc_val + keyw_opt_matched;
947 }
948
949 *argc_val = argc_val_max;
950}
951
952/*
953 * Finds the function to call based on keywords and
954 * modifies *argc_va to skip them
955 */
956static void cmd_keywords_check(struct ethsw_command_def *parsed_cmd,
957 int *argc_val)
958{
959 int i;
960 int keyw_matched;
961 int *cmd_keyw_p;
962 int *cmd_keyw_def_p;
963
964 /*
965 * check if our command's keywords match the
966 * keywords of an available command
967 */
968 for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
969 keyw_matched = 0;
970 cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_matched];
971 cmd_keyw_def_p = &ethsw_cmd_def[i].cmd_keyword[keyw_matched];
972
973 /*
974 * increase the number of keywords that
975 * matched with a command
976 */
977 while (keyw_matched + *argc_val < parsed_cmd->cmd_keywords_nr &&
978 *cmd_keyw_def_p != ethsw_id_key_end &&
979 *(cmd_keyw_p + *argc_val) == *cmd_keyw_def_p) {
980 keyw_matched++;
981 cmd_keyw_p++;
982 cmd_keyw_def_p++;
983 }
984
985 /*
986 * if all our command's keywords perfectly match an
987 * available command, then we get the function we need to call
988 * to configure the Ethernet Switch
989 */
990 if (keyw_matched && keyw_matched + *argc_val ==
991 parsed_cmd->cmd_keywords_nr &&
992 *cmd_keyw_def_p == ethsw_id_key_end) {
993 *argc_val += keyw_matched;
994 parsed_cmd->cmd_function =
995 ethsw_cmd_def[i].keyword_function;
996 return;
997 }
998 }
999}
1000
1001/* find all the keywords in the command */
1002static int keywords_find(int argc, char * const argv[],
1003 struct ethsw_command_def *parsed_cmd)
1004{
1005 int i;
1006 int j;
1007 int argc_val;
1008 int rc = CMD_RET_SUCCESS;
1009
1010 for (i = 1; i < argc; i++) {
1011 for (j = 0; j < ethsw_id_count; j++) {
1012 if (keyword[j].match(j, argc, argv, &i, parsed_cmd))
1013 break;
1014 }
1015 }
1016
1017 /* if there is no keyword match for a word, the command is invalid */
1018 for (i = 1; i < argc; i++)
1019 if (parsed_cmd->cmd_to_keywords[i] == ethsw_id_key_end)
1020 rc = CMD_RET_USAGE;
1021
1022 parsed_cmd->cmd_keywords_nr = argc;
1023 argc_val = 1;
1024
1025 /* get optional parameters first */
1026 cmd_keywords_opt_check(parsed_cmd, &argc_val);
1027
1028 if (argc_val == parsed_cmd->cmd_keywords_nr)
1029 return CMD_RET_USAGE;
1030
1031 /*
1032 * check the keywords and if a match is found,
1033 * get the function to call
1034 */
1035 cmd_keywords_check(parsed_cmd, &argc_val);
1036
1037 /* error if not all commands' parameters were matched */
1038 if (argc_val == parsed_cmd->cmd_keywords_nr) {
1039 if (!parsed_cmd->cmd_function) {
1040 printf("Command not available for: %s\n", ethsw_name);
1041 rc = CMD_RET_FAILURE;
1042 }
1043 } else {
1044 rc = CMD_RET_USAGE;
1045 }
1046
1047 return rc;
1048}
1049
1050static void command_def_init(struct ethsw_command_def *parsed_cmd)
1051{
1052 int i;
1053
1054 for (i = 0; i < ETHSW_MAX_CMD_PARAMS; i++)
1055 parsed_cmd->cmd_to_keywords[i] = ethsw_id_key_end;
1056
1057 parsed_cmd->port = ETHSW_CMD_PORT_ALL;
Codrin Ciubotariu22449852015-09-09 18:00:52 +03001058 parsed_cmd->vid = ETHSW_CMD_VLAN_ALL;
Codrin Ciubotariuaae0e682015-12-15 15:21:06 +02001059 parsed_cmd->aggr_grp = ETHSW_CMD_AGGR_GRP_NONE;
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +03001060 parsed_cmd->cmd_function = NULL;
Codrin Ciubotariu22449852015-09-09 18:00:52 +03001061
1062 /* We initialize the MAC address with the Broadcast address */
1063 memset(parsed_cmd->ethaddr, 0xff, sizeof(parsed_cmd->ethaddr));
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +03001064}
1065
1066/* function to interpret commands starting with "ethsw " */
1067static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1068{
1069 struct ethsw_command_def parsed_cmd;
1070 int rc = CMD_RET_SUCCESS;
1071
1072 if (argc == 1 || argc >= ETHSW_MAX_CMD_PARAMS)
1073 return CMD_RET_USAGE;
1074
1075 command_def_init(&parsed_cmd);
1076
1077 rc = keywords_find(argc, argv, &parsed_cmd);
1078
1079 if (rc == CMD_RET_SUCCESS)
1080 rc = parsed_cmd.cmd_function(&parsed_cmd);
1081
1082 return rc;
1083}
1084
1085#define ETHSW_PORT_CONF_HELP "[port <port_no>] { enable | disable | show } " \
Codrin Ciubotariubf9f2ed2015-12-15 15:21:05 +02001086"- enable/disable a port; show a port's configuration"
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +03001087
1088U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
1089 "Ethernet l2 switch commands",
1090 ETHSW_PORT_CONF_HELP"\n"
Codrin Ciubotariu86719f02015-07-24 16:55:29 +03001091 ETHSW_PORT_STATS_HELP"\n"
Codrin Ciubotariu68c929d2015-07-24 16:55:30 +03001092 ETHSW_LEARN_HELP"\n"
Codrin Ciubotariu22449852015-09-09 18:00:52 +03001093 ETHSW_FDB_HELP"\n"
Codrin Ciubotariua2477922015-07-24 16:55:33 +03001094 ETHSW_PVID_HELP"\n"
1095 ETHSW_VLAN_HELP"\n"
1096 ETHSW_PORT_UNTAG_HELP"\n"
1097 ETHSW_EGR_VLAN_TAG_HELP"\n"
Codrin Ciubotariu21d214f2015-07-24 16:55:34 +03001098 ETHSW_VLAN_FDB_HELP"\n"
Codrin Ciubotariu5ed1bac2015-07-24 16:55:35 +03001099 ETHSW_PORT_INGR_FLTR_HELP"\n"
Codrin Ciubotariuaae0e682015-12-15 15:21:06 +02001100 ETHSW_PORT_AGGR_HELP"\n"
Codrin Ciubotariu4ea54e32015-07-24 16:55:27 +03001101);