ila_xlat.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/jhash.h>
  3. #include <linux/netfilter.h>
  4. #include <linux/rcupdate.h>
  5. #include <linux/rhashtable.h>
  6. #include <linux/vmalloc.h>
  7. #include <net/genetlink.h>
  8. #include <net/ila.h>
  9. #include <net/netns/generic.h>
  10. #include <uapi/linux/genetlink.h>
  11. #include "ila.h"
  12. struct ila_xlat_params {
  13. struct ila_params ip;
  14. int ifindex;
  15. };
  16. struct ila_map {
  17. struct ila_xlat_params xp;
  18. struct rhash_head node;
  19. struct ila_map __rcu *next;
  20. struct rcu_head rcu;
  21. };
  22. static unsigned int ila_net_id;
  23. struct ila_net {
  24. struct rhashtable rhash_table;
  25. spinlock_t *locks; /* Bucket locks for entry manipulation */
  26. unsigned int locks_mask;
  27. bool hooks_registered;
  28. };
  29. #define LOCKS_PER_CPU 10
  30. static int alloc_ila_locks(struct ila_net *ilan)
  31. {
  32. unsigned int i, size;
  33. unsigned int nr_pcpus = num_possible_cpus();
  34. nr_pcpus = min_t(unsigned int, nr_pcpus, 32UL);
  35. size = roundup_pow_of_two(nr_pcpus * LOCKS_PER_CPU);
  36. if (sizeof(spinlock_t) != 0) {
  37. ilan->locks = kvmalloc_array(size, sizeof(spinlock_t),
  38. GFP_KERNEL);
  39. if (!ilan->locks)
  40. return -ENOMEM;
  41. for (i = 0; i < size; i++)
  42. spin_lock_init(&ilan->locks[i]);
  43. }
  44. ilan->locks_mask = size - 1;
  45. return 0;
  46. }
  47. static u32 hashrnd __read_mostly;
  48. static __always_inline void __ila_hash_secret_init(void)
  49. {
  50. net_get_random_once(&hashrnd, sizeof(hashrnd));
  51. }
  52. static inline u32 ila_locator_hash(struct ila_locator loc)
  53. {
  54. u32 *v = (u32 *)loc.v32;
  55. __ila_hash_secret_init();
  56. return jhash_2words(v[0], v[1], hashrnd);
  57. }
  58. static inline spinlock_t *ila_get_lock(struct ila_net *ilan,
  59. struct ila_locator loc)
  60. {
  61. return &ilan->locks[ila_locator_hash(loc) & ilan->locks_mask];
  62. }
  63. static inline int ila_cmp_wildcards(struct ila_map *ila,
  64. struct ila_addr *iaddr, int ifindex)
  65. {
  66. return (ila->xp.ifindex && ila->xp.ifindex != ifindex);
  67. }
  68. static inline int ila_cmp_params(struct ila_map *ila,
  69. struct ila_xlat_params *xp)
  70. {
  71. return (ila->xp.ifindex != xp->ifindex);
  72. }
  73. static int ila_cmpfn(struct rhashtable_compare_arg *arg,
  74. const void *obj)
  75. {
  76. const struct ila_map *ila = obj;
  77. return (ila->xp.ip.locator_match.v64 != *(__be64 *)arg->key);
  78. }
  79. static inline int ila_order(struct ila_map *ila)
  80. {
  81. int score = 0;
  82. if (ila->xp.ifindex)
  83. score += 1 << 1;
  84. return score;
  85. }
  86. static const struct rhashtable_params rht_params = {
  87. .nelem_hint = 1024,
  88. .head_offset = offsetof(struct ila_map, node),
  89. .key_offset = offsetof(struct ila_map, xp.ip.locator_match),
  90. .key_len = sizeof(u64), /* identifier */
  91. .max_size = 1048576,
  92. .min_size = 256,
  93. .automatic_shrinking = true,
  94. .obj_cmpfn = ila_cmpfn,
  95. };
  96. static struct genl_family ila_nl_family;
  97. static const struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
  98. [ILA_ATTR_LOCATOR] = { .type = NLA_U64, },
  99. [ILA_ATTR_LOCATOR_MATCH] = { .type = NLA_U64, },
  100. [ILA_ATTR_IFINDEX] = { .type = NLA_U32, },
  101. [ILA_ATTR_CSUM_MODE] = { .type = NLA_U8, },
  102. [ILA_ATTR_IDENT_TYPE] = { .type = NLA_U8, },
  103. };
  104. static int parse_nl_config(struct genl_info *info,
  105. struct ila_xlat_params *xp)
  106. {
  107. memset(xp, 0, sizeof(*xp));
  108. if (info->attrs[ILA_ATTR_LOCATOR])
  109. xp->ip.locator.v64 = (__force __be64)nla_get_u64(
  110. info->attrs[ILA_ATTR_LOCATOR]);
  111. if (info->attrs[ILA_ATTR_LOCATOR_MATCH])
  112. xp->ip.locator_match.v64 = (__force __be64)nla_get_u64(
  113. info->attrs[ILA_ATTR_LOCATOR_MATCH]);
  114. if (info->attrs[ILA_ATTR_CSUM_MODE])
  115. xp->ip.csum_mode = nla_get_u8(info->attrs[ILA_ATTR_CSUM_MODE]);
  116. else
  117. xp->ip.csum_mode = ILA_CSUM_NO_ACTION;
  118. if (info->attrs[ILA_ATTR_IDENT_TYPE])
  119. xp->ip.ident_type = nla_get_u8(
  120. info->attrs[ILA_ATTR_IDENT_TYPE]);
  121. else
  122. xp->ip.ident_type = ILA_ATYPE_USE_FORMAT;
  123. if (info->attrs[ILA_ATTR_IFINDEX])
  124. xp->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]);
  125. return 0;
  126. }
  127. /* Must be called with rcu readlock */
  128. static inline struct ila_map *ila_lookup_wildcards(struct ila_addr *iaddr,
  129. int ifindex,
  130. struct ila_net *ilan)
  131. {
  132. struct ila_map *ila;
  133. ila = rhashtable_lookup_fast(&ilan->rhash_table, &iaddr->loc,
  134. rht_params);
  135. while (ila) {
  136. if (!ila_cmp_wildcards(ila, iaddr, ifindex))
  137. return ila;
  138. ila = rcu_access_pointer(ila->next);
  139. }
  140. return NULL;
  141. }
  142. /* Must be called with rcu readlock */
  143. static inline struct ila_map *ila_lookup_by_params(struct ila_xlat_params *xp,
  144. struct ila_net *ilan)
  145. {
  146. struct ila_map *ila;
  147. ila = rhashtable_lookup_fast(&ilan->rhash_table,
  148. &xp->ip.locator_match,
  149. rht_params);
  150. while (ila) {
  151. if (!ila_cmp_params(ila, xp))
  152. return ila;
  153. ila = rcu_access_pointer(ila->next);
  154. }
  155. return NULL;
  156. }
  157. static inline void ila_release(struct ila_map *ila)
  158. {
  159. kfree_rcu(ila, rcu);
  160. }
  161. static void ila_free_cb(void *ptr, void *arg)
  162. {
  163. struct ila_map *ila = (struct ila_map *)ptr, *next;
  164. /* Assume rcu_readlock held */
  165. while (ila) {
  166. next = rcu_access_pointer(ila->next);
  167. ila_release(ila);
  168. ila = next;
  169. }
  170. }
  171. static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila);
  172. static unsigned int
  173. ila_nf_input(void *priv,
  174. struct sk_buff *skb,
  175. const struct nf_hook_state *state)
  176. {
  177. ila_xlat_addr(skb, false);
  178. return NF_ACCEPT;
  179. }
  180. static const struct nf_hook_ops ila_nf_hook_ops[] = {
  181. {
  182. .hook = ila_nf_input,
  183. .pf = NFPROTO_IPV6,
  184. .hooknum = NF_INET_PRE_ROUTING,
  185. .priority = -1,
  186. },
  187. };
  188. static int ila_add_mapping(struct net *net, struct ila_xlat_params *xp)
  189. {
  190. struct ila_net *ilan = net_generic(net, ila_net_id);
  191. struct ila_map *ila, *head;
  192. spinlock_t *lock = ila_get_lock(ilan, xp->ip.locator_match);
  193. int err = 0, order;
  194. if (!ilan->hooks_registered) {
  195. /* We defer registering net hooks in the namespace until the
  196. * first mapping is added.
  197. */
  198. err = nf_register_net_hooks(net, ila_nf_hook_ops,
  199. ARRAY_SIZE(ila_nf_hook_ops));
  200. if (err)
  201. return err;
  202. ilan->hooks_registered = true;
  203. }
  204. ila = kzalloc(sizeof(*ila), GFP_KERNEL);
  205. if (!ila)
  206. return -ENOMEM;
  207. ila_init_saved_csum(&xp->ip);
  208. ila->xp = *xp;
  209. order = ila_order(ila);
  210. spin_lock(lock);
  211. head = rhashtable_lookup_fast(&ilan->rhash_table,
  212. &xp->ip.locator_match,
  213. rht_params);
  214. if (!head) {
  215. /* New entry for the rhash_table */
  216. err = rhashtable_lookup_insert_fast(&ilan->rhash_table,
  217. &ila->node, rht_params);
  218. } else {
  219. struct ila_map *tila = head, *prev = NULL;
  220. do {
  221. if (!ila_cmp_params(tila, xp)) {
  222. err = -EEXIST;
  223. goto out;
  224. }
  225. if (order > ila_order(tila))
  226. break;
  227. prev = tila;
  228. tila = rcu_dereference_protected(tila->next,
  229. lockdep_is_held(lock));
  230. } while (tila);
  231. if (prev) {
  232. /* Insert in sub list of head */
  233. RCU_INIT_POINTER(ila->next, tila);
  234. rcu_assign_pointer(prev->next, ila);
  235. } else {
  236. /* Make this ila new head */
  237. RCU_INIT_POINTER(ila->next, head);
  238. err = rhashtable_replace_fast(&ilan->rhash_table,
  239. &head->node,
  240. &ila->node, rht_params);
  241. if (err)
  242. goto out;
  243. }
  244. }
  245. out:
  246. spin_unlock(lock);
  247. if (err)
  248. kfree(ila);
  249. return err;
  250. }
  251. static int ila_del_mapping(struct net *net, struct ila_xlat_params *xp)
  252. {
  253. struct ila_net *ilan = net_generic(net, ila_net_id);
  254. struct ila_map *ila, *head, *prev;
  255. spinlock_t *lock = ila_get_lock(ilan, xp->ip.locator_match);
  256. int err = -ENOENT;
  257. spin_lock(lock);
  258. head = rhashtable_lookup_fast(&ilan->rhash_table,
  259. &xp->ip.locator_match, rht_params);
  260. ila = head;
  261. prev = NULL;
  262. while (ila) {
  263. if (ila_cmp_params(ila, xp)) {
  264. prev = ila;
  265. ila = rcu_dereference_protected(ila->next,
  266. lockdep_is_held(lock));
  267. continue;
  268. }
  269. err = 0;
  270. if (prev) {
  271. /* Not head, just delete from list */
  272. rcu_assign_pointer(prev->next, ila->next);
  273. } else {
  274. /* It is the head. If there is something in the
  275. * sublist we need to make a new head.
  276. */
  277. head = rcu_dereference_protected(ila->next,
  278. lockdep_is_held(lock));
  279. if (head) {
  280. /* Put first entry in the sublist into the
  281. * table
  282. */
  283. err = rhashtable_replace_fast(
  284. &ilan->rhash_table, &ila->node,
  285. &head->node, rht_params);
  286. if (err)
  287. goto out;
  288. } else {
  289. /* Entry no longer used */
  290. err = rhashtable_remove_fast(&ilan->rhash_table,
  291. &ila->node,
  292. rht_params);
  293. }
  294. }
  295. ila_release(ila);
  296. break;
  297. }
  298. out:
  299. spin_unlock(lock);
  300. return err;
  301. }
  302. static int ila_nl_cmd_add_mapping(struct sk_buff *skb, struct genl_info *info)
  303. {
  304. struct net *net = genl_info_net(info);
  305. struct ila_xlat_params p;
  306. int err;
  307. err = parse_nl_config(info, &p);
  308. if (err)
  309. return err;
  310. return ila_add_mapping(net, &p);
  311. }
  312. static int ila_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info)
  313. {
  314. struct net *net = genl_info_net(info);
  315. struct ila_xlat_params xp;
  316. int err;
  317. err = parse_nl_config(info, &xp);
  318. if (err)
  319. return err;
  320. ila_del_mapping(net, &xp);
  321. return 0;
  322. }
  323. static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg)
  324. {
  325. if (nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR,
  326. (__force u64)ila->xp.ip.locator.v64,
  327. ILA_ATTR_PAD) ||
  328. nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR_MATCH,
  329. (__force u64)ila->xp.ip.locator_match.v64,
  330. ILA_ATTR_PAD) ||
  331. nla_put_s32(msg, ILA_ATTR_IFINDEX, ila->xp.ifindex) ||
  332. nla_put_u8(msg, ILA_ATTR_CSUM_MODE, ila->xp.ip.csum_mode) ||
  333. nla_put_u8(msg, ILA_ATTR_IDENT_TYPE, ila->xp.ip.ident_type))
  334. return -1;
  335. return 0;
  336. }
  337. static int ila_dump_info(struct ila_map *ila,
  338. u32 portid, u32 seq, u32 flags,
  339. struct sk_buff *skb, u8 cmd)
  340. {
  341. void *hdr;
  342. hdr = genlmsg_put(skb, portid, seq, &ila_nl_family, flags, cmd);
  343. if (!hdr)
  344. return -ENOMEM;
  345. if (ila_fill_info(ila, skb) < 0)
  346. goto nla_put_failure;
  347. genlmsg_end(skb, hdr);
  348. return 0;
  349. nla_put_failure:
  350. genlmsg_cancel(skb, hdr);
  351. return -EMSGSIZE;
  352. }
  353. static int ila_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info)
  354. {
  355. struct net *net = genl_info_net(info);
  356. struct ila_net *ilan = net_generic(net, ila_net_id);
  357. struct sk_buff *msg;
  358. struct ila_xlat_params xp;
  359. struct ila_map *ila;
  360. int ret;
  361. ret = parse_nl_config(info, &xp);
  362. if (ret)
  363. return ret;
  364. msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  365. if (!msg)
  366. return -ENOMEM;
  367. rcu_read_lock();
  368. ila = ila_lookup_by_params(&xp, ilan);
  369. if (ila) {
  370. ret = ila_dump_info(ila,
  371. info->snd_portid,
  372. info->snd_seq, 0, msg,
  373. info->genlhdr->cmd);
  374. }
  375. rcu_read_unlock();
  376. if (ret < 0)
  377. goto out_free;
  378. return genlmsg_reply(msg, info);
  379. out_free:
  380. nlmsg_free(msg);
  381. return ret;
  382. }
  383. struct ila_dump_iter {
  384. struct rhashtable_iter rhiter;
  385. };
  386. static int ila_nl_dump_start(struct netlink_callback *cb)
  387. {
  388. struct net *net = sock_net(cb->skb->sk);
  389. struct ila_net *ilan = net_generic(net, ila_net_id);
  390. struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
  391. if (!iter) {
  392. iter = kmalloc(sizeof(*iter), GFP_KERNEL);
  393. if (!iter)
  394. return -ENOMEM;
  395. cb->args[0] = (long)iter;
  396. }
  397. return rhashtable_walk_init(&ilan->rhash_table, &iter->rhiter,
  398. GFP_KERNEL);
  399. }
  400. static int ila_nl_dump_done(struct netlink_callback *cb)
  401. {
  402. struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
  403. rhashtable_walk_exit(&iter->rhiter);
  404. kfree(iter);
  405. return 0;
  406. }
  407. static int ila_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
  408. {
  409. struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
  410. struct rhashtable_iter *rhiter = &iter->rhiter;
  411. struct ila_map *ila;
  412. int ret;
  413. rhashtable_walk_start(rhiter);
  414. for (;;) {
  415. ila = rhashtable_walk_next(rhiter);
  416. if (IS_ERR(ila)) {
  417. if (PTR_ERR(ila) == -EAGAIN)
  418. continue;
  419. ret = PTR_ERR(ila);
  420. goto done;
  421. } else if (!ila) {
  422. break;
  423. }
  424. while (ila) {
  425. ret = ila_dump_info(ila, NETLINK_CB(cb->skb).portid,
  426. cb->nlh->nlmsg_seq, NLM_F_MULTI,
  427. skb, ILA_CMD_GET);
  428. if (ret)
  429. goto done;
  430. ila = rcu_access_pointer(ila->next);
  431. }
  432. }
  433. ret = skb->len;
  434. done:
  435. rhashtable_walk_stop(rhiter);
  436. return ret;
  437. }
  438. static const struct genl_ops ila_nl_ops[] = {
  439. {
  440. .cmd = ILA_CMD_ADD,
  441. .doit = ila_nl_cmd_add_mapping,
  442. .policy = ila_nl_policy,
  443. .flags = GENL_ADMIN_PERM,
  444. },
  445. {
  446. .cmd = ILA_CMD_DEL,
  447. .doit = ila_nl_cmd_del_mapping,
  448. .policy = ila_nl_policy,
  449. .flags = GENL_ADMIN_PERM,
  450. },
  451. {
  452. .cmd = ILA_CMD_GET,
  453. .doit = ila_nl_cmd_get_mapping,
  454. .start = ila_nl_dump_start,
  455. .dumpit = ila_nl_dump,
  456. .done = ila_nl_dump_done,
  457. .policy = ila_nl_policy,
  458. },
  459. };
  460. static struct genl_family ila_nl_family __ro_after_init = {
  461. .hdrsize = 0,
  462. .name = ILA_GENL_NAME,
  463. .version = ILA_GENL_VERSION,
  464. .maxattr = ILA_ATTR_MAX,
  465. .netnsok = true,
  466. .parallel_ops = true,
  467. .module = THIS_MODULE,
  468. .ops = ila_nl_ops,
  469. .n_ops = ARRAY_SIZE(ila_nl_ops),
  470. };
  471. #define ILA_HASH_TABLE_SIZE 1024
  472. static __net_init int ila_init_net(struct net *net)
  473. {
  474. int err;
  475. struct ila_net *ilan = net_generic(net, ila_net_id);
  476. err = alloc_ila_locks(ilan);
  477. if (err)
  478. return err;
  479. rhashtable_init(&ilan->rhash_table, &rht_params);
  480. return 0;
  481. }
  482. static __net_exit void ila_exit_net(struct net *net)
  483. {
  484. struct ila_net *ilan = net_generic(net, ila_net_id);
  485. rhashtable_free_and_destroy(&ilan->rhash_table, ila_free_cb, NULL);
  486. kvfree(ilan->locks);
  487. if (ilan->hooks_registered)
  488. nf_unregister_net_hooks(net, ila_nf_hook_ops,
  489. ARRAY_SIZE(ila_nf_hook_ops));
  490. }
  491. static struct pernet_operations ila_net_ops = {
  492. .init = ila_init_net,
  493. .exit = ila_exit_net,
  494. .id = &ila_net_id,
  495. .size = sizeof(struct ila_net),
  496. };
  497. static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila)
  498. {
  499. struct ila_map *ila;
  500. struct ipv6hdr *ip6h = ipv6_hdr(skb);
  501. struct net *net = dev_net(skb->dev);
  502. struct ila_net *ilan = net_generic(net, ila_net_id);
  503. struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
  504. /* Assumes skb contains a valid IPv6 header that is pulled */
  505. /* No check here that ILA type in the mapping matches what is in the
  506. * address. We assume that whatever sender gaves us can be translated.
  507. * The checksum mode however is relevant.
  508. */
  509. rcu_read_lock();
  510. ila = ila_lookup_wildcards(iaddr, skb->dev->ifindex, ilan);
  511. if (ila)
  512. ila_update_ipv6_locator(skb, &ila->xp.ip, sir2ila);
  513. rcu_read_unlock();
  514. return 0;
  515. }
  516. int __init ila_xlat_init(void)
  517. {
  518. int ret;
  519. ret = register_pernet_device(&ila_net_ops);
  520. if (ret)
  521. goto exit;
  522. ret = genl_register_family(&ila_nl_family);
  523. if (ret < 0)
  524. goto unregister;
  525. return 0;
  526. unregister:
  527. unregister_pernet_device(&ila_net_ops);
  528. exit:
  529. return ret;
  530. }
  531. void ila_xlat_fini(void)
  532. {
  533. genl_unregister_family(&ila_nl_family);
  534. unregister_pernet_device(&ila_net_ops);
  535. }