cmd_ethsw.c 25 KB

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