spectrum_router.c 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030
  1. /*
  2. * drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
  3. * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
  4. * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
  5. * Copyright (c) 2016 Ido Schimmel <idosch@mellanox.com>
  6. * Copyright (c) 2016 Yotam Gigi <yotamg@mellanox.com>
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the names of the copyright holders nor the names of its
  17. * contributors may be used to endorse or promote products derived from
  18. * this software without specific prior written permission.
  19. *
  20. * Alternatively, this software may be distributed under the terms of the
  21. * GNU General Public License ("GPL") version 2 as published by the Free
  22. * Software Foundation.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  25. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  28. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  29. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  30. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  31. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  32. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  33. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  34. * POSSIBILITY OF SUCH DAMAGE.
  35. */
  36. #include <linux/kernel.h>
  37. #include <linux/types.h>
  38. #include <linux/rhashtable.h>
  39. #include <linux/bitops.h>
  40. #include <linux/in6.h>
  41. #include <linux/notifier.h>
  42. #include <net/netevent.h>
  43. #include <net/neighbour.h>
  44. #include <net/arp.h>
  45. #include <net/ip_fib.h>
  46. #include "spectrum.h"
  47. #include "core.h"
  48. #include "reg.h"
  49. #define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \
  50. for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
  51. static bool
  52. mlxsw_sp_prefix_usage_subset(struct mlxsw_sp_prefix_usage *prefix_usage1,
  53. struct mlxsw_sp_prefix_usage *prefix_usage2)
  54. {
  55. unsigned char prefix;
  56. mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage1) {
  57. if (!test_bit(prefix, prefix_usage2->b))
  58. return false;
  59. }
  60. return true;
  61. }
  62. static bool
  63. mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage *prefix_usage1,
  64. struct mlxsw_sp_prefix_usage *prefix_usage2)
  65. {
  66. return !memcmp(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1));
  67. }
  68. static bool
  69. mlxsw_sp_prefix_usage_none(struct mlxsw_sp_prefix_usage *prefix_usage)
  70. {
  71. struct mlxsw_sp_prefix_usage prefix_usage_none = {{ 0 } };
  72. return mlxsw_sp_prefix_usage_eq(prefix_usage, &prefix_usage_none);
  73. }
  74. static void
  75. mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage *prefix_usage1,
  76. struct mlxsw_sp_prefix_usage *prefix_usage2)
  77. {
  78. memcpy(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1));
  79. }
  80. static void
  81. mlxsw_sp_prefix_usage_zero(struct mlxsw_sp_prefix_usage *prefix_usage)
  82. {
  83. memset(prefix_usage, 0, sizeof(*prefix_usage));
  84. }
  85. static void
  86. mlxsw_sp_prefix_usage_set(struct mlxsw_sp_prefix_usage *prefix_usage,
  87. unsigned char prefix_len)
  88. {
  89. set_bit(prefix_len, prefix_usage->b);
  90. }
  91. static void
  92. mlxsw_sp_prefix_usage_clear(struct mlxsw_sp_prefix_usage *prefix_usage,
  93. unsigned char prefix_len)
  94. {
  95. clear_bit(prefix_len, prefix_usage->b);
  96. }
  97. struct mlxsw_sp_fib_key {
  98. struct net_device *dev;
  99. unsigned char addr[sizeof(struct in6_addr)];
  100. unsigned char prefix_len;
  101. };
  102. enum mlxsw_sp_fib_entry_type {
  103. MLXSW_SP_FIB_ENTRY_TYPE_REMOTE,
  104. MLXSW_SP_FIB_ENTRY_TYPE_LOCAL,
  105. MLXSW_SP_FIB_ENTRY_TYPE_TRAP,
  106. };
  107. struct mlxsw_sp_nexthop_group;
  108. struct mlxsw_sp_fib_entry {
  109. struct rhash_head ht_node;
  110. struct list_head list;
  111. struct mlxsw_sp_fib_key key;
  112. enum mlxsw_sp_fib_entry_type type;
  113. unsigned int ref_count;
  114. u16 rif; /* used for action local */
  115. struct mlxsw_sp_vr *vr;
  116. struct fib_info *fi;
  117. struct list_head nexthop_group_node;
  118. struct mlxsw_sp_nexthop_group *nh_group;
  119. };
  120. struct mlxsw_sp_fib {
  121. struct rhashtable ht;
  122. struct list_head entry_list;
  123. unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT];
  124. struct mlxsw_sp_prefix_usage prefix_usage;
  125. };
  126. static const struct rhashtable_params mlxsw_sp_fib_ht_params = {
  127. .key_offset = offsetof(struct mlxsw_sp_fib_entry, key),
  128. .head_offset = offsetof(struct mlxsw_sp_fib_entry, ht_node),
  129. .key_len = sizeof(struct mlxsw_sp_fib_key),
  130. .automatic_shrinking = true,
  131. };
  132. static int mlxsw_sp_fib_entry_insert(struct mlxsw_sp_fib *fib,
  133. struct mlxsw_sp_fib_entry *fib_entry)
  134. {
  135. unsigned char prefix_len = fib_entry->key.prefix_len;
  136. int err;
  137. err = rhashtable_insert_fast(&fib->ht, &fib_entry->ht_node,
  138. mlxsw_sp_fib_ht_params);
  139. if (err)
  140. return err;
  141. list_add_tail(&fib_entry->list, &fib->entry_list);
  142. if (fib->prefix_ref_count[prefix_len]++ == 0)
  143. mlxsw_sp_prefix_usage_set(&fib->prefix_usage, prefix_len);
  144. return 0;
  145. }
  146. static void mlxsw_sp_fib_entry_remove(struct mlxsw_sp_fib *fib,
  147. struct mlxsw_sp_fib_entry *fib_entry)
  148. {
  149. unsigned char prefix_len = fib_entry->key.prefix_len;
  150. if (--fib->prefix_ref_count[prefix_len] == 0)
  151. mlxsw_sp_prefix_usage_clear(&fib->prefix_usage, prefix_len);
  152. list_del(&fib_entry->list);
  153. rhashtable_remove_fast(&fib->ht, &fib_entry->ht_node,
  154. mlxsw_sp_fib_ht_params);
  155. }
  156. static struct mlxsw_sp_fib_entry *
  157. mlxsw_sp_fib_entry_create(struct mlxsw_sp_fib *fib, const void *addr,
  158. size_t addr_len, unsigned char prefix_len,
  159. struct net_device *dev)
  160. {
  161. struct mlxsw_sp_fib_entry *fib_entry;
  162. fib_entry = kzalloc(sizeof(*fib_entry), GFP_KERNEL);
  163. if (!fib_entry)
  164. return NULL;
  165. fib_entry->key.dev = dev;
  166. memcpy(fib_entry->key.addr, addr, addr_len);
  167. fib_entry->key.prefix_len = prefix_len;
  168. return fib_entry;
  169. }
  170. static void mlxsw_sp_fib_entry_destroy(struct mlxsw_sp_fib_entry *fib_entry)
  171. {
  172. kfree(fib_entry);
  173. }
  174. static struct mlxsw_sp_fib_entry *
  175. mlxsw_sp_fib_entry_lookup(struct mlxsw_sp_fib *fib, const void *addr,
  176. size_t addr_len, unsigned char prefix_len,
  177. struct net_device *dev)
  178. {
  179. struct mlxsw_sp_fib_key key;
  180. memset(&key, 0, sizeof(key));
  181. key.dev = dev;
  182. memcpy(key.addr, addr, addr_len);
  183. key.prefix_len = prefix_len;
  184. return rhashtable_lookup_fast(&fib->ht, &key, mlxsw_sp_fib_ht_params);
  185. }
  186. static struct mlxsw_sp_fib *mlxsw_sp_fib_create(void)
  187. {
  188. struct mlxsw_sp_fib *fib;
  189. int err;
  190. fib = kzalloc(sizeof(*fib), GFP_KERNEL);
  191. if (!fib)
  192. return ERR_PTR(-ENOMEM);
  193. err = rhashtable_init(&fib->ht, &mlxsw_sp_fib_ht_params);
  194. if (err)
  195. goto err_rhashtable_init;
  196. INIT_LIST_HEAD(&fib->entry_list);
  197. return fib;
  198. err_rhashtable_init:
  199. kfree(fib);
  200. return ERR_PTR(err);
  201. }
  202. static void mlxsw_sp_fib_destroy(struct mlxsw_sp_fib *fib)
  203. {
  204. rhashtable_destroy(&fib->ht);
  205. kfree(fib);
  206. }
  207. static struct mlxsw_sp_lpm_tree *
  208. mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp, bool one_reserved)
  209. {
  210. static struct mlxsw_sp_lpm_tree *lpm_tree;
  211. int i;
  212. for (i = 0; i < MLXSW_SP_LPM_TREE_COUNT; i++) {
  213. lpm_tree = &mlxsw_sp->router.lpm_trees[i];
  214. if (lpm_tree->ref_count == 0) {
  215. if (one_reserved)
  216. one_reserved = false;
  217. else
  218. return lpm_tree;
  219. }
  220. }
  221. return NULL;
  222. }
  223. static int mlxsw_sp_lpm_tree_alloc(struct mlxsw_sp *mlxsw_sp,
  224. struct mlxsw_sp_lpm_tree *lpm_tree)
  225. {
  226. char ralta_pl[MLXSW_REG_RALTA_LEN];
  227. mlxsw_reg_ralta_pack(ralta_pl, true,
  228. (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
  229. lpm_tree->id);
  230. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
  231. }
  232. static int mlxsw_sp_lpm_tree_free(struct mlxsw_sp *mlxsw_sp,
  233. struct mlxsw_sp_lpm_tree *lpm_tree)
  234. {
  235. char ralta_pl[MLXSW_REG_RALTA_LEN];
  236. mlxsw_reg_ralta_pack(ralta_pl, false,
  237. (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
  238. lpm_tree->id);
  239. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
  240. }
  241. static int
  242. mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp *mlxsw_sp,
  243. struct mlxsw_sp_prefix_usage *prefix_usage,
  244. struct mlxsw_sp_lpm_tree *lpm_tree)
  245. {
  246. char ralst_pl[MLXSW_REG_RALST_LEN];
  247. u8 root_bin = 0;
  248. u8 prefix;
  249. u8 last_prefix = MLXSW_REG_RALST_BIN_NO_CHILD;
  250. mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage)
  251. root_bin = prefix;
  252. mlxsw_reg_ralst_pack(ralst_pl, root_bin, lpm_tree->id);
  253. mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) {
  254. if (prefix == 0)
  255. continue;
  256. mlxsw_reg_ralst_bin_pack(ralst_pl, prefix, last_prefix,
  257. MLXSW_REG_RALST_BIN_NO_CHILD);
  258. last_prefix = prefix;
  259. }
  260. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl);
  261. }
  262. static struct mlxsw_sp_lpm_tree *
  263. mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
  264. struct mlxsw_sp_prefix_usage *prefix_usage,
  265. enum mlxsw_sp_l3proto proto, bool one_reserved)
  266. {
  267. struct mlxsw_sp_lpm_tree *lpm_tree;
  268. int err;
  269. lpm_tree = mlxsw_sp_lpm_tree_find_unused(mlxsw_sp, one_reserved);
  270. if (!lpm_tree)
  271. return ERR_PTR(-EBUSY);
  272. lpm_tree->proto = proto;
  273. err = mlxsw_sp_lpm_tree_alloc(mlxsw_sp, lpm_tree);
  274. if (err)
  275. return ERR_PTR(err);
  276. err = mlxsw_sp_lpm_tree_left_struct_set(mlxsw_sp, prefix_usage,
  277. lpm_tree);
  278. if (err)
  279. goto err_left_struct_set;
  280. memcpy(&lpm_tree->prefix_usage, prefix_usage,
  281. sizeof(lpm_tree->prefix_usage));
  282. return lpm_tree;
  283. err_left_struct_set:
  284. mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
  285. return ERR_PTR(err);
  286. }
  287. static int mlxsw_sp_lpm_tree_destroy(struct mlxsw_sp *mlxsw_sp,
  288. struct mlxsw_sp_lpm_tree *lpm_tree)
  289. {
  290. return mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
  291. }
  292. static struct mlxsw_sp_lpm_tree *
  293. mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
  294. struct mlxsw_sp_prefix_usage *prefix_usage,
  295. enum mlxsw_sp_l3proto proto, bool one_reserved)
  296. {
  297. struct mlxsw_sp_lpm_tree *lpm_tree;
  298. int i;
  299. for (i = 0; i < MLXSW_SP_LPM_TREE_COUNT; i++) {
  300. lpm_tree = &mlxsw_sp->router.lpm_trees[i];
  301. if (lpm_tree->ref_count != 0 &&
  302. lpm_tree->proto == proto &&
  303. mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage,
  304. prefix_usage))
  305. goto inc_ref_count;
  306. }
  307. lpm_tree = mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage,
  308. proto, one_reserved);
  309. if (IS_ERR(lpm_tree))
  310. return lpm_tree;
  311. inc_ref_count:
  312. lpm_tree->ref_count++;
  313. return lpm_tree;
  314. }
  315. static int mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
  316. struct mlxsw_sp_lpm_tree *lpm_tree)
  317. {
  318. if (--lpm_tree->ref_count == 0)
  319. return mlxsw_sp_lpm_tree_destroy(mlxsw_sp, lpm_tree);
  320. return 0;
  321. }
  322. static void mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
  323. {
  324. struct mlxsw_sp_lpm_tree *lpm_tree;
  325. int i;
  326. for (i = 0; i < MLXSW_SP_LPM_TREE_COUNT; i++) {
  327. lpm_tree = &mlxsw_sp->router.lpm_trees[i];
  328. lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN;
  329. }
  330. }
  331. static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp)
  332. {
  333. struct mlxsw_resources *resources;
  334. struct mlxsw_sp_vr *vr;
  335. int i;
  336. resources = mlxsw_core_resources_get(mlxsw_sp->core);
  337. for (i = 0; i < resources->max_virtual_routers; i++) {
  338. vr = &mlxsw_sp->router.vrs[i];
  339. if (!vr->used)
  340. return vr;
  341. }
  342. return NULL;
  343. }
  344. static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
  345. struct mlxsw_sp_vr *vr)
  346. {
  347. char raltb_pl[MLXSW_REG_RALTB_LEN];
  348. mlxsw_reg_raltb_pack(raltb_pl, vr->id,
  349. (enum mlxsw_reg_ralxx_protocol) vr->proto,
  350. vr->lpm_tree->id);
  351. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
  352. }
  353. static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
  354. struct mlxsw_sp_vr *vr)
  355. {
  356. char raltb_pl[MLXSW_REG_RALTB_LEN];
  357. /* Bind to tree 0 which is default */
  358. mlxsw_reg_raltb_pack(raltb_pl, vr->id,
  359. (enum mlxsw_reg_ralxx_protocol) vr->proto, 0);
  360. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
  361. }
  362. static u32 mlxsw_sp_fix_tb_id(u32 tb_id)
  363. {
  364. /* For our purpose, squash main and local table into one */
  365. if (tb_id == RT_TABLE_LOCAL)
  366. tb_id = RT_TABLE_MAIN;
  367. return tb_id;
  368. }
  369. static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp,
  370. u32 tb_id,
  371. enum mlxsw_sp_l3proto proto)
  372. {
  373. struct mlxsw_resources *resources;
  374. struct mlxsw_sp_vr *vr;
  375. int i;
  376. tb_id = mlxsw_sp_fix_tb_id(tb_id);
  377. resources = mlxsw_core_resources_get(mlxsw_sp->core);
  378. for (i = 0; i < resources->max_virtual_routers; i++) {
  379. vr = &mlxsw_sp->router.vrs[i];
  380. if (vr->used && vr->proto == proto && vr->tb_id == tb_id)
  381. return vr;
  382. }
  383. return NULL;
  384. }
  385. static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
  386. unsigned char prefix_len,
  387. u32 tb_id,
  388. enum mlxsw_sp_l3proto proto)
  389. {
  390. struct mlxsw_sp_prefix_usage req_prefix_usage;
  391. struct mlxsw_sp_lpm_tree *lpm_tree;
  392. struct mlxsw_sp_vr *vr;
  393. int err;
  394. vr = mlxsw_sp_vr_find_unused(mlxsw_sp);
  395. if (!vr)
  396. return ERR_PTR(-EBUSY);
  397. vr->fib = mlxsw_sp_fib_create();
  398. if (IS_ERR(vr->fib))
  399. return ERR_CAST(vr->fib);
  400. vr->proto = proto;
  401. vr->tb_id = tb_id;
  402. mlxsw_sp_prefix_usage_zero(&req_prefix_usage);
  403. mlxsw_sp_prefix_usage_set(&req_prefix_usage, prefix_len);
  404. lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
  405. proto, true);
  406. if (IS_ERR(lpm_tree)) {
  407. err = PTR_ERR(lpm_tree);
  408. goto err_tree_get;
  409. }
  410. vr->lpm_tree = lpm_tree;
  411. err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, vr);
  412. if (err)
  413. goto err_tree_bind;
  414. vr->used = true;
  415. return vr;
  416. err_tree_bind:
  417. mlxsw_sp_lpm_tree_put(mlxsw_sp, vr->lpm_tree);
  418. err_tree_get:
  419. mlxsw_sp_fib_destroy(vr->fib);
  420. return ERR_PTR(err);
  421. }
  422. static void mlxsw_sp_vr_destroy(struct mlxsw_sp *mlxsw_sp,
  423. struct mlxsw_sp_vr *vr)
  424. {
  425. mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, vr);
  426. mlxsw_sp_lpm_tree_put(mlxsw_sp, vr->lpm_tree);
  427. mlxsw_sp_fib_destroy(vr->fib);
  428. vr->used = false;
  429. }
  430. static int
  431. mlxsw_sp_vr_lpm_tree_check(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr,
  432. struct mlxsw_sp_prefix_usage *req_prefix_usage)
  433. {
  434. struct mlxsw_sp_lpm_tree *lpm_tree = vr->lpm_tree;
  435. struct mlxsw_sp_lpm_tree *new_tree;
  436. int err;
  437. if (mlxsw_sp_prefix_usage_eq(req_prefix_usage, &lpm_tree->prefix_usage))
  438. return 0;
  439. new_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, req_prefix_usage,
  440. vr->proto, false);
  441. if (IS_ERR(new_tree)) {
  442. /* We failed to get a tree according to the required
  443. * prefix usage. However, the current tree might be still good
  444. * for us if our requirement is subset of the prefixes used
  445. * in the tree.
  446. */
  447. if (mlxsw_sp_prefix_usage_subset(req_prefix_usage,
  448. &lpm_tree->prefix_usage))
  449. return 0;
  450. return PTR_ERR(new_tree);
  451. }
  452. /* Prevent packet loss by overwriting existing binding */
  453. vr->lpm_tree = new_tree;
  454. err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, vr);
  455. if (err)
  456. goto err_tree_bind;
  457. mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
  458. return 0;
  459. err_tree_bind:
  460. vr->lpm_tree = lpm_tree;
  461. mlxsw_sp_lpm_tree_put(mlxsw_sp, new_tree);
  462. return err;
  463. }
  464. static struct mlxsw_sp_vr *mlxsw_sp_vr_get(struct mlxsw_sp *mlxsw_sp,
  465. unsigned char prefix_len,
  466. u32 tb_id,
  467. enum mlxsw_sp_l3proto proto)
  468. {
  469. struct mlxsw_sp_vr *vr;
  470. int err;
  471. tb_id = mlxsw_sp_fix_tb_id(tb_id);
  472. vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id, proto);
  473. if (!vr) {
  474. vr = mlxsw_sp_vr_create(mlxsw_sp, prefix_len, tb_id, proto);
  475. if (IS_ERR(vr))
  476. return vr;
  477. } else {
  478. struct mlxsw_sp_prefix_usage req_prefix_usage;
  479. mlxsw_sp_prefix_usage_cpy(&req_prefix_usage,
  480. &vr->fib->prefix_usage);
  481. mlxsw_sp_prefix_usage_set(&req_prefix_usage, prefix_len);
  482. /* Need to replace LPM tree in case new prefix is required. */
  483. err = mlxsw_sp_vr_lpm_tree_check(mlxsw_sp, vr,
  484. &req_prefix_usage);
  485. if (err)
  486. return ERR_PTR(err);
  487. }
  488. return vr;
  489. }
  490. static void mlxsw_sp_vr_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr)
  491. {
  492. /* Destroy virtual router entity in case the associated FIB is empty
  493. * and allow it to be used for other tables in future. Otherwise,
  494. * check if some prefix usage did not disappear and change tree if
  495. * that is the case. Note that in case new, smaller tree cannot be
  496. * allocated, the original one will be kept being used.
  497. */
  498. if (mlxsw_sp_prefix_usage_none(&vr->fib->prefix_usage))
  499. mlxsw_sp_vr_destroy(mlxsw_sp, vr);
  500. else
  501. mlxsw_sp_vr_lpm_tree_check(mlxsw_sp, vr,
  502. &vr->fib->prefix_usage);
  503. }
  504. static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
  505. {
  506. struct mlxsw_resources *resources;
  507. struct mlxsw_sp_vr *vr;
  508. int i;
  509. resources = mlxsw_core_resources_get(mlxsw_sp->core);
  510. if (!resources->max_virtual_routers_valid)
  511. return -EIO;
  512. mlxsw_sp->router.vrs = kcalloc(resources->max_virtual_routers,
  513. sizeof(struct mlxsw_sp_vr),
  514. GFP_KERNEL);
  515. if (!mlxsw_sp->router.vrs)
  516. return -ENOMEM;
  517. for (i = 0; i < resources->max_virtual_routers; i++) {
  518. vr = &mlxsw_sp->router.vrs[i];
  519. vr->id = i;
  520. }
  521. return 0;
  522. }
  523. static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp);
  524. static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp)
  525. {
  526. mlxsw_sp_router_fib_flush(mlxsw_sp);
  527. kfree(mlxsw_sp->router.vrs);
  528. }
  529. struct mlxsw_sp_neigh_key {
  530. struct neighbour *n;
  531. };
  532. struct mlxsw_sp_neigh_entry {
  533. struct rhash_head ht_node;
  534. struct mlxsw_sp_neigh_key key;
  535. u16 rif;
  536. bool offloaded;
  537. struct delayed_work dw;
  538. struct mlxsw_sp_port *mlxsw_sp_port;
  539. unsigned char ha[ETH_ALEN];
  540. struct list_head nexthop_list; /* list of nexthops using
  541. * this neigh entry
  542. */
  543. struct list_head nexthop_neighs_list_node;
  544. };
  545. static const struct rhashtable_params mlxsw_sp_neigh_ht_params = {
  546. .key_offset = offsetof(struct mlxsw_sp_neigh_entry, key),
  547. .head_offset = offsetof(struct mlxsw_sp_neigh_entry, ht_node),
  548. .key_len = sizeof(struct mlxsw_sp_neigh_key),
  549. };
  550. static int
  551. mlxsw_sp_neigh_entry_insert(struct mlxsw_sp *mlxsw_sp,
  552. struct mlxsw_sp_neigh_entry *neigh_entry)
  553. {
  554. return rhashtable_insert_fast(&mlxsw_sp->router.neigh_ht,
  555. &neigh_entry->ht_node,
  556. mlxsw_sp_neigh_ht_params);
  557. }
  558. static void
  559. mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp,
  560. struct mlxsw_sp_neigh_entry *neigh_entry)
  561. {
  562. rhashtable_remove_fast(&mlxsw_sp->router.neigh_ht,
  563. &neigh_entry->ht_node,
  564. mlxsw_sp_neigh_ht_params);
  565. }
  566. static void mlxsw_sp_router_neigh_update_hw(struct work_struct *work);
  567. static struct mlxsw_sp_neigh_entry *
  568. mlxsw_sp_neigh_entry_create(struct neighbour *n, u16 rif)
  569. {
  570. struct mlxsw_sp_neigh_entry *neigh_entry;
  571. neigh_entry = kzalloc(sizeof(*neigh_entry), GFP_ATOMIC);
  572. if (!neigh_entry)
  573. return NULL;
  574. neigh_entry->key.n = n;
  575. neigh_entry->rif = rif;
  576. INIT_DELAYED_WORK(&neigh_entry->dw, mlxsw_sp_router_neigh_update_hw);
  577. INIT_LIST_HEAD(&neigh_entry->nexthop_list);
  578. return neigh_entry;
  579. }
  580. static void
  581. mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp_neigh_entry *neigh_entry)
  582. {
  583. kfree(neigh_entry);
  584. }
  585. static struct mlxsw_sp_neigh_entry *
  586. mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
  587. {
  588. struct mlxsw_sp_neigh_key key;
  589. key.n = n;
  590. return rhashtable_lookup_fast(&mlxsw_sp->router.neigh_ht,
  591. &key, mlxsw_sp_neigh_ht_params);
  592. }
  593. int mlxsw_sp_router_neigh_construct(struct net_device *dev,
  594. struct neighbour *n)
  595. {
  596. struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
  597. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  598. struct mlxsw_sp_neigh_entry *neigh_entry;
  599. struct mlxsw_sp_rif *r;
  600. int err;
  601. if (n->tbl != &arp_tbl)
  602. return 0;
  603. neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
  604. if (neigh_entry)
  605. return 0;
  606. r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, n->dev);
  607. if (WARN_ON(!r))
  608. return -EINVAL;
  609. neigh_entry = mlxsw_sp_neigh_entry_create(n, r->rif);
  610. if (!neigh_entry)
  611. return -ENOMEM;
  612. err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
  613. if (err)
  614. goto err_neigh_entry_insert;
  615. return 0;
  616. err_neigh_entry_insert:
  617. mlxsw_sp_neigh_entry_destroy(neigh_entry);
  618. return err;
  619. }
  620. void mlxsw_sp_router_neigh_destroy(struct net_device *dev,
  621. struct neighbour *n)
  622. {
  623. struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
  624. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  625. struct mlxsw_sp_neigh_entry *neigh_entry;
  626. if (n->tbl != &arp_tbl)
  627. return;
  628. neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
  629. if (!neigh_entry)
  630. return;
  631. mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
  632. mlxsw_sp_neigh_entry_destroy(neigh_entry);
  633. }
  634. static void
  635. mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp *mlxsw_sp)
  636. {
  637. unsigned long interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME);
  638. mlxsw_sp->router.neighs_update.interval = jiffies_to_msecs(interval);
  639. }
  640. static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
  641. char *rauhtd_pl,
  642. int ent_index)
  643. {
  644. struct net_device *dev;
  645. struct neighbour *n;
  646. __be32 dipn;
  647. u32 dip;
  648. u16 rif;
  649. mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip);
  650. if (!mlxsw_sp->rifs[rif]) {
  651. dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
  652. return;
  653. }
  654. dipn = htonl(dip);
  655. dev = mlxsw_sp->rifs[rif]->dev;
  656. n = neigh_lookup(&arp_tbl, &dipn, dev);
  657. if (!n)
  658. return;
  659. netdev_dbg(dev, "Updating neighbour with IP=%pI4h\n", &dip);
  660. neigh_event_send(n, NULL);
  661. neigh_release(n);
  662. }
  663. static void mlxsw_sp_router_neigh_rec_ipv4_process(struct mlxsw_sp *mlxsw_sp,
  664. char *rauhtd_pl,
  665. int rec_index)
  666. {
  667. u8 num_entries;
  668. int i;
  669. num_entries = mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl,
  670. rec_index);
  671. /* Hardware starts counting at 0, so add 1. */
  672. num_entries++;
  673. /* Each record consists of several neighbour entries. */
  674. for (i = 0; i < num_entries; i++) {
  675. int ent_index;
  676. ent_index = rec_index * MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC + i;
  677. mlxsw_sp_router_neigh_ent_ipv4_process(mlxsw_sp, rauhtd_pl,
  678. ent_index);
  679. }
  680. }
  681. static void mlxsw_sp_router_neigh_rec_process(struct mlxsw_sp *mlxsw_sp,
  682. char *rauhtd_pl, int rec_index)
  683. {
  684. switch (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl, rec_index)) {
  685. case MLXSW_REG_RAUHTD_TYPE_IPV4:
  686. mlxsw_sp_router_neigh_rec_ipv4_process(mlxsw_sp, rauhtd_pl,
  687. rec_index);
  688. break;
  689. case MLXSW_REG_RAUHTD_TYPE_IPV6:
  690. WARN_ON_ONCE(1);
  691. break;
  692. }
  693. }
  694. static bool mlxsw_sp_router_rauhtd_is_full(char *rauhtd_pl)
  695. {
  696. u8 num_rec, last_rec_index, num_entries;
  697. num_rec = mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl);
  698. last_rec_index = num_rec - 1;
  699. if (num_rec < MLXSW_REG_RAUHTD_REC_MAX_NUM)
  700. return false;
  701. if (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl, last_rec_index) ==
  702. MLXSW_REG_RAUHTD_TYPE_IPV6)
  703. return true;
  704. num_entries = mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl,
  705. last_rec_index);
  706. if (++num_entries == MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC)
  707. return true;
  708. return false;
  709. }
  710. static int mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp)
  711. {
  712. char *rauhtd_pl;
  713. u8 num_rec;
  714. int i, err;
  715. rauhtd_pl = kmalloc(MLXSW_REG_RAUHTD_LEN, GFP_KERNEL);
  716. if (!rauhtd_pl)
  717. return -ENOMEM;
  718. /* Make sure the neighbour's netdev isn't removed in the
  719. * process.
  720. */
  721. rtnl_lock();
  722. do {
  723. mlxsw_reg_rauhtd_pack(rauhtd_pl, MLXSW_REG_RAUHTD_TYPE_IPV4);
  724. err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(rauhtd),
  725. rauhtd_pl);
  726. if (err) {
  727. dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to dump neighbour talbe\n");
  728. break;
  729. }
  730. num_rec = mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl);
  731. for (i = 0; i < num_rec; i++)
  732. mlxsw_sp_router_neigh_rec_process(mlxsw_sp, rauhtd_pl,
  733. i);
  734. } while (mlxsw_sp_router_rauhtd_is_full(rauhtd_pl));
  735. rtnl_unlock();
  736. kfree(rauhtd_pl);
  737. return err;
  738. }
  739. static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp)
  740. {
  741. struct mlxsw_sp_neigh_entry *neigh_entry;
  742. /* Take RTNL mutex here to prevent lists from changes */
  743. rtnl_lock();
  744. list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list,
  745. nexthop_neighs_list_node) {
  746. /* If this neigh have nexthops, make the kernel think this neigh
  747. * is active regardless of the traffic.
  748. */
  749. if (!list_empty(&neigh_entry->nexthop_list))
  750. neigh_event_send(neigh_entry->key.n, NULL);
  751. }
  752. rtnl_unlock();
  753. }
  754. static void
  755. mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp *mlxsw_sp)
  756. {
  757. unsigned long interval = mlxsw_sp->router.neighs_update.interval;
  758. mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw,
  759. msecs_to_jiffies(interval));
  760. }
  761. static void mlxsw_sp_router_neighs_update_work(struct work_struct *work)
  762. {
  763. struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp,
  764. router.neighs_update.dw.work);
  765. int err;
  766. err = mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp);
  767. if (err)
  768. dev_err(mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity");
  769. mlxsw_sp_router_neighs_update_nh(mlxsw_sp);
  770. mlxsw_sp_router_neighs_update_work_schedule(mlxsw_sp);
  771. }
  772. static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work)
  773. {
  774. struct mlxsw_sp_neigh_entry *neigh_entry;
  775. struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp,
  776. router.nexthop_probe_dw.work);
  777. /* Iterate over nexthop neighbours, find those who are unresolved and
  778. * send arp on them. This solves the chicken-egg problem when
  779. * the nexthop wouldn't get offloaded until the neighbor is resolved
  780. * but it wouldn't get resolved ever in case traffic is flowing in HW
  781. * using different nexthop.
  782. *
  783. * Take RTNL mutex here to prevent lists from changes.
  784. */
  785. rtnl_lock();
  786. list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list,
  787. nexthop_neighs_list_node) {
  788. if (!(neigh_entry->key.n->nud_state & NUD_VALID) &&
  789. !list_empty(&neigh_entry->nexthop_list))
  790. neigh_event_send(neigh_entry->key.n, NULL);
  791. }
  792. rtnl_unlock();
  793. mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw,
  794. MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL);
  795. }
  796. static void
  797. mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
  798. struct mlxsw_sp_neigh_entry *neigh_entry,
  799. bool removing);
  800. static void mlxsw_sp_router_neigh_update_hw(struct work_struct *work)
  801. {
  802. struct mlxsw_sp_neigh_entry *neigh_entry =
  803. container_of(work, struct mlxsw_sp_neigh_entry, dw.work);
  804. struct neighbour *n = neigh_entry->key.n;
  805. struct mlxsw_sp_port *mlxsw_sp_port = neigh_entry->mlxsw_sp_port;
  806. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  807. char rauht_pl[MLXSW_REG_RAUHT_LEN];
  808. struct net_device *dev;
  809. bool entry_connected;
  810. u8 nud_state;
  811. bool updating;
  812. bool removing;
  813. bool adding;
  814. u32 dip;
  815. int err;
  816. read_lock_bh(&n->lock);
  817. dip = ntohl(*((__be32 *) n->primary_key));
  818. memcpy(neigh_entry->ha, n->ha, sizeof(neigh_entry->ha));
  819. nud_state = n->nud_state;
  820. dev = n->dev;
  821. read_unlock_bh(&n->lock);
  822. entry_connected = nud_state & NUD_VALID;
  823. adding = (!neigh_entry->offloaded) && entry_connected;
  824. updating = neigh_entry->offloaded && entry_connected;
  825. removing = neigh_entry->offloaded && !entry_connected;
  826. if (adding || updating) {
  827. mlxsw_reg_rauht_pack4(rauht_pl, MLXSW_REG_RAUHT_OP_WRITE_ADD,
  828. neigh_entry->rif,
  829. neigh_entry->ha, dip);
  830. err = mlxsw_reg_write(mlxsw_sp->core,
  831. MLXSW_REG(rauht), rauht_pl);
  832. if (err) {
  833. netdev_err(dev, "Could not add neigh %pI4h\n", &dip);
  834. neigh_entry->offloaded = false;
  835. } else {
  836. neigh_entry->offloaded = true;
  837. }
  838. mlxsw_sp_nexthop_neigh_update(mlxsw_sp, neigh_entry, false);
  839. } else if (removing) {
  840. mlxsw_reg_rauht_pack4(rauht_pl, MLXSW_REG_RAUHT_OP_WRITE_DELETE,
  841. neigh_entry->rif,
  842. neigh_entry->ha, dip);
  843. err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht),
  844. rauht_pl);
  845. if (err) {
  846. netdev_err(dev, "Could not delete neigh %pI4h\n", &dip);
  847. neigh_entry->offloaded = true;
  848. } else {
  849. neigh_entry->offloaded = false;
  850. }
  851. mlxsw_sp_nexthop_neigh_update(mlxsw_sp, neigh_entry, true);
  852. }
  853. neigh_release(n);
  854. mlxsw_sp_port_dev_put(mlxsw_sp_port);
  855. }
  856. int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
  857. unsigned long event, void *ptr)
  858. {
  859. struct mlxsw_sp_neigh_entry *neigh_entry;
  860. struct mlxsw_sp_port *mlxsw_sp_port;
  861. struct mlxsw_sp *mlxsw_sp;
  862. unsigned long interval;
  863. struct net_device *dev;
  864. struct neigh_parms *p;
  865. struct neighbour *n;
  866. u32 dip;
  867. switch (event) {
  868. case NETEVENT_DELAY_PROBE_TIME_UPDATE:
  869. p = ptr;
  870. /* We don't care about changes in the default table. */
  871. if (!p->dev || p->tbl != &arp_tbl)
  872. return NOTIFY_DONE;
  873. /* We are in atomic context and can't take RTNL mutex,
  874. * so use RCU variant to walk the device chain.
  875. */
  876. mlxsw_sp_port = mlxsw_sp_port_lower_dev_hold(p->dev);
  877. if (!mlxsw_sp_port)
  878. return NOTIFY_DONE;
  879. mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  880. interval = jiffies_to_msecs(NEIGH_VAR(p, DELAY_PROBE_TIME));
  881. mlxsw_sp->router.neighs_update.interval = interval;
  882. mlxsw_sp_port_dev_put(mlxsw_sp_port);
  883. break;
  884. case NETEVENT_NEIGH_UPDATE:
  885. n = ptr;
  886. dev = n->dev;
  887. if (n->tbl != &arp_tbl)
  888. return NOTIFY_DONE;
  889. mlxsw_sp_port = mlxsw_sp_port_lower_dev_hold(dev);
  890. if (!mlxsw_sp_port)
  891. return NOTIFY_DONE;
  892. mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  893. dip = ntohl(*((__be32 *) n->primary_key));
  894. neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
  895. if (WARN_ON(!neigh_entry)) {
  896. mlxsw_sp_port_dev_put(mlxsw_sp_port);
  897. return NOTIFY_DONE;
  898. }
  899. neigh_entry->mlxsw_sp_port = mlxsw_sp_port;
  900. /* Take a reference to ensure the neighbour won't be
  901. * destructed until we drop the reference in delayed
  902. * work.
  903. */
  904. neigh_clone(n);
  905. if (!mlxsw_core_schedule_dw(&neigh_entry->dw, 0)) {
  906. neigh_release(n);
  907. mlxsw_sp_port_dev_put(mlxsw_sp_port);
  908. }
  909. break;
  910. }
  911. return NOTIFY_DONE;
  912. }
  913. static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
  914. {
  915. int err;
  916. err = rhashtable_init(&mlxsw_sp->router.neigh_ht,
  917. &mlxsw_sp_neigh_ht_params);
  918. if (err)
  919. return err;
  920. /* Initialize the polling interval according to the default
  921. * table.
  922. */
  923. mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp);
  924. /* Create the delayed works for the activity_update */
  925. INIT_DELAYED_WORK(&mlxsw_sp->router.neighs_update.dw,
  926. mlxsw_sp_router_neighs_update_work);
  927. INIT_DELAYED_WORK(&mlxsw_sp->router.nexthop_probe_dw,
  928. mlxsw_sp_router_probe_unresolved_nexthops);
  929. mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw, 0);
  930. mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw, 0);
  931. return 0;
  932. }
  933. static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)
  934. {
  935. cancel_delayed_work_sync(&mlxsw_sp->router.neighs_update.dw);
  936. cancel_delayed_work_sync(&mlxsw_sp->router.nexthop_probe_dw);
  937. rhashtable_destroy(&mlxsw_sp->router.neigh_ht);
  938. }
  939. struct mlxsw_sp_nexthop {
  940. struct list_head neigh_list_node; /* member of neigh entry list */
  941. struct mlxsw_sp_nexthop_group *nh_grp; /* pointer back to the group
  942. * this belongs to
  943. */
  944. u8 should_offload:1, /* set indicates this neigh is connected and
  945. * should be put to KVD linear area of this group.
  946. */
  947. offloaded:1, /* set in case the neigh is actually put into
  948. * KVD linear area of this group.
  949. */
  950. update:1; /* set indicates that MAC of this neigh should be
  951. * updated in HW
  952. */
  953. struct mlxsw_sp_neigh_entry *neigh_entry;
  954. };
  955. struct mlxsw_sp_nexthop_group {
  956. struct list_head list; /* node in mlxsw->router.nexthop_group_list */
  957. struct list_head fib_list; /* list of fib entries that use this group */
  958. u8 adj_index_valid:1;
  959. u32 adj_index;
  960. u16 ecmp_size;
  961. u16 count;
  962. struct mlxsw_sp_nexthop nexthops[0];
  963. };
  964. static int mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp *mlxsw_sp,
  965. struct mlxsw_sp_vr *vr,
  966. u32 adj_index, u16 ecmp_size,
  967. u32 new_adj_index,
  968. u16 new_ecmp_size)
  969. {
  970. char raleu_pl[MLXSW_REG_RALEU_LEN];
  971. mlxsw_reg_raleu_pack(raleu_pl,
  972. (enum mlxsw_reg_ralxx_protocol) vr->proto, vr->id,
  973. adj_index, ecmp_size, new_adj_index,
  974. new_ecmp_size);
  975. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raleu), raleu_pl);
  976. }
  977. static int mlxsw_sp_adj_index_mass_update(struct mlxsw_sp *mlxsw_sp,
  978. struct mlxsw_sp_nexthop_group *nh_grp,
  979. u32 old_adj_index, u16 old_ecmp_size)
  980. {
  981. struct mlxsw_sp_fib_entry *fib_entry;
  982. struct mlxsw_sp_vr *vr = NULL;
  983. int err;
  984. list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) {
  985. if (vr == fib_entry->vr)
  986. continue;
  987. vr = fib_entry->vr;
  988. err = mlxsw_sp_adj_index_mass_update_vr(mlxsw_sp, vr,
  989. old_adj_index,
  990. old_ecmp_size,
  991. nh_grp->adj_index,
  992. nh_grp->ecmp_size);
  993. if (err)
  994. return err;
  995. }
  996. return 0;
  997. }
  998. static int mlxsw_sp_nexthop_mac_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
  999. struct mlxsw_sp_nexthop *nh)
  1000. {
  1001. struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry;
  1002. char ratr_pl[MLXSW_REG_RATR_LEN];
  1003. mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY,
  1004. true, adj_index, neigh_entry->rif);
  1005. mlxsw_reg_ratr_eth_entry_pack(ratr_pl, neigh_entry->ha);
  1006. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
  1007. }
  1008. static int
  1009. mlxsw_sp_nexthop_group_mac_update(struct mlxsw_sp *mlxsw_sp,
  1010. struct mlxsw_sp_nexthop_group *nh_grp,
  1011. bool reallocate)
  1012. {
  1013. u32 adj_index = nh_grp->adj_index; /* base */
  1014. struct mlxsw_sp_nexthop *nh;
  1015. int i;
  1016. int err;
  1017. for (i = 0; i < nh_grp->count; i++) {
  1018. nh = &nh_grp->nexthops[i];
  1019. if (!nh->should_offload) {
  1020. nh->offloaded = 0;
  1021. continue;
  1022. }
  1023. if (nh->update || reallocate) {
  1024. err = mlxsw_sp_nexthop_mac_update(mlxsw_sp,
  1025. adj_index, nh);
  1026. if (err)
  1027. return err;
  1028. nh->update = 0;
  1029. nh->offloaded = 1;
  1030. }
  1031. adj_index++;
  1032. }
  1033. return 0;
  1034. }
  1035. static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
  1036. struct mlxsw_sp_fib_entry *fib_entry);
  1037. static int
  1038. mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp *mlxsw_sp,
  1039. struct mlxsw_sp_nexthop_group *nh_grp)
  1040. {
  1041. struct mlxsw_sp_fib_entry *fib_entry;
  1042. int err;
  1043. list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) {
  1044. err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
  1045. if (err)
  1046. return err;
  1047. }
  1048. return 0;
  1049. }
  1050. static void
  1051. mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
  1052. struct mlxsw_sp_nexthop_group *nh_grp)
  1053. {
  1054. struct mlxsw_sp_nexthop *nh;
  1055. bool offload_change = false;
  1056. u32 adj_index;
  1057. u16 ecmp_size = 0;
  1058. bool old_adj_index_valid;
  1059. u32 old_adj_index;
  1060. u16 old_ecmp_size;
  1061. int ret;
  1062. int i;
  1063. int err;
  1064. for (i = 0; i < nh_grp->count; i++) {
  1065. nh = &nh_grp->nexthops[i];
  1066. if (nh->should_offload ^ nh->offloaded) {
  1067. offload_change = true;
  1068. if (nh->should_offload)
  1069. nh->update = 1;
  1070. }
  1071. if (nh->should_offload)
  1072. ecmp_size++;
  1073. }
  1074. if (!offload_change) {
  1075. /* Nothing was added or removed, so no need to reallocate. Just
  1076. * update MAC on existing adjacency indexes.
  1077. */
  1078. err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp,
  1079. false);
  1080. if (err) {
  1081. dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
  1082. goto set_trap;
  1083. }
  1084. return;
  1085. }
  1086. if (!ecmp_size)
  1087. /* No neigh of this group is connected so we just set
  1088. * the trap and let everthing flow through kernel.
  1089. */
  1090. goto set_trap;
  1091. ret = mlxsw_sp_kvdl_alloc(mlxsw_sp, ecmp_size);
  1092. if (ret < 0) {
  1093. /* We ran out of KVD linear space, just set the
  1094. * trap and let everything flow through kernel.
  1095. */
  1096. dev_warn(mlxsw_sp->bus_info->dev, "Failed to allocate KVD linear area for nexthop group.\n");
  1097. goto set_trap;
  1098. }
  1099. adj_index = ret;
  1100. old_adj_index_valid = nh_grp->adj_index_valid;
  1101. old_adj_index = nh_grp->adj_index;
  1102. old_ecmp_size = nh_grp->ecmp_size;
  1103. nh_grp->adj_index_valid = 1;
  1104. nh_grp->adj_index = adj_index;
  1105. nh_grp->ecmp_size = ecmp_size;
  1106. err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp, true);
  1107. if (err) {
  1108. dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
  1109. goto set_trap;
  1110. }
  1111. if (!old_adj_index_valid) {
  1112. /* The trap was set for fib entries, so we have to call
  1113. * fib entry update to unset it and use adjacency index.
  1114. */
  1115. err = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
  1116. if (err) {
  1117. dev_warn(mlxsw_sp->bus_info->dev, "Failed to add adjacency index to fib entries.\n");
  1118. goto set_trap;
  1119. }
  1120. return;
  1121. }
  1122. err = mlxsw_sp_adj_index_mass_update(mlxsw_sp, nh_grp,
  1123. old_adj_index, old_ecmp_size);
  1124. mlxsw_sp_kvdl_free(mlxsw_sp, old_adj_index);
  1125. if (err) {
  1126. dev_warn(mlxsw_sp->bus_info->dev, "Failed to mass-update adjacency index for nexthop group.\n");
  1127. goto set_trap;
  1128. }
  1129. return;
  1130. set_trap:
  1131. old_adj_index_valid = nh_grp->adj_index_valid;
  1132. nh_grp->adj_index_valid = 0;
  1133. for (i = 0; i < nh_grp->count; i++) {
  1134. nh = &nh_grp->nexthops[i];
  1135. nh->offloaded = 0;
  1136. }
  1137. err = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
  1138. if (err)
  1139. dev_warn(mlxsw_sp->bus_info->dev, "Failed to set traps for fib entries.\n");
  1140. if (old_adj_index_valid)
  1141. mlxsw_sp_kvdl_free(mlxsw_sp, nh_grp->adj_index);
  1142. }
  1143. static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop *nh,
  1144. bool removing)
  1145. {
  1146. if (!removing)
  1147. nh->should_offload = 1;
  1148. else
  1149. nh->should_offload = 0;
  1150. nh->update = 1;
  1151. }
  1152. static void
  1153. mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
  1154. struct mlxsw_sp_neigh_entry *neigh_entry,
  1155. bool removing)
  1156. {
  1157. struct mlxsw_sp_nexthop *nh;
  1158. /* Take RTNL mutex here to prevent lists from changes */
  1159. rtnl_lock();
  1160. list_for_each_entry(nh, &neigh_entry->nexthop_list,
  1161. neigh_list_node) {
  1162. __mlxsw_sp_nexthop_neigh_update(nh, removing);
  1163. mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
  1164. }
  1165. rtnl_unlock();
  1166. }
  1167. static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp,
  1168. struct mlxsw_sp_nexthop_group *nh_grp,
  1169. struct mlxsw_sp_nexthop *nh,
  1170. struct fib_nh *fib_nh)
  1171. {
  1172. struct mlxsw_sp_neigh_entry *neigh_entry;
  1173. struct net_device *dev = fib_nh->nh_dev;
  1174. struct neighbour *n;
  1175. u8 nud_state;
  1176. /* Take a reference of neigh here ensuring that neigh would
  1177. * not be detructed before the nexthop entry is finished.
  1178. * The reference is taken either in neigh_lookup() or
  1179. * in neith_create() in case n is not found.
  1180. */
  1181. n = neigh_lookup(&arp_tbl, &fib_nh->nh_gw, dev);
  1182. if (!n) {
  1183. n = neigh_create(&arp_tbl, &fib_nh->nh_gw, dev);
  1184. if (IS_ERR(n))
  1185. return PTR_ERR(n);
  1186. neigh_event_send(n, NULL);
  1187. }
  1188. neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
  1189. if (!neigh_entry) {
  1190. neigh_release(n);
  1191. return -EINVAL;
  1192. }
  1193. /* If that is the first nexthop connected to that neigh, add to
  1194. * nexthop_neighs_list
  1195. */
  1196. if (list_empty(&neigh_entry->nexthop_list))
  1197. list_add_tail(&neigh_entry->nexthop_neighs_list_node,
  1198. &mlxsw_sp->router.nexthop_neighs_list);
  1199. nh->nh_grp = nh_grp;
  1200. nh->neigh_entry = neigh_entry;
  1201. list_add_tail(&nh->neigh_list_node, &neigh_entry->nexthop_list);
  1202. read_lock_bh(&n->lock);
  1203. nud_state = n->nud_state;
  1204. read_unlock_bh(&n->lock);
  1205. __mlxsw_sp_nexthop_neigh_update(nh, !(nud_state & NUD_VALID));
  1206. return 0;
  1207. }
  1208. static void mlxsw_sp_nexthop_fini(struct mlxsw_sp *mlxsw_sp,
  1209. struct mlxsw_sp_nexthop *nh)
  1210. {
  1211. struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry;
  1212. list_del(&nh->neigh_list_node);
  1213. /* If that is the last nexthop connected to that neigh, remove from
  1214. * nexthop_neighs_list
  1215. */
  1216. if (list_empty(&nh->neigh_entry->nexthop_list))
  1217. list_del(&nh->neigh_entry->nexthop_neighs_list_node);
  1218. neigh_release(neigh_entry->key.n);
  1219. }
  1220. static struct mlxsw_sp_nexthop_group *
  1221. mlxsw_sp_nexthop_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi)
  1222. {
  1223. struct mlxsw_sp_nexthop_group *nh_grp;
  1224. struct mlxsw_sp_nexthop *nh;
  1225. struct fib_nh *fib_nh;
  1226. size_t alloc_size;
  1227. int i;
  1228. int err;
  1229. alloc_size = sizeof(*nh_grp) +
  1230. fi->fib_nhs * sizeof(struct mlxsw_sp_nexthop);
  1231. nh_grp = kzalloc(alloc_size, GFP_KERNEL);
  1232. if (!nh_grp)
  1233. return ERR_PTR(-ENOMEM);
  1234. INIT_LIST_HEAD(&nh_grp->fib_list);
  1235. nh_grp->count = fi->fib_nhs;
  1236. for (i = 0; i < nh_grp->count; i++) {
  1237. nh = &nh_grp->nexthops[i];
  1238. fib_nh = &fi->fib_nh[i];
  1239. err = mlxsw_sp_nexthop_init(mlxsw_sp, nh_grp, nh, fib_nh);
  1240. if (err)
  1241. goto err_nexthop_init;
  1242. }
  1243. list_add_tail(&nh_grp->list, &mlxsw_sp->router.nexthop_group_list);
  1244. mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
  1245. return nh_grp;
  1246. err_nexthop_init:
  1247. for (i--; i >= 0; i--)
  1248. mlxsw_sp_nexthop_fini(mlxsw_sp, nh);
  1249. kfree(nh_grp);
  1250. return ERR_PTR(err);
  1251. }
  1252. static void
  1253. mlxsw_sp_nexthop_group_destroy(struct mlxsw_sp *mlxsw_sp,
  1254. struct mlxsw_sp_nexthop_group *nh_grp)
  1255. {
  1256. struct mlxsw_sp_nexthop *nh;
  1257. int i;
  1258. list_del(&nh_grp->list);
  1259. for (i = 0; i < nh_grp->count; i++) {
  1260. nh = &nh_grp->nexthops[i];
  1261. mlxsw_sp_nexthop_fini(mlxsw_sp, nh);
  1262. }
  1263. kfree(nh_grp);
  1264. }
  1265. static bool mlxsw_sp_nexthop_match(struct mlxsw_sp_nexthop *nh,
  1266. struct fib_info *fi)
  1267. {
  1268. int i;
  1269. for (i = 0; i < fi->fib_nhs; i++) {
  1270. struct fib_nh *fib_nh = &fi->fib_nh[i];
  1271. struct neighbour *n = nh->neigh_entry->key.n;
  1272. if (memcmp(n->primary_key, &fib_nh->nh_gw,
  1273. sizeof(fib_nh->nh_gw)) == 0 &&
  1274. n->dev == fib_nh->nh_dev)
  1275. return true;
  1276. }
  1277. return false;
  1278. }
  1279. static bool mlxsw_sp_nexthop_group_match(struct mlxsw_sp_nexthop_group *nh_grp,
  1280. struct fib_info *fi)
  1281. {
  1282. int i;
  1283. if (nh_grp->count != fi->fib_nhs)
  1284. return false;
  1285. for (i = 0; i < nh_grp->count; i++) {
  1286. struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
  1287. if (!mlxsw_sp_nexthop_match(nh, fi))
  1288. return false;
  1289. }
  1290. return true;
  1291. }
  1292. static struct mlxsw_sp_nexthop_group *
  1293. mlxsw_sp_nexthop_group_find(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi)
  1294. {
  1295. struct mlxsw_sp_nexthop_group *nh_grp;
  1296. list_for_each_entry(nh_grp, &mlxsw_sp->router.nexthop_group_list,
  1297. list) {
  1298. if (mlxsw_sp_nexthop_group_match(nh_grp, fi))
  1299. return nh_grp;
  1300. }
  1301. return NULL;
  1302. }
  1303. static int mlxsw_sp_nexthop_group_get(struct mlxsw_sp *mlxsw_sp,
  1304. struct mlxsw_sp_fib_entry *fib_entry,
  1305. struct fib_info *fi)
  1306. {
  1307. struct mlxsw_sp_nexthop_group *nh_grp;
  1308. nh_grp = mlxsw_sp_nexthop_group_find(mlxsw_sp, fi);
  1309. if (!nh_grp) {
  1310. nh_grp = mlxsw_sp_nexthop_group_create(mlxsw_sp, fi);
  1311. if (IS_ERR(nh_grp))
  1312. return PTR_ERR(nh_grp);
  1313. }
  1314. list_add_tail(&fib_entry->nexthop_group_node, &nh_grp->fib_list);
  1315. fib_entry->nh_group = nh_grp;
  1316. return 0;
  1317. }
  1318. static void mlxsw_sp_nexthop_group_put(struct mlxsw_sp *mlxsw_sp,
  1319. struct mlxsw_sp_fib_entry *fib_entry)
  1320. {
  1321. struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
  1322. list_del(&fib_entry->nexthop_group_node);
  1323. if (!list_empty(&nh_grp->fib_list))
  1324. return;
  1325. mlxsw_sp_nexthop_group_destroy(mlxsw_sp, nh_grp);
  1326. }
  1327. static int mlxsw_sp_fib_entry_op4_remote(struct mlxsw_sp *mlxsw_sp,
  1328. struct mlxsw_sp_fib_entry *fib_entry,
  1329. enum mlxsw_reg_ralue_op op)
  1330. {
  1331. char ralue_pl[MLXSW_REG_RALUE_LEN];
  1332. u32 *p_dip = (u32 *) fib_entry->key.addr;
  1333. struct mlxsw_sp_vr *vr = fib_entry->vr;
  1334. enum mlxsw_reg_ralue_trap_action trap_action;
  1335. u16 trap_id = 0;
  1336. u32 adjacency_index = 0;
  1337. u16 ecmp_size = 0;
  1338. /* In case the nexthop group adjacency index is valid, use it
  1339. * with provided ECMP size. Otherwise, setup trap and pass
  1340. * traffic to kernel.
  1341. */
  1342. if (fib_entry->nh_group->adj_index_valid) {
  1343. trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
  1344. adjacency_index = fib_entry->nh_group->adj_index;
  1345. ecmp_size = fib_entry->nh_group->ecmp_size;
  1346. } else {
  1347. trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
  1348. trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
  1349. }
  1350. mlxsw_reg_ralue_pack4(ralue_pl,
  1351. (enum mlxsw_reg_ralxx_protocol) vr->proto, op,
  1352. vr->id, fib_entry->key.prefix_len, *p_dip);
  1353. mlxsw_reg_ralue_act_remote_pack(ralue_pl, trap_action, trap_id,
  1354. adjacency_index, ecmp_size);
  1355. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
  1356. }
  1357. static int mlxsw_sp_fib_entry_op4_local(struct mlxsw_sp *mlxsw_sp,
  1358. struct mlxsw_sp_fib_entry *fib_entry,
  1359. enum mlxsw_reg_ralue_op op)
  1360. {
  1361. char ralue_pl[MLXSW_REG_RALUE_LEN];
  1362. u32 *p_dip = (u32 *) fib_entry->key.addr;
  1363. struct mlxsw_sp_vr *vr = fib_entry->vr;
  1364. mlxsw_reg_ralue_pack4(ralue_pl,
  1365. (enum mlxsw_reg_ralxx_protocol) vr->proto, op,
  1366. vr->id, fib_entry->key.prefix_len, *p_dip);
  1367. mlxsw_reg_ralue_act_local_pack(ralue_pl,
  1368. MLXSW_REG_RALUE_TRAP_ACTION_NOP, 0,
  1369. fib_entry->rif);
  1370. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
  1371. }
  1372. static int mlxsw_sp_fib_entry_op4_trap(struct mlxsw_sp *mlxsw_sp,
  1373. struct mlxsw_sp_fib_entry *fib_entry,
  1374. enum mlxsw_reg_ralue_op op)
  1375. {
  1376. char ralue_pl[MLXSW_REG_RALUE_LEN];
  1377. u32 *p_dip = (u32 *) fib_entry->key.addr;
  1378. struct mlxsw_sp_vr *vr = fib_entry->vr;
  1379. mlxsw_reg_ralue_pack4(ralue_pl,
  1380. (enum mlxsw_reg_ralxx_protocol) vr->proto, op,
  1381. vr->id, fib_entry->key.prefix_len, *p_dip);
  1382. mlxsw_reg_ralue_act_ip2me_pack(ralue_pl);
  1383. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
  1384. }
  1385. static int mlxsw_sp_fib_entry_op4(struct mlxsw_sp *mlxsw_sp,
  1386. struct mlxsw_sp_fib_entry *fib_entry,
  1387. enum mlxsw_reg_ralue_op op)
  1388. {
  1389. switch (fib_entry->type) {
  1390. case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE:
  1391. return mlxsw_sp_fib_entry_op4_remote(mlxsw_sp, fib_entry, op);
  1392. case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
  1393. return mlxsw_sp_fib_entry_op4_local(mlxsw_sp, fib_entry, op);
  1394. case MLXSW_SP_FIB_ENTRY_TYPE_TRAP:
  1395. return mlxsw_sp_fib_entry_op4_trap(mlxsw_sp, fib_entry, op);
  1396. }
  1397. return -EINVAL;
  1398. }
  1399. static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
  1400. struct mlxsw_sp_fib_entry *fib_entry,
  1401. enum mlxsw_reg_ralue_op op)
  1402. {
  1403. switch (fib_entry->vr->proto) {
  1404. case MLXSW_SP_L3_PROTO_IPV4:
  1405. return mlxsw_sp_fib_entry_op4(mlxsw_sp, fib_entry, op);
  1406. case MLXSW_SP_L3_PROTO_IPV6:
  1407. return -EINVAL;
  1408. }
  1409. return -EINVAL;
  1410. }
  1411. static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
  1412. struct mlxsw_sp_fib_entry *fib_entry)
  1413. {
  1414. return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
  1415. MLXSW_REG_RALUE_OP_WRITE_WRITE);
  1416. }
  1417. static int mlxsw_sp_fib_entry_del(struct mlxsw_sp *mlxsw_sp,
  1418. struct mlxsw_sp_fib_entry *fib_entry)
  1419. {
  1420. return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
  1421. MLXSW_REG_RALUE_OP_WRITE_DELETE);
  1422. }
  1423. static int
  1424. mlxsw_sp_router_fib4_entry_init(struct mlxsw_sp *mlxsw_sp,
  1425. const struct fib_entry_notifier_info *fen_info,
  1426. struct mlxsw_sp_fib_entry *fib_entry)
  1427. {
  1428. struct fib_info *fi = fen_info->fi;
  1429. struct mlxsw_sp_rif *r = NULL;
  1430. int nhsel;
  1431. int err;
  1432. if (fen_info->type == RTN_LOCAL || fen_info->type == RTN_BROADCAST) {
  1433. fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
  1434. return 0;
  1435. }
  1436. if (fen_info->type != RTN_UNICAST)
  1437. return -EINVAL;
  1438. for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
  1439. const struct fib_nh *nh = &fi->fib_nh[nhsel];
  1440. if (!nh->nh_dev)
  1441. continue;
  1442. r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, nh->nh_dev);
  1443. if (!r) {
  1444. /* In case router interface is not found for
  1445. * at least one of the nexthops, that means
  1446. * the nexthop points to some device unrelated
  1447. * to us. Set trap and pass the packets for
  1448. * this prefix to kernel.
  1449. */
  1450. break;
  1451. }
  1452. }
  1453. if (!r) {
  1454. fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
  1455. return 0;
  1456. }
  1457. if (fi->fib_scope != RT_SCOPE_UNIVERSE) {
  1458. fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
  1459. fib_entry->rif = r->rif;
  1460. } else {
  1461. fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
  1462. err = mlxsw_sp_nexthop_group_get(mlxsw_sp, fib_entry, fi);
  1463. if (err)
  1464. return err;
  1465. }
  1466. fib_info_offload_inc(fen_info->fi);
  1467. return 0;
  1468. }
  1469. static void
  1470. mlxsw_sp_router_fib4_entry_fini(struct mlxsw_sp *mlxsw_sp,
  1471. struct mlxsw_sp_fib_entry *fib_entry)
  1472. {
  1473. if (fib_entry->type != MLXSW_SP_FIB_ENTRY_TYPE_TRAP)
  1474. fib_info_offload_dec(fib_entry->fi);
  1475. if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_REMOTE)
  1476. mlxsw_sp_nexthop_group_put(mlxsw_sp, fib_entry);
  1477. }
  1478. static struct mlxsw_sp_fib_entry *
  1479. mlxsw_sp_fib_entry_get(struct mlxsw_sp *mlxsw_sp,
  1480. const struct fib_entry_notifier_info *fen_info)
  1481. {
  1482. struct mlxsw_sp_fib_entry *fib_entry;
  1483. struct fib_info *fi = fen_info->fi;
  1484. struct mlxsw_sp_vr *vr;
  1485. int err;
  1486. vr = mlxsw_sp_vr_get(mlxsw_sp, fen_info->dst_len, fen_info->tb_id,
  1487. MLXSW_SP_L3_PROTO_IPV4);
  1488. if (IS_ERR(vr))
  1489. return ERR_CAST(vr);
  1490. fib_entry = mlxsw_sp_fib_entry_lookup(vr->fib, &fen_info->dst,
  1491. sizeof(fen_info->dst),
  1492. fen_info->dst_len, fi->fib_dev);
  1493. if (fib_entry) {
  1494. /* Already exists, just take a reference */
  1495. fib_entry->ref_count++;
  1496. return fib_entry;
  1497. }
  1498. fib_entry = mlxsw_sp_fib_entry_create(vr->fib, &fen_info->dst,
  1499. sizeof(fen_info->dst),
  1500. fen_info->dst_len, fi->fib_dev);
  1501. if (!fib_entry) {
  1502. err = -ENOMEM;
  1503. goto err_fib_entry_create;
  1504. }
  1505. fib_entry->vr = vr;
  1506. fib_entry->fi = fi;
  1507. fib_entry->ref_count = 1;
  1508. err = mlxsw_sp_router_fib4_entry_init(mlxsw_sp, fen_info, fib_entry);
  1509. if (err)
  1510. goto err_fib4_entry_init;
  1511. return fib_entry;
  1512. err_fib4_entry_init:
  1513. mlxsw_sp_fib_entry_destroy(fib_entry);
  1514. err_fib_entry_create:
  1515. mlxsw_sp_vr_put(mlxsw_sp, vr);
  1516. return ERR_PTR(err);
  1517. }
  1518. static struct mlxsw_sp_fib_entry *
  1519. mlxsw_sp_fib_entry_find(struct mlxsw_sp *mlxsw_sp,
  1520. const struct fib_entry_notifier_info *fen_info)
  1521. {
  1522. struct mlxsw_sp_vr *vr;
  1523. vr = mlxsw_sp_vr_find(mlxsw_sp, fen_info->tb_id,
  1524. MLXSW_SP_L3_PROTO_IPV4);
  1525. if (!vr)
  1526. return NULL;
  1527. return mlxsw_sp_fib_entry_lookup(vr->fib, &fen_info->dst,
  1528. sizeof(fen_info->dst),
  1529. fen_info->dst_len,
  1530. fen_info->fi->fib_dev);
  1531. }
  1532. static void mlxsw_sp_fib_entry_put(struct mlxsw_sp *mlxsw_sp,
  1533. struct mlxsw_sp_fib_entry *fib_entry)
  1534. {
  1535. struct mlxsw_sp_vr *vr = fib_entry->vr;
  1536. if (--fib_entry->ref_count == 0) {
  1537. mlxsw_sp_router_fib4_entry_fini(mlxsw_sp, fib_entry);
  1538. mlxsw_sp_fib_entry_destroy(fib_entry);
  1539. }
  1540. mlxsw_sp_vr_put(mlxsw_sp, vr);
  1541. }
  1542. static void mlxsw_sp_fib_entry_put_all(struct mlxsw_sp *mlxsw_sp,
  1543. struct mlxsw_sp_fib_entry *fib_entry)
  1544. {
  1545. unsigned int last_ref_count;
  1546. do {
  1547. last_ref_count = fib_entry->ref_count;
  1548. mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry);
  1549. } while (last_ref_count != 1);
  1550. }
  1551. static int mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp,
  1552. struct fib_entry_notifier_info *fen_info)
  1553. {
  1554. struct mlxsw_sp_fib_entry *fib_entry;
  1555. struct mlxsw_sp_vr *vr;
  1556. int err;
  1557. if (mlxsw_sp->router.aborted)
  1558. return 0;
  1559. fib_entry = mlxsw_sp_fib_entry_get(mlxsw_sp, fen_info);
  1560. if (IS_ERR(fib_entry)) {
  1561. dev_warn(mlxsw_sp->bus_info->dev, "Failed to get FIB4 entry being added.\n");
  1562. return PTR_ERR(fib_entry);
  1563. }
  1564. if (fib_entry->ref_count != 1)
  1565. return 0;
  1566. vr = fib_entry->vr;
  1567. err = mlxsw_sp_fib_entry_insert(vr->fib, fib_entry);
  1568. if (err) {
  1569. dev_warn(mlxsw_sp->bus_info->dev, "Failed to insert FIB4 entry being added.\n");
  1570. goto err_fib_entry_insert;
  1571. }
  1572. err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
  1573. if (err)
  1574. goto err_fib_entry_add;
  1575. return 0;
  1576. err_fib_entry_add:
  1577. mlxsw_sp_fib_entry_remove(vr->fib, fib_entry);
  1578. err_fib_entry_insert:
  1579. mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry);
  1580. return err;
  1581. }
  1582. static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
  1583. struct fib_entry_notifier_info *fen_info)
  1584. {
  1585. struct mlxsw_sp_fib_entry *fib_entry;
  1586. if (mlxsw_sp->router.aborted)
  1587. return;
  1588. fib_entry = mlxsw_sp_fib_entry_find(mlxsw_sp, fen_info);
  1589. if (!fib_entry)
  1590. return;
  1591. if (fib_entry->ref_count == 1) {
  1592. mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry);
  1593. mlxsw_sp_fib_entry_remove(fib_entry->vr->fib, fib_entry);
  1594. }
  1595. mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry);
  1596. }
  1597. static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
  1598. {
  1599. char ralta_pl[MLXSW_REG_RALTA_LEN];
  1600. char ralst_pl[MLXSW_REG_RALST_LEN];
  1601. char raltb_pl[MLXSW_REG_RALTB_LEN];
  1602. char ralue_pl[MLXSW_REG_RALUE_LEN];
  1603. int err;
  1604. mlxsw_reg_ralta_pack(ralta_pl, true, MLXSW_REG_RALXX_PROTOCOL_IPV4,
  1605. MLXSW_SP_LPM_TREE_MIN);
  1606. err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
  1607. if (err)
  1608. return err;
  1609. mlxsw_reg_ralst_pack(ralst_pl, 0xff, MLXSW_SP_LPM_TREE_MIN);
  1610. err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl);
  1611. if (err)
  1612. return err;
  1613. mlxsw_reg_raltb_pack(raltb_pl, 0, MLXSW_REG_RALXX_PROTOCOL_IPV4,
  1614. MLXSW_SP_LPM_TREE_MIN);
  1615. err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
  1616. if (err)
  1617. return err;
  1618. mlxsw_reg_ralue_pack4(ralue_pl, MLXSW_SP_L3_PROTO_IPV4,
  1619. MLXSW_REG_RALUE_OP_WRITE_WRITE, 0, 0, 0);
  1620. mlxsw_reg_ralue_act_ip2me_pack(ralue_pl);
  1621. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
  1622. }
  1623. static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp)
  1624. {
  1625. struct mlxsw_resources *resources;
  1626. struct mlxsw_sp_fib_entry *fib_entry;
  1627. struct mlxsw_sp_fib_entry *tmp;
  1628. struct mlxsw_sp_vr *vr;
  1629. int i;
  1630. resources = mlxsw_core_resources_get(mlxsw_sp->core);
  1631. for (i = 0; i < resources->max_virtual_routers; i++) {
  1632. vr = &mlxsw_sp->router.vrs[i];
  1633. if (!vr->used)
  1634. continue;
  1635. list_for_each_entry_safe(fib_entry, tmp,
  1636. &vr->fib->entry_list, list) {
  1637. bool do_break = &tmp->list == &vr->fib->entry_list;
  1638. mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry);
  1639. mlxsw_sp_fib_entry_remove(fib_entry->vr->fib,
  1640. fib_entry);
  1641. mlxsw_sp_fib_entry_put_all(mlxsw_sp, fib_entry);
  1642. if (do_break)
  1643. break;
  1644. }
  1645. }
  1646. }
  1647. static void mlxsw_sp_router_fib4_abort(struct mlxsw_sp *mlxsw_sp)
  1648. {
  1649. int err;
  1650. mlxsw_sp_router_fib_flush(mlxsw_sp);
  1651. mlxsw_sp->router.aborted = true;
  1652. err = mlxsw_sp_router_set_abort_trap(mlxsw_sp);
  1653. if (err)
  1654. dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
  1655. }
  1656. static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
  1657. {
  1658. struct mlxsw_resources *resources;
  1659. char rgcr_pl[MLXSW_REG_RGCR_LEN];
  1660. int err;
  1661. resources = mlxsw_core_resources_get(mlxsw_sp->core);
  1662. if (!resources->max_rif_valid)
  1663. return -EIO;
  1664. mlxsw_sp->rifs = kcalloc(resources->max_rif,
  1665. sizeof(struct mlxsw_sp_rif *), GFP_KERNEL);
  1666. if (!mlxsw_sp->rifs)
  1667. return -ENOMEM;
  1668. mlxsw_reg_rgcr_pack(rgcr_pl, true);
  1669. mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, resources->max_rif);
  1670. err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
  1671. if (err)
  1672. goto err_rgcr_fail;
  1673. return 0;
  1674. err_rgcr_fail:
  1675. kfree(mlxsw_sp->rifs);
  1676. return err;
  1677. }
  1678. static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
  1679. {
  1680. struct mlxsw_resources *resources;
  1681. char rgcr_pl[MLXSW_REG_RGCR_LEN];
  1682. int i;
  1683. mlxsw_reg_rgcr_pack(rgcr_pl, false);
  1684. mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
  1685. resources = mlxsw_core_resources_get(mlxsw_sp->core);
  1686. for (i = 0; i < resources->max_rif; i++)
  1687. WARN_ON_ONCE(mlxsw_sp->rifs[i]);
  1688. kfree(mlxsw_sp->rifs);
  1689. }
  1690. static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
  1691. unsigned long event, void *ptr)
  1692. {
  1693. struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb);
  1694. struct fib_entry_notifier_info *fen_info = ptr;
  1695. int err;
  1696. if (!net_eq(fen_info->info.net, &init_net))
  1697. return NOTIFY_DONE;
  1698. switch (event) {
  1699. case FIB_EVENT_ENTRY_ADD:
  1700. err = mlxsw_sp_router_fib4_add(mlxsw_sp, fen_info);
  1701. if (err)
  1702. mlxsw_sp_router_fib4_abort(mlxsw_sp);
  1703. break;
  1704. case FIB_EVENT_ENTRY_DEL:
  1705. mlxsw_sp_router_fib4_del(mlxsw_sp, fen_info);
  1706. break;
  1707. case FIB_EVENT_RULE_ADD: /* fall through */
  1708. case FIB_EVENT_RULE_DEL:
  1709. mlxsw_sp_router_fib4_abort(mlxsw_sp);
  1710. break;
  1711. }
  1712. return NOTIFY_DONE;
  1713. }
  1714. int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
  1715. {
  1716. int err;
  1717. INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_neighs_list);
  1718. INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_group_list);
  1719. err = __mlxsw_sp_router_init(mlxsw_sp);
  1720. if (err)
  1721. return err;
  1722. mlxsw_sp_lpm_init(mlxsw_sp);
  1723. err = mlxsw_sp_vrs_init(mlxsw_sp);
  1724. if (err)
  1725. goto err_vrs_init;
  1726. err = mlxsw_sp_neigh_init(mlxsw_sp);
  1727. if (err)
  1728. goto err_neigh_init;
  1729. mlxsw_sp->fib_nb.notifier_call = mlxsw_sp_router_fib_event;
  1730. register_fib_notifier(&mlxsw_sp->fib_nb);
  1731. return 0;
  1732. err_neigh_init:
  1733. mlxsw_sp_vrs_fini(mlxsw_sp);
  1734. err_vrs_init:
  1735. __mlxsw_sp_router_fini(mlxsw_sp);
  1736. return err;
  1737. }
  1738. void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
  1739. {
  1740. unregister_fib_notifier(&mlxsw_sp->fib_nb);
  1741. mlxsw_sp_neigh_fini(mlxsw_sp);
  1742. mlxsw_sp_vrs_fini(mlxsw_sp);
  1743. __mlxsw_sp_router_fini(mlxsw_sp);
  1744. }