ethsw.c 27 KB

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