nexthop.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Generic nexthop implementation
  4. *
  5. * Copyright (c) 2017-19 Cumulus Networks
  6. * Copyright (c) 2017-19 David Ahern <dsa@cumulusnetworks.com>
  7. */
  8. #ifndef __LINUX_NEXTHOP_H
  9. #define __LINUX_NEXTHOP_H
  10. #include <linux/netdevice.h>
  11. #include <linux/notifier.h>
  12. #include <linux/route.h>
  13. #include <linux/types.h>
  14. #include <net/ip_fib.h>
  15. #include <net/ip6_fib.h>
  16. #include <net/netlink.h>
  17. #define NEXTHOP_VALID_USER_FLAGS RTNH_F_ONLINK
  18. struct nexthop;
  19. struct nh_config {
  20. u32 nh_id;
  21. u8 nh_family;
  22. u8 nh_protocol;
  23. u8 nh_blackhole;
  24. u8 nh_fdb;
  25. u32 nh_flags;
  26. int nh_ifindex;
  27. struct net_device *dev;
  28. union {
  29. __be32 ipv4;
  30. struct in6_addr ipv6;
  31. } gw;
  32. struct nlattr *nh_grp;
  33. u16 nh_grp_type;
  34. u16 nh_grp_res_num_buckets;
  35. unsigned long nh_grp_res_idle_timer;
  36. unsigned long nh_grp_res_unbalanced_timer;
  37. bool nh_grp_res_has_num_buckets;
  38. bool nh_grp_res_has_idle_timer;
  39. bool nh_grp_res_has_unbalanced_timer;
  40. bool nh_hw_stats;
  41. struct nlattr *nh_encap;
  42. u16 nh_encap_type;
  43. u32 nlflags;
  44. struct nl_info nlinfo;
  45. };
  46. struct nh_info {
  47. struct hlist_node dev_hash; /* entry on netns devhash */
  48. struct nexthop *nh_parent;
  49. u8 family;
  50. bool reject_nh;
  51. bool fdb_nh;
  52. union {
  53. struct fib_nh_common fib_nhc;
  54. struct fib_nh fib_nh;
  55. struct fib6_nh fib6_nh;
  56. };
  57. };
  58. struct nh_res_bucket {
  59. struct nh_grp_entry __rcu *nh_entry;
  60. atomic_long_t used_time;
  61. unsigned long migrated_time;
  62. bool occupied;
  63. u8 nh_flags;
  64. };
  65. struct nh_res_table {
  66. struct net *net;
  67. u32 nhg_id;
  68. struct delayed_work upkeep_dw;
  69. /* List of NHGEs that have too few buckets ("uw" for underweight).
  70. * Reclaimed buckets will be given to entries in this list.
  71. */
  72. struct list_head uw_nh_entries;
  73. unsigned long unbalanced_since;
  74. u32 idle_timer;
  75. u32 unbalanced_timer;
  76. u16 num_nh_buckets;
  77. struct nh_res_bucket nh_buckets[] __counted_by(num_nh_buckets);
  78. };
  79. struct nh_grp_entry_stats {
  80. u64_stats_t packets;
  81. struct u64_stats_sync syncp;
  82. };
  83. struct nh_grp_entry {
  84. struct nexthop *nh;
  85. struct nh_grp_entry_stats __percpu *stats;
  86. u16 weight;
  87. union {
  88. struct {
  89. atomic_t upper_bound;
  90. } hthr;
  91. struct {
  92. /* Member on uw_nh_entries. */
  93. struct list_head uw_nh_entry;
  94. u16 count_buckets;
  95. u16 wants_buckets;
  96. } res;
  97. };
  98. struct list_head nh_list;
  99. struct nexthop *nh_parent; /* nexthop of group with this entry */
  100. u64 packets_hw;
  101. };
  102. struct nh_group {
  103. struct nh_group *spare; /* spare group for removals */
  104. u16 num_nh;
  105. bool is_multipath;
  106. bool hash_threshold;
  107. bool resilient;
  108. bool fdb_nh;
  109. bool has_v4;
  110. bool hw_stats;
  111. struct nh_res_table __rcu *res_table;
  112. struct nh_grp_entry nh_entries[] __counted_by(num_nh);
  113. };
  114. struct nexthop {
  115. struct rb_node rb_node; /* entry on netns rbtree */
  116. struct list_head fi_list; /* v4 entries using nh */
  117. struct list_head f6i_list; /* v6 entries using nh */
  118. struct list_head fdb_list; /* fdb entries using this nh */
  119. struct list_head grp_list; /* nh group entries using this nh */
  120. struct net *net;
  121. u32 id;
  122. u8 protocol; /* app managing this nh */
  123. u8 nh_flags;
  124. bool is_group;
  125. refcount_t refcnt;
  126. struct rcu_head rcu;
  127. union {
  128. struct nh_info __rcu *nh_info;
  129. struct nh_group __rcu *nh_grp;
  130. };
  131. };
  132. enum nexthop_event_type {
  133. NEXTHOP_EVENT_DEL,
  134. NEXTHOP_EVENT_REPLACE,
  135. NEXTHOP_EVENT_RES_TABLE_PRE_REPLACE,
  136. NEXTHOP_EVENT_BUCKET_REPLACE,
  137. NEXTHOP_EVENT_HW_STATS_REPORT_DELTA,
  138. };
  139. enum nh_notifier_info_type {
  140. NH_NOTIFIER_INFO_TYPE_SINGLE,
  141. NH_NOTIFIER_INFO_TYPE_GRP,
  142. NH_NOTIFIER_INFO_TYPE_RES_TABLE,
  143. NH_NOTIFIER_INFO_TYPE_RES_BUCKET,
  144. NH_NOTIFIER_INFO_TYPE_GRP_HW_STATS,
  145. };
  146. struct nh_notifier_single_info {
  147. struct net_device *dev;
  148. u8 gw_family;
  149. union {
  150. __be32 ipv4;
  151. struct in6_addr ipv6;
  152. };
  153. u32 id;
  154. u8 is_reject:1,
  155. is_fdb:1,
  156. has_encap:1;
  157. };
  158. struct nh_notifier_grp_entry_info {
  159. u16 weight;
  160. struct nh_notifier_single_info nh;
  161. };
  162. struct nh_notifier_grp_info {
  163. u16 num_nh;
  164. bool is_fdb;
  165. bool hw_stats;
  166. struct nh_notifier_grp_entry_info nh_entries[] __counted_by(num_nh);
  167. };
  168. struct nh_notifier_res_bucket_info {
  169. u16 bucket_index;
  170. unsigned int idle_timer_ms;
  171. bool force;
  172. struct nh_notifier_single_info old_nh;
  173. struct nh_notifier_single_info new_nh;
  174. };
  175. struct nh_notifier_res_table_info {
  176. u16 num_nh_buckets;
  177. bool hw_stats;
  178. struct nh_notifier_single_info nhs[] __counted_by(num_nh_buckets);
  179. };
  180. struct nh_notifier_grp_hw_stats_entry_info {
  181. u32 id;
  182. u64 packets;
  183. };
  184. struct nh_notifier_grp_hw_stats_info {
  185. u16 num_nh;
  186. bool hw_stats_used;
  187. struct nh_notifier_grp_hw_stats_entry_info stats[] __counted_by(num_nh);
  188. };
  189. struct nh_notifier_info {
  190. struct net *net;
  191. struct netlink_ext_ack *extack;
  192. u32 id;
  193. enum nh_notifier_info_type type;
  194. union {
  195. struct nh_notifier_single_info *nh;
  196. struct nh_notifier_grp_info *nh_grp;
  197. struct nh_notifier_res_table_info *nh_res_table;
  198. struct nh_notifier_res_bucket_info *nh_res_bucket;
  199. struct nh_notifier_grp_hw_stats_info *nh_grp_hw_stats;
  200. };
  201. };
  202. int register_nexthop_notifier(struct net *net, struct notifier_block *nb,
  203. struct netlink_ext_ack *extack);
  204. int __unregister_nexthop_notifier(struct net *net, struct notifier_block *nb);
  205. int unregister_nexthop_notifier(struct net *net, struct notifier_block *nb);
  206. void nexthop_set_hw_flags(struct net *net, u32 id, bool offload, bool trap);
  207. void nexthop_bucket_set_hw_flags(struct net *net, u32 id, u16 bucket_index,
  208. bool offload, bool trap);
  209. void nexthop_res_grp_activity_update(struct net *net, u32 id, u16 num_buckets,
  210. unsigned long *activity);
  211. void nh_grp_hw_stats_report_delta(struct nh_notifier_grp_hw_stats_info *info,
  212. unsigned int nh_idx,
  213. u64 delta_packets);
  214. /* caller is holding rcu or rtnl; no reference taken to nexthop */
  215. struct nexthop *nexthop_find_by_id(struct net *net, u32 id);
  216. void nexthop_free_rcu(struct rcu_head *head);
  217. static inline bool nexthop_get(struct nexthop *nh)
  218. {
  219. return refcount_inc_not_zero(&nh->refcnt);
  220. }
  221. static inline void nexthop_put(struct nexthop *nh)
  222. {
  223. if (refcount_dec_and_test(&nh->refcnt))
  224. call_rcu_hurry(&nh->rcu, nexthop_free_rcu);
  225. }
  226. static inline bool nexthop_cmp(const struct nexthop *nh1,
  227. const struct nexthop *nh2)
  228. {
  229. return nh1 == nh2;
  230. }
  231. static inline bool nexthop_is_fdb(const struct nexthop *nh)
  232. {
  233. if (nh->is_group) {
  234. const struct nh_group *nh_grp;
  235. nh_grp = rcu_dereference_rtnl(nh->nh_grp);
  236. return nh_grp->fdb_nh;
  237. } else {
  238. const struct nh_info *nhi;
  239. nhi = rcu_dereference_rtnl(nh->nh_info);
  240. return nhi->fdb_nh;
  241. }
  242. }
  243. static inline bool nexthop_has_v4(const struct nexthop *nh)
  244. {
  245. if (nh->is_group) {
  246. struct nh_group *nh_grp;
  247. nh_grp = rcu_dereference_rtnl(nh->nh_grp);
  248. return nh_grp->has_v4;
  249. }
  250. return false;
  251. }
  252. static inline bool nexthop_is_multipath(const struct nexthop *nh)
  253. {
  254. if (nh->is_group) {
  255. struct nh_group *nh_grp;
  256. nh_grp = rcu_dereference_rtnl(nh->nh_grp);
  257. return nh_grp->is_multipath;
  258. }
  259. return false;
  260. }
  261. struct nexthop *nexthop_select_path(struct nexthop *nh, int hash);
  262. static inline unsigned int nexthop_num_path(const struct nexthop *nh)
  263. {
  264. unsigned int rc = 1;
  265. if (nh->is_group) {
  266. struct nh_group *nh_grp;
  267. nh_grp = rcu_dereference_rtnl(nh->nh_grp);
  268. if (nh_grp->is_multipath)
  269. rc = nh_grp->num_nh;
  270. }
  271. return rc;
  272. }
  273. static inline
  274. struct nexthop *nexthop_mpath_select(const struct nh_group *nhg, int nhsel)
  275. {
  276. /* for_nexthops macros in fib_semantics.c grabs a pointer to
  277. * the nexthop before checking nhsel
  278. */
  279. if (nhsel >= nhg->num_nh)
  280. return NULL;
  281. return nhg->nh_entries[nhsel].nh;
  282. }
  283. static inline
  284. int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh,
  285. u8 rt_family)
  286. {
  287. struct nh_group *nhg = rcu_dereference_rtnl(nh->nh_grp);
  288. int i;
  289. for (i = 0; i < nhg->num_nh; i++) {
  290. struct nexthop *nhe = nhg->nh_entries[i].nh;
  291. struct nh_info *nhi = rcu_dereference_rtnl(nhe->nh_info);
  292. struct fib_nh_common *nhc = &nhi->fib_nhc;
  293. int weight = nhg->nh_entries[i].weight;
  294. if (fib_add_nexthop(skb, nhc, weight, rt_family, 0) < 0)
  295. return -EMSGSIZE;
  296. }
  297. return 0;
  298. }
  299. /* called with rcu lock */
  300. static inline bool nexthop_is_blackhole(const struct nexthop *nh)
  301. {
  302. const struct nh_info *nhi;
  303. if (nh->is_group) {
  304. struct nh_group *nh_grp;
  305. nh_grp = rcu_dereference_rtnl(nh->nh_grp);
  306. if (nh_grp->num_nh > 1)
  307. return false;
  308. nh = nh_grp->nh_entries[0].nh;
  309. }
  310. nhi = rcu_dereference_rtnl(nh->nh_info);
  311. return nhi->reject_nh;
  312. }
  313. static inline void nexthop_path_fib_result(struct fib_result *res, int hash)
  314. {
  315. struct nh_info *nhi;
  316. struct nexthop *nh;
  317. nh = nexthop_select_path(res->fi->nh, hash);
  318. nhi = rcu_dereference(nh->nh_info);
  319. res->nhc = &nhi->fib_nhc;
  320. }
  321. /* called with rcu read lock or rtnl held */
  322. static inline
  323. struct fib_nh_common *nexthop_fib_nhc(struct nexthop *nh, int nhsel)
  324. {
  325. struct nh_info *nhi;
  326. BUILD_BUG_ON(offsetof(struct fib_nh, nh_common) != 0);
  327. BUILD_BUG_ON(offsetof(struct fib6_nh, nh_common) != 0);
  328. if (nh->is_group) {
  329. struct nh_group *nh_grp;
  330. nh_grp = rcu_dereference_rtnl(nh->nh_grp);
  331. if (nh_grp->is_multipath) {
  332. nh = nexthop_mpath_select(nh_grp, nhsel);
  333. if (!nh)
  334. return NULL;
  335. }
  336. }
  337. nhi = rcu_dereference_rtnl(nh->nh_info);
  338. return &nhi->fib_nhc;
  339. }
  340. /* called from fib_table_lookup with rcu_lock */
  341. static inline
  342. struct fib_nh_common *nexthop_get_nhc_lookup(const struct nexthop *nh,
  343. int fib_flags,
  344. const struct flowi4 *flp,
  345. int *nhsel)
  346. {
  347. struct nh_info *nhi;
  348. if (nh->is_group) {
  349. struct nh_group *nhg = rcu_dereference(nh->nh_grp);
  350. int i;
  351. for (i = 0; i < nhg->num_nh; i++) {
  352. struct nexthop *nhe = nhg->nh_entries[i].nh;
  353. nhi = rcu_dereference(nhe->nh_info);
  354. if (fib_lookup_good_nhc(&nhi->fib_nhc, fib_flags, flp)) {
  355. *nhsel = i;
  356. return &nhi->fib_nhc;
  357. }
  358. }
  359. } else {
  360. nhi = rcu_dereference(nh->nh_info);
  361. if (fib_lookup_good_nhc(&nhi->fib_nhc, fib_flags, flp)) {
  362. *nhsel = 0;
  363. return &nhi->fib_nhc;
  364. }
  365. }
  366. return NULL;
  367. }
  368. static inline bool nexthop_uses_dev(const struct nexthop *nh,
  369. const struct net_device *dev)
  370. {
  371. struct nh_info *nhi;
  372. if (nh->is_group) {
  373. struct nh_group *nhg = rcu_dereference(nh->nh_grp);
  374. int i;
  375. for (i = 0; i < nhg->num_nh; i++) {
  376. struct nexthop *nhe = nhg->nh_entries[i].nh;
  377. nhi = rcu_dereference(nhe->nh_info);
  378. if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev))
  379. return true;
  380. }
  381. } else {
  382. nhi = rcu_dereference(nh->nh_info);
  383. if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev))
  384. return true;
  385. }
  386. return false;
  387. }
  388. static inline unsigned int fib_info_num_path(const struct fib_info *fi)
  389. {
  390. if (unlikely(fi->nh))
  391. return nexthop_num_path(fi->nh);
  392. return fi->fib_nhs;
  393. }
  394. int fib_check_nexthop(struct nexthop *nh, u8 scope,
  395. struct netlink_ext_ack *extack);
  396. static inline struct fib_nh_common *fib_info_nhc(struct fib_info *fi, int nhsel)
  397. {
  398. if (unlikely(fi->nh))
  399. return nexthop_fib_nhc(fi->nh, nhsel);
  400. return &fi->fib_nh[nhsel].nh_common;
  401. }
  402. /* only used when fib_nh is built into fib_info */
  403. static inline struct fib_nh *fib_info_nh(struct fib_info *fi, int nhsel)
  404. {
  405. WARN_ON(fi->nh);
  406. return &fi->fib_nh[nhsel];
  407. }
  408. /*
  409. * IPv6 variants
  410. */
  411. int fib6_check_nexthop(struct nexthop *nh, struct fib6_config *cfg,
  412. struct netlink_ext_ack *extack);
  413. /* Caller should either hold rcu_read_lock(), or RTNL. */
  414. static inline struct fib6_nh *nexthop_fib6_nh(struct nexthop *nh)
  415. {
  416. struct nh_info *nhi;
  417. if (nh->is_group) {
  418. struct nh_group *nh_grp;
  419. nh_grp = rcu_dereference_rtnl(nh->nh_grp);
  420. nh = nexthop_mpath_select(nh_grp, 0);
  421. if (!nh)
  422. return NULL;
  423. }
  424. nhi = rcu_dereference_rtnl(nh->nh_info);
  425. if (nhi->family == AF_INET6)
  426. return &nhi->fib6_nh;
  427. return NULL;
  428. }
  429. static inline struct net_device *fib6_info_nh_dev(struct fib6_info *f6i)
  430. {
  431. struct fib6_nh *fib6_nh;
  432. fib6_nh = f6i->nh ? nexthop_fib6_nh(f6i->nh) : f6i->fib6_nh;
  433. return fib6_nh->fib_nh_dev;
  434. }
  435. static inline void nexthop_path_fib6_result(struct fib6_result *res, int hash)
  436. {
  437. struct nexthop *nh = res->f6i->nh;
  438. struct nh_info *nhi;
  439. nh = nexthop_select_path(nh, hash);
  440. nhi = rcu_dereference_rtnl(nh->nh_info);
  441. if (nhi->reject_nh) {
  442. res->fib6_type = RTN_BLACKHOLE;
  443. res->fib6_flags |= RTF_REJECT;
  444. res->nh = nexthop_fib6_nh(nh);
  445. } else {
  446. res->nh = &nhi->fib6_nh;
  447. }
  448. }
  449. int nexthop_for_each_fib6_nh(struct nexthop *nh,
  450. int (*cb)(struct fib6_nh *nh, void *arg),
  451. void *arg);
  452. static inline int nexthop_get_family(struct nexthop *nh)
  453. {
  454. struct nh_info *nhi = rcu_dereference_rtnl(nh->nh_info);
  455. return nhi->family;
  456. }
  457. static inline
  458. struct fib_nh_common *nexthop_fdb_nhc(struct nexthop *nh)
  459. {
  460. struct nh_info *nhi = rcu_dereference_rtnl(nh->nh_info);
  461. return &nhi->fib_nhc;
  462. }
  463. static inline struct fib_nh_common *nexthop_path_fdb_result(struct nexthop *nh,
  464. int hash)
  465. {
  466. struct nh_info *nhi;
  467. struct nexthop *nhp;
  468. nhp = nexthop_select_path(nh, hash);
  469. if (unlikely(!nhp))
  470. return NULL;
  471. nhi = rcu_dereference(nhp->nh_info);
  472. return &nhi->fib_nhc;
  473. }
  474. #endif