seg6.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * SR-IPv6 implementation
  4. *
  5. * Author:
  6. * David Lebrun <[email protected]>
  7. */
  8. #include <linux/errno.h>
  9. #include <linux/types.h>
  10. #include <linux/socket.h>
  11. #include <linux/net.h>
  12. #include <linux/in6.h>
  13. #include <linux/slab.h>
  14. #include <linux/rhashtable.h>
  15. #include <net/ipv6.h>
  16. #include <net/protocol.h>
  17. #include <net/seg6.h>
  18. #include <net/genetlink.h>
  19. #include <linux/seg6.h>
  20. #include <linux/seg6_genl.h>
  21. #ifdef CONFIG_IPV6_SEG6_HMAC
  22. #include <net/seg6_hmac.h>
  23. #endif
  24. bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced)
  25. {
  26. unsigned int tlv_offset;
  27. int max_last_entry;
  28. int trailing;
  29. if (srh->type != IPV6_SRCRT_TYPE_4)
  30. return false;
  31. if (((srh->hdrlen + 1) << 3) != len)
  32. return false;
  33. if (!reduced && srh->segments_left > srh->first_segment) {
  34. return false;
  35. } else {
  36. max_last_entry = (srh->hdrlen / 2) - 1;
  37. if (srh->first_segment > max_last_entry)
  38. return false;
  39. if (srh->segments_left > srh->first_segment + 1)
  40. return false;
  41. }
  42. tlv_offset = sizeof(*srh) + ((srh->first_segment + 1) << 4);
  43. trailing = len - tlv_offset;
  44. if (trailing < 0)
  45. return false;
  46. while (trailing) {
  47. struct sr6_tlv *tlv;
  48. unsigned int tlv_len;
  49. if (trailing < sizeof(*tlv))
  50. return false;
  51. tlv = (struct sr6_tlv *)((unsigned char *)srh + tlv_offset);
  52. tlv_len = sizeof(*tlv) + tlv->len;
  53. trailing -= tlv_len;
  54. if (trailing < 0)
  55. return false;
  56. tlv_offset += tlv_len;
  57. }
  58. return true;
  59. }
  60. struct ipv6_sr_hdr *seg6_get_srh(struct sk_buff *skb, int flags)
  61. {
  62. struct ipv6_sr_hdr *srh;
  63. int len, srhoff = 0;
  64. if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, &flags) < 0)
  65. return NULL;
  66. if (!pskb_may_pull(skb, srhoff + sizeof(*srh)))
  67. return NULL;
  68. srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
  69. len = (srh->hdrlen + 1) << 3;
  70. if (!pskb_may_pull(skb, srhoff + len))
  71. return NULL;
  72. /* note that pskb_may_pull may change pointers in header;
  73. * for this reason it is necessary to reload them when needed.
  74. */
  75. srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
  76. if (!seg6_validate_srh(srh, len, true))
  77. return NULL;
  78. return srh;
  79. }
  80. /* Determine if an ICMP invoking packet contains a segment routing
  81. * header. If it does, extract the offset to the true destination
  82. * address, which is in the first segment address.
  83. */
  84. void seg6_icmp_srh(struct sk_buff *skb, struct inet6_skb_parm *opt)
  85. {
  86. __u16 network_header = skb->network_header;
  87. struct ipv6_sr_hdr *srh;
  88. /* Update network header to point to the invoking packet
  89. * inside the ICMP packet, so we can use the seg6_get_srh()
  90. * helper.
  91. */
  92. skb_reset_network_header(skb);
  93. srh = seg6_get_srh(skb, 0);
  94. if (!srh)
  95. goto out;
  96. if (srh->type != IPV6_SRCRT_TYPE_4)
  97. goto out;
  98. opt->flags |= IP6SKB_SEG6;
  99. opt->srhoff = (unsigned char *)srh - skb->data;
  100. out:
  101. /* Restore the network header back to the ICMP packet */
  102. skb->network_header = network_header;
  103. }
  104. static struct genl_family seg6_genl_family;
  105. static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
  106. [SEG6_ATTR_DST] = { .type = NLA_BINARY,
  107. .len = sizeof(struct in6_addr) },
  108. [SEG6_ATTR_DSTLEN] = { .type = NLA_S32, },
  109. [SEG6_ATTR_HMACKEYID] = { .type = NLA_U32, },
  110. [SEG6_ATTR_SECRET] = { .type = NLA_BINARY, },
  111. [SEG6_ATTR_SECRETLEN] = { .type = NLA_U8, },
  112. [SEG6_ATTR_ALGID] = { .type = NLA_U8, },
  113. [SEG6_ATTR_HMACINFO] = { .type = NLA_NESTED, },
  114. };
  115. #ifdef CONFIG_IPV6_SEG6_HMAC
  116. static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
  117. {
  118. struct net *net = genl_info_net(info);
  119. struct seg6_pernet_data *sdata;
  120. struct seg6_hmac_info *hinfo;
  121. u32 hmackeyid;
  122. char *secret;
  123. int err = 0;
  124. u8 algid;
  125. u8 slen;
  126. sdata = seg6_pernet(net);
  127. if (!info->attrs[SEG6_ATTR_HMACKEYID] ||
  128. !info->attrs[SEG6_ATTR_SECRETLEN] ||
  129. !info->attrs[SEG6_ATTR_ALGID])
  130. return -EINVAL;
  131. hmackeyid = nla_get_u32(info->attrs[SEG6_ATTR_HMACKEYID]);
  132. slen = nla_get_u8(info->attrs[SEG6_ATTR_SECRETLEN]);
  133. algid = nla_get_u8(info->attrs[SEG6_ATTR_ALGID]);
  134. if (hmackeyid == 0)
  135. return -EINVAL;
  136. if (slen > SEG6_HMAC_SECRET_LEN)
  137. return -EINVAL;
  138. mutex_lock(&sdata->lock);
  139. hinfo = seg6_hmac_info_lookup(net, hmackeyid);
  140. if (!slen) {
  141. err = seg6_hmac_info_del(net, hmackeyid);
  142. goto out_unlock;
  143. }
  144. if (!info->attrs[SEG6_ATTR_SECRET]) {
  145. err = -EINVAL;
  146. goto out_unlock;
  147. }
  148. if (slen > nla_len(info->attrs[SEG6_ATTR_SECRET])) {
  149. err = -EINVAL;
  150. goto out_unlock;
  151. }
  152. if (hinfo) {
  153. err = seg6_hmac_info_del(net, hmackeyid);
  154. if (err)
  155. goto out_unlock;
  156. }
  157. secret = (char *)nla_data(info->attrs[SEG6_ATTR_SECRET]);
  158. hinfo = kzalloc(sizeof(*hinfo), GFP_KERNEL);
  159. if (!hinfo) {
  160. err = -ENOMEM;
  161. goto out_unlock;
  162. }
  163. memcpy(hinfo->secret, secret, slen);
  164. hinfo->slen = slen;
  165. hinfo->alg_id = algid;
  166. hinfo->hmackeyid = hmackeyid;
  167. err = seg6_hmac_info_add(net, hmackeyid, hinfo);
  168. if (err)
  169. kfree(hinfo);
  170. out_unlock:
  171. mutex_unlock(&sdata->lock);
  172. return err;
  173. }
  174. #else
  175. static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
  176. {
  177. return -ENOTSUPP;
  178. }
  179. #endif
  180. static int seg6_genl_set_tunsrc(struct sk_buff *skb, struct genl_info *info)
  181. {
  182. struct net *net = genl_info_net(info);
  183. struct in6_addr *val, *t_old, *t_new;
  184. struct seg6_pernet_data *sdata;
  185. sdata = seg6_pernet(net);
  186. if (!info->attrs[SEG6_ATTR_DST])
  187. return -EINVAL;
  188. val = nla_data(info->attrs[SEG6_ATTR_DST]);
  189. t_new = kmemdup(val, sizeof(*val), GFP_KERNEL);
  190. if (!t_new)
  191. return -ENOMEM;
  192. mutex_lock(&sdata->lock);
  193. t_old = sdata->tun_src;
  194. rcu_assign_pointer(sdata->tun_src, t_new);
  195. mutex_unlock(&sdata->lock);
  196. synchronize_net();
  197. kfree(t_old);
  198. return 0;
  199. }
  200. static int seg6_genl_get_tunsrc(struct sk_buff *skb, struct genl_info *info)
  201. {
  202. struct net *net = genl_info_net(info);
  203. struct in6_addr *tun_src;
  204. struct sk_buff *msg;
  205. void *hdr;
  206. msg = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  207. if (!msg)
  208. return -ENOMEM;
  209. hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
  210. &seg6_genl_family, 0, SEG6_CMD_GET_TUNSRC);
  211. if (!hdr)
  212. goto free_msg;
  213. rcu_read_lock();
  214. tun_src = rcu_dereference(seg6_pernet(net)->tun_src);
  215. if (nla_put(msg, SEG6_ATTR_DST, sizeof(struct in6_addr), tun_src))
  216. goto nla_put_failure;
  217. rcu_read_unlock();
  218. genlmsg_end(msg, hdr);
  219. return genlmsg_reply(msg, info);
  220. nla_put_failure:
  221. rcu_read_unlock();
  222. free_msg:
  223. nlmsg_free(msg);
  224. return -ENOMEM;
  225. }
  226. #ifdef CONFIG_IPV6_SEG6_HMAC
  227. static int __seg6_hmac_fill_info(struct seg6_hmac_info *hinfo,
  228. struct sk_buff *msg)
  229. {
  230. if (nla_put_u32(msg, SEG6_ATTR_HMACKEYID, hinfo->hmackeyid) ||
  231. nla_put_u8(msg, SEG6_ATTR_SECRETLEN, hinfo->slen) ||
  232. nla_put(msg, SEG6_ATTR_SECRET, hinfo->slen, hinfo->secret) ||
  233. nla_put_u8(msg, SEG6_ATTR_ALGID, hinfo->alg_id))
  234. return -1;
  235. return 0;
  236. }
  237. static int __seg6_genl_dumphmac_element(struct seg6_hmac_info *hinfo,
  238. u32 portid, u32 seq, u32 flags,
  239. struct sk_buff *skb, u8 cmd)
  240. {
  241. void *hdr;
  242. hdr = genlmsg_put(skb, portid, seq, &seg6_genl_family, flags, cmd);
  243. if (!hdr)
  244. return -ENOMEM;
  245. if (__seg6_hmac_fill_info(hinfo, skb) < 0)
  246. goto nla_put_failure;
  247. genlmsg_end(skb, hdr);
  248. return 0;
  249. nla_put_failure:
  250. genlmsg_cancel(skb, hdr);
  251. return -EMSGSIZE;
  252. }
  253. static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
  254. {
  255. struct net *net = sock_net(cb->skb->sk);
  256. struct seg6_pernet_data *sdata;
  257. struct rhashtable_iter *iter;
  258. sdata = seg6_pernet(net);
  259. iter = (struct rhashtable_iter *)cb->args[0];
  260. if (!iter) {
  261. iter = kmalloc(sizeof(*iter), GFP_KERNEL);
  262. if (!iter)
  263. return -ENOMEM;
  264. cb->args[0] = (long)iter;
  265. }
  266. rhashtable_walk_enter(&sdata->hmac_infos, iter);
  267. return 0;
  268. }
  269. static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
  270. {
  271. struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
  272. rhashtable_walk_exit(iter);
  273. kfree(iter);
  274. return 0;
  275. }
  276. static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
  277. {
  278. struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
  279. struct seg6_hmac_info *hinfo;
  280. int ret;
  281. rhashtable_walk_start(iter);
  282. for (;;) {
  283. hinfo = rhashtable_walk_next(iter);
  284. if (IS_ERR(hinfo)) {
  285. if (PTR_ERR(hinfo) == -EAGAIN)
  286. continue;
  287. ret = PTR_ERR(hinfo);
  288. goto done;
  289. } else if (!hinfo) {
  290. break;
  291. }
  292. ret = __seg6_genl_dumphmac_element(hinfo,
  293. NETLINK_CB(cb->skb).portid,
  294. cb->nlh->nlmsg_seq,
  295. NLM_F_MULTI,
  296. skb, SEG6_CMD_DUMPHMAC);
  297. if (ret)
  298. goto done;
  299. }
  300. ret = skb->len;
  301. done:
  302. rhashtable_walk_stop(iter);
  303. return ret;
  304. }
  305. #else
  306. static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
  307. {
  308. return 0;
  309. }
  310. static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
  311. {
  312. return 0;
  313. }
  314. static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
  315. {
  316. return -ENOTSUPP;
  317. }
  318. #endif
  319. static int __net_init seg6_net_init(struct net *net)
  320. {
  321. struct seg6_pernet_data *sdata;
  322. sdata = kzalloc(sizeof(*sdata), GFP_KERNEL);
  323. if (!sdata)
  324. return -ENOMEM;
  325. mutex_init(&sdata->lock);
  326. sdata->tun_src = kzalloc(sizeof(*sdata->tun_src), GFP_KERNEL);
  327. if (!sdata->tun_src) {
  328. kfree(sdata);
  329. return -ENOMEM;
  330. }
  331. net->ipv6.seg6_data = sdata;
  332. #ifdef CONFIG_IPV6_SEG6_HMAC
  333. if (seg6_hmac_net_init(net)) {
  334. kfree(rcu_dereference_raw(sdata->tun_src));
  335. kfree(sdata);
  336. return -ENOMEM;
  337. }
  338. #endif
  339. return 0;
  340. }
  341. static void __net_exit seg6_net_exit(struct net *net)
  342. {
  343. struct seg6_pernet_data *sdata = seg6_pernet(net);
  344. #ifdef CONFIG_IPV6_SEG6_HMAC
  345. seg6_hmac_net_exit(net);
  346. #endif
  347. kfree(rcu_dereference_raw(sdata->tun_src));
  348. kfree(sdata);
  349. }
  350. static struct pernet_operations ip6_segments_ops = {
  351. .init = seg6_net_init,
  352. .exit = seg6_net_exit,
  353. };
  354. static const struct genl_ops seg6_genl_ops[] = {
  355. {
  356. .cmd = SEG6_CMD_SETHMAC,
  357. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  358. .doit = seg6_genl_sethmac,
  359. .flags = GENL_ADMIN_PERM,
  360. },
  361. {
  362. .cmd = SEG6_CMD_DUMPHMAC,
  363. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  364. .start = seg6_genl_dumphmac_start,
  365. .dumpit = seg6_genl_dumphmac,
  366. .done = seg6_genl_dumphmac_done,
  367. .flags = GENL_ADMIN_PERM,
  368. },
  369. {
  370. .cmd = SEG6_CMD_SET_TUNSRC,
  371. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  372. .doit = seg6_genl_set_tunsrc,
  373. .flags = GENL_ADMIN_PERM,
  374. },
  375. {
  376. .cmd = SEG6_CMD_GET_TUNSRC,
  377. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  378. .doit = seg6_genl_get_tunsrc,
  379. .flags = GENL_ADMIN_PERM,
  380. },
  381. };
  382. static struct genl_family seg6_genl_family __ro_after_init = {
  383. .hdrsize = 0,
  384. .name = SEG6_GENL_NAME,
  385. .version = SEG6_GENL_VERSION,
  386. .maxattr = SEG6_ATTR_MAX,
  387. .policy = seg6_genl_policy,
  388. .netnsok = true,
  389. .parallel_ops = true,
  390. .ops = seg6_genl_ops,
  391. .n_ops = ARRAY_SIZE(seg6_genl_ops),
  392. .resv_start_op = SEG6_CMD_GET_TUNSRC + 1,
  393. .module = THIS_MODULE,
  394. };
  395. int __init seg6_init(void)
  396. {
  397. int err;
  398. err = genl_register_family(&seg6_genl_family);
  399. if (err)
  400. goto out;
  401. err = register_pernet_subsys(&ip6_segments_ops);
  402. if (err)
  403. goto out_unregister_genl;
  404. #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
  405. err = seg6_iptunnel_init();
  406. if (err)
  407. goto out_unregister_pernet;
  408. err = seg6_local_init();
  409. if (err)
  410. goto out_unregister_pernet;
  411. #endif
  412. #ifdef CONFIG_IPV6_SEG6_HMAC
  413. err = seg6_hmac_init();
  414. if (err)
  415. goto out_unregister_iptun;
  416. #endif
  417. pr_info("Segment Routing with IPv6\n");
  418. out:
  419. return err;
  420. #ifdef CONFIG_IPV6_SEG6_HMAC
  421. out_unregister_iptun:
  422. #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
  423. seg6_local_exit();
  424. seg6_iptunnel_exit();
  425. #endif
  426. #endif
  427. #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
  428. out_unregister_pernet:
  429. unregister_pernet_subsys(&ip6_segments_ops);
  430. #endif
  431. out_unregister_genl:
  432. genl_unregister_family(&seg6_genl_family);
  433. goto out;
  434. }
  435. void seg6_exit(void)
  436. {
  437. #ifdef CONFIG_IPV6_SEG6_HMAC
  438. seg6_hmac_exit();
  439. #endif
  440. #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
  441. seg6_iptunnel_exit();
  442. #endif
  443. unregister_pernet_subsys(&ip6_segments_ops);
  444. genl_unregister_family(&seg6_genl_family);
  445. }