lan966x_mdb.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. // SPDX-License-Identifier: GPL-2.0+
  2. #include <net/switchdev.h>
  3. #include "lan966x_main.h"
  4. struct lan966x_pgid_entry {
  5. struct list_head list;
  6. int index;
  7. refcount_t refcount;
  8. u16 ports;
  9. };
  10. struct lan966x_mdb_entry {
  11. struct list_head list;
  12. unsigned char mac[ETH_ALEN];
  13. u16 vid;
  14. u16 ports;
  15. struct lan966x_pgid_entry *pgid;
  16. u8 cpu_copy;
  17. };
  18. void lan966x_mdb_init(struct lan966x *lan966x)
  19. {
  20. INIT_LIST_HEAD(&lan966x->mdb_entries);
  21. INIT_LIST_HEAD(&lan966x->pgid_entries);
  22. }
  23. static void lan966x_mdb_purge_mdb_entries(struct lan966x *lan966x)
  24. {
  25. struct lan966x_mdb_entry *mdb_entry, *tmp;
  26. list_for_each_entry_safe(mdb_entry, tmp, &lan966x->mdb_entries, list) {
  27. list_del(&mdb_entry->list);
  28. kfree(mdb_entry);
  29. }
  30. }
  31. static void lan966x_mdb_purge_pgid_entries(struct lan966x *lan966x)
  32. {
  33. struct lan966x_pgid_entry *pgid_entry, *tmp;
  34. list_for_each_entry_safe(pgid_entry, tmp, &lan966x->pgid_entries, list) {
  35. list_del(&pgid_entry->list);
  36. kfree(pgid_entry);
  37. }
  38. }
  39. void lan966x_mdb_deinit(struct lan966x *lan966x)
  40. {
  41. lan966x_mdb_purge_mdb_entries(lan966x);
  42. lan966x_mdb_purge_pgid_entries(lan966x);
  43. }
  44. static struct lan966x_mdb_entry *
  45. lan966x_mdb_entry_get(struct lan966x *lan966x,
  46. const unsigned char *mac,
  47. u16 vid)
  48. {
  49. struct lan966x_mdb_entry *mdb_entry;
  50. list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
  51. if (ether_addr_equal(mdb_entry->mac, mac) &&
  52. mdb_entry->vid == vid)
  53. return mdb_entry;
  54. }
  55. return NULL;
  56. }
  57. static struct lan966x_mdb_entry *
  58. lan966x_mdb_entry_add(struct lan966x *lan966x,
  59. const struct switchdev_obj_port_mdb *mdb)
  60. {
  61. struct lan966x_mdb_entry *mdb_entry;
  62. mdb_entry = kzalloc(sizeof(*mdb_entry), GFP_KERNEL);
  63. if (!mdb_entry)
  64. return ERR_PTR(-ENOMEM);
  65. ether_addr_copy(mdb_entry->mac, mdb->addr);
  66. mdb_entry->vid = mdb->vid;
  67. list_add_tail(&mdb_entry->list, &lan966x->mdb_entries);
  68. return mdb_entry;
  69. }
  70. static void lan966x_mdb_encode_mac(unsigned char *mac,
  71. struct lan966x_mdb_entry *mdb_entry,
  72. enum macaccess_entry_type type)
  73. {
  74. ether_addr_copy(mac, mdb_entry->mac);
  75. if (type == ENTRYTYPE_MACV4) {
  76. mac[0] = 0;
  77. mac[1] = mdb_entry->ports >> 8;
  78. mac[2] = mdb_entry->ports & 0xff;
  79. } else if (type == ENTRYTYPE_MACV6) {
  80. mac[0] = mdb_entry->ports >> 8;
  81. mac[1] = mdb_entry->ports & 0xff;
  82. }
  83. }
  84. static int lan966x_mdb_ip_add(struct lan966x_port *port,
  85. const struct switchdev_obj_port_mdb *mdb,
  86. enum macaccess_entry_type type)
  87. {
  88. bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
  89. struct lan966x *lan966x = port->lan966x;
  90. struct lan966x_mdb_entry *mdb_entry;
  91. unsigned char mac[ETH_ALEN];
  92. bool cpu_copy = false;
  93. mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
  94. if (!mdb_entry) {
  95. mdb_entry = lan966x_mdb_entry_add(lan966x, mdb);
  96. if (IS_ERR(mdb_entry))
  97. return PTR_ERR(mdb_entry);
  98. } else {
  99. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  100. lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
  101. }
  102. if (cpu_port)
  103. mdb_entry->cpu_copy++;
  104. else
  105. mdb_entry->ports |= BIT(port->chip_port);
  106. /* Copy the frame to CPU only if the CPU is in the VLAN */
  107. if (lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, mdb_entry->vid) &&
  108. mdb_entry->cpu_copy)
  109. cpu_copy = true;
  110. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  111. return lan966x_mac_ip_learn(lan966x, cpu_copy,
  112. mac, mdb_entry->vid, type);
  113. }
  114. static int lan966x_mdb_ip_del(struct lan966x_port *port,
  115. const struct switchdev_obj_port_mdb *mdb,
  116. enum macaccess_entry_type type)
  117. {
  118. bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
  119. struct lan966x *lan966x = port->lan966x;
  120. struct lan966x_mdb_entry *mdb_entry;
  121. unsigned char mac[ETH_ALEN];
  122. u16 ports;
  123. mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
  124. if (!mdb_entry)
  125. return -ENOENT;
  126. ports = mdb_entry->ports;
  127. if (cpu_port) {
  128. /* If there are still other references to the CPU port then
  129. * there is no point to delete and add again the same entry
  130. */
  131. mdb_entry->cpu_copy--;
  132. if (mdb_entry->cpu_copy)
  133. return 0;
  134. } else {
  135. ports &= ~BIT(port->chip_port);
  136. }
  137. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  138. lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
  139. mdb_entry->ports = ports;
  140. if (!mdb_entry->ports && !mdb_entry->cpu_copy) {
  141. list_del(&mdb_entry->list);
  142. kfree(mdb_entry);
  143. return 0;
  144. }
  145. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  146. return lan966x_mac_ip_learn(lan966x, mdb_entry->cpu_copy,
  147. mac, mdb_entry->vid, type);
  148. }
  149. static struct lan966x_pgid_entry *
  150. lan966x_pgid_entry_add(struct lan966x *lan966x, int index, u16 ports)
  151. {
  152. struct lan966x_pgid_entry *pgid_entry;
  153. pgid_entry = kzalloc(sizeof(*pgid_entry), GFP_KERNEL);
  154. if (!pgid_entry)
  155. return ERR_PTR(-ENOMEM);
  156. pgid_entry->ports = ports;
  157. pgid_entry->index = index;
  158. refcount_set(&pgid_entry->refcount, 1);
  159. list_add_tail(&pgid_entry->list, &lan966x->pgid_entries);
  160. return pgid_entry;
  161. }
  162. static struct lan966x_pgid_entry *
  163. lan966x_pgid_entry_get(struct lan966x *lan966x,
  164. struct lan966x_mdb_entry *mdb_entry)
  165. {
  166. struct lan966x_pgid_entry *pgid_entry;
  167. int index;
  168. /* Try to find an existing pgid that uses the same ports as the
  169. * mdb_entry
  170. */
  171. list_for_each_entry(pgid_entry, &lan966x->pgid_entries, list) {
  172. if (pgid_entry->ports == mdb_entry->ports) {
  173. refcount_inc(&pgid_entry->refcount);
  174. return pgid_entry;
  175. }
  176. }
  177. /* Try to find an empty pgid entry and allocate one in case it finds it,
  178. * otherwise it means that there are no more resources
  179. */
  180. for (index = PGID_GP_START; index < PGID_GP_END; index++) {
  181. bool used = false;
  182. list_for_each_entry(pgid_entry, &lan966x->pgid_entries, list) {
  183. if (pgid_entry->index == index) {
  184. used = true;
  185. break;
  186. }
  187. }
  188. if (!used)
  189. return lan966x_pgid_entry_add(lan966x, index,
  190. mdb_entry->ports);
  191. }
  192. return ERR_PTR(-ENOSPC);
  193. }
  194. static void lan966x_pgid_entry_del(struct lan966x *lan966x,
  195. struct lan966x_pgid_entry *pgid_entry)
  196. {
  197. if (!refcount_dec_and_test(&pgid_entry->refcount))
  198. return;
  199. list_del(&pgid_entry->list);
  200. kfree(pgid_entry);
  201. }
  202. static int lan966x_mdb_l2_add(struct lan966x_port *port,
  203. const struct switchdev_obj_port_mdb *mdb,
  204. enum macaccess_entry_type type)
  205. {
  206. bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
  207. struct lan966x *lan966x = port->lan966x;
  208. struct lan966x_pgid_entry *pgid_entry;
  209. struct lan966x_mdb_entry *mdb_entry;
  210. unsigned char mac[ETH_ALEN];
  211. mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
  212. if (!mdb_entry) {
  213. mdb_entry = lan966x_mdb_entry_add(lan966x, mdb);
  214. if (IS_ERR(mdb_entry))
  215. return PTR_ERR(mdb_entry);
  216. } else {
  217. lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
  218. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  219. lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
  220. }
  221. if (cpu_port) {
  222. mdb_entry->ports |= BIT(CPU_PORT);
  223. mdb_entry->cpu_copy++;
  224. } else {
  225. mdb_entry->ports |= BIT(port->chip_port);
  226. }
  227. pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
  228. if (IS_ERR(pgid_entry)) {
  229. list_del(&mdb_entry->list);
  230. kfree(mdb_entry);
  231. return PTR_ERR(pgid_entry);
  232. }
  233. mdb_entry->pgid = pgid_entry;
  234. /* Copy the frame to CPU only if the CPU is in the VLAN */
  235. if (!lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, mdb_entry->vid) &&
  236. mdb_entry->cpu_copy)
  237. mdb_entry->ports &= BIT(CPU_PORT);
  238. lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
  239. ANA_PGID_PGID,
  240. lan966x, ANA_PGID(pgid_entry->index));
  241. return lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
  242. mdb_entry->vid, type);
  243. }
  244. static int lan966x_mdb_l2_del(struct lan966x_port *port,
  245. const struct switchdev_obj_port_mdb *mdb,
  246. enum macaccess_entry_type type)
  247. {
  248. bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
  249. struct lan966x *lan966x = port->lan966x;
  250. struct lan966x_pgid_entry *pgid_entry;
  251. struct lan966x_mdb_entry *mdb_entry;
  252. unsigned char mac[ETH_ALEN];
  253. u16 ports;
  254. mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
  255. if (!mdb_entry)
  256. return -ENOENT;
  257. ports = mdb_entry->ports;
  258. if (cpu_port) {
  259. /* If there are still other references to the CPU port then
  260. * there is no point to delete and add again the same entry
  261. */
  262. mdb_entry->cpu_copy--;
  263. if (mdb_entry->cpu_copy)
  264. return 0;
  265. ports &= ~BIT(CPU_PORT);
  266. } else {
  267. ports &= ~BIT(port->chip_port);
  268. }
  269. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  270. lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
  271. lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
  272. mdb_entry->ports = ports;
  273. if (!mdb_entry->ports) {
  274. list_del(&mdb_entry->list);
  275. kfree(mdb_entry);
  276. return 0;
  277. }
  278. pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
  279. if (IS_ERR(pgid_entry)) {
  280. list_del(&mdb_entry->list);
  281. kfree(mdb_entry);
  282. return PTR_ERR(pgid_entry);
  283. }
  284. mdb_entry->pgid = pgid_entry;
  285. lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
  286. ANA_PGID_PGID,
  287. lan966x, ANA_PGID(pgid_entry->index));
  288. return lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
  289. mdb_entry->vid, type);
  290. }
  291. static enum macaccess_entry_type
  292. lan966x_mdb_classify(const unsigned char *mac)
  293. {
  294. if (mac[0] == 0x01 && mac[1] == 0x00 && mac[2] == 0x5e)
  295. return ENTRYTYPE_MACV4;
  296. if (mac[0] == 0x33 && mac[1] == 0x33)
  297. return ENTRYTYPE_MACV6;
  298. return ENTRYTYPE_LOCKED;
  299. }
  300. int lan966x_handle_port_mdb_add(struct lan966x_port *port,
  301. const struct switchdev_obj *obj)
  302. {
  303. const struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
  304. enum macaccess_entry_type type;
  305. /* Split the way the entries are added for ipv4/ipv6 and for l2. The
  306. * reason is that for ipv4/ipv6 it doesn't require to use any pgid
  307. * entry, while for l2 is required to use pgid entries
  308. */
  309. type = lan966x_mdb_classify(mdb->addr);
  310. if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
  311. return lan966x_mdb_ip_add(port, mdb, type);
  312. return lan966x_mdb_l2_add(port, mdb, type);
  313. }
  314. int lan966x_handle_port_mdb_del(struct lan966x_port *port,
  315. const struct switchdev_obj *obj)
  316. {
  317. const struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
  318. enum macaccess_entry_type type;
  319. /* Split the way the entries are removed for ipv4/ipv6 and for l2. The
  320. * reason is that for ipv4/ipv6 it doesn't require to use any pgid
  321. * entry, while for l2 is required to use pgid entries
  322. */
  323. type = lan966x_mdb_classify(mdb->addr);
  324. if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
  325. return lan966x_mdb_ip_del(port, mdb, type);
  326. return lan966x_mdb_l2_del(port, mdb, type);
  327. }
  328. static void lan966x_mdb_ip_cpu_copy(struct lan966x *lan966x,
  329. struct lan966x_mdb_entry *mdb_entry,
  330. enum macaccess_entry_type type)
  331. {
  332. unsigned char mac[ETH_ALEN];
  333. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  334. lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
  335. lan966x_mac_ip_learn(lan966x, true, mac, mdb_entry->vid, type);
  336. }
  337. static void lan966x_mdb_l2_cpu_copy(struct lan966x *lan966x,
  338. struct lan966x_mdb_entry *mdb_entry,
  339. enum macaccess_entry_type type)
  340. {
  341. struct lan966x_pgid_entry *pgid_entry;
  342. unsigned char mac[ETH_ALEN];
  343. lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
  344. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  345. lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
  346. mdb_entry->ports |= BIT(CPU_PORT);
  347. pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
  348. if (IS_ERR(pgid_entry))
  349. return;
  350. mdb_entry->pgid = pgid_entry;
  351. lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
  352. ANA_PGID_PGID,
  353. lan966x, ANA_PGID(pgid_entry->index));
  354. lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
  355. mdb_entry->vid, type);
  356. }
  357. void lan966x_mdb_write_entries(struct lan966x *lan966x, u16 vid)
  358. {
  359. struct lan966x_mdb_entry *mdb_entry;
  360. enum macaccess_entry_type type;
  361. list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
  362. if (mdb_entry->vid != vid || !mdb_entry->cpu_copy)
  363. continue;
  364. type = lan966x_mdb_classify(mdb_entry->mac);
  365. if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
  366. lan966x_mdb_ip_cpu_copy(lan966x, mdb_entry, type);
  367. else
  368. lan966x_mdb_l2_cpu_copy(lan966x, mdb_entry, type);
  369. }
  370. }
  371. static void lan966x_mdb_ip_cpu_remove(struct lan966x *lan966x,
  372. struct lan966x_mdb_entry *mdb_entry,
  373. enum macaccess_entry_type type)
  374. {
  375. unsigned char mac[ETH_ALEN];
  376. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  377. lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
  378. lan966x_mac_ip_learn(lan966x, false, mac, mdb_entry->vid, type);
  379. }
  380. static void lan966x_mdb_l2_cpu_remove(struct lan966x *lan966x,
  381. struct lan966x_mdb_entry *mdb_entry,
  382. enum macaccess_entry_type type)
  383. {
  384. struct lan966x_pgid_entry *pgid_entry;
  385. unsigned char mac[ETH_ALEN];
  386. lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
  387. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  388. lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
  389. mdb_entry->ports &= ~BIT(CPU_PORT);
  390. pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
  391. if (IS_ERR(pgid_entry))
  392. return;
  393. mdb_entry->pgid = pgid_entry;
  394. lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
  395. ANA_PGID_PGID,
  396. lan966x, ANA_PGID(pgid_entry->index));
  397. lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
  398. mdb_entry->vid, type);
  399. }
  400. void lan966x_mdb_erase_entries(struct lan966x *lan966x, u16 vid)
  401. {
  402. struct lan966x_mdb_entry *mdb_entry;
  403. enum macaccess_entry_type type;
  404. list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
  405. if (mdb_entry->vid != vid || !mdb_entry->cpu_copy)
  406. continue;
  407. type = lan966x_mdb_classify(mdb_entry->mac);
  408. if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
  409. lan966x_mdb_ip_cpu_remove(lan966x, mdb_entry, type);
  410. else
  411. lan966x_mdb_l2_cpu_remove(lan966x, mdb_entry, type);
  412. }
  413. }
  414. void lan966x_mdb_clear_entries(struct lan966x *lan966x)
  415. {
  416. struct lan966x_mdb_entry *mdb_entry;
  417. enum macaccess_entry_type type;
  418. unsigned char mac[ETH_ALEN];
  419. list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
  420. type = lan966x_mdb_classify(mdb_entry->mac);
  421. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  422. /* Remove just the MAC entry, still keep the PGID in case of L2
  423. * entries because this can be restored at later point
  424. */
  425. lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
  426. }
  427. }
  428. void lan966x_mdb_restore_entries(struct lan966x *lan966x)
  429. {
  430. struct lan966x_mdb_entry *mdb_entry;
  431. enum macaccess_entry_type type;
  432. unsigned char mac[ETH_ALEN];
  433. bool cpu_copy = false;
  434. list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
  435. type = lan966x_mdb_classify(mdb_entry->mac);
  436. lan966x_mdb_encode_mac(mac, mdb_entry, type);
  437. if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6) {
  438. /* Copy the frame to CPU only if the CPU is in the VLAN */
  439. if (lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x,
  440. mdb_entry->vid) &&
  441. mdb_entry->cpu_copy)
  442. cpu_copy = true;
  443. lan966x_mac_ip_learn(lan966x, cpu_copy, mac,
  444. mdb_entry->vid, type);
  445. } else {
  446. lan966x_mac_learn(lan966x, mdb_entry->pgid->index,
  447. mdb_entry->mac,
  448. mdb_entry->vid, type);
  449. }
  450. }
  451. }