seg6_local.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. /*
  2. * SR-IPv6 implementation
  3. *
  4. * Author:
  5. * David Lebrun <david.lebrun@uclouvain.be>
  6. *
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version
  11. * 2 of the License, or (at your option) any later version.
  12. */
  13. #include <linux/types.h>
  14. #include <linux/skbuff.h>
  15. #include <linux/net.h>
  16. #include <linux/module.h>
  17. #include <net/ip.h>
  18. #include <net/lwtunnel.h>
  19. #include <net/netevent.h>
  20. #include <net/netns/generic.h>
  21. #include <net/ip6_fib.h>
  22. #include <net/route.h>
  23. #include <net/seg6.h>
  24. #include <linux/seg6.h>
  25. #include <linux/seg6_local.h>
  26. #include <net/addrconf.h>
  27. #include <net/ip6_route.h>
  28. #include <net/dst_cache.h>
  29. #ifdef CONFIG_IPV6_SEG6_HMAC
  30. #include <net/seg6_hmac.h>
  31. #endif
  32. struct seg6_local_lwt;
  33. struct seg6_action_desc {
  34. int action;
  35. unsigned long attrs;
  36. int (*input)(struct sk_buff *skb, struct seg6_local_lwt *slwt);
  37. int static_headroom;
  38. };
  39. struct seg6_local_lwt {
  40. int action;
  41. struct ipv6_sr_hdr *srh;
  42. int table;
  43. struct in_addr nh4;
  44. struct in6_addr nh6;
  45. int iif;
  46. int oif;
  47. int headroom;
  48. struct seg6_action_desc *desc;
  49. };
  50. static struct seg6_local_lwt *seg6_local_lwtunnel(struct lwtunnel_state *lwt)
  51. {
  52. return (struct seg6_local_lwt *)lwt->data;
  53. }
  54. static struct ipv6_sr_hdr *get_srh(struct sk_buff *skb)
  55. {
  56. struct ipv6_sr_hdr *srh;
  57. struct ipv6hdr *hdr;
  58. int len;
  59. hdr = ipv6_hdr(skb);
  60. if (hdr->nexthdr != IPPROTO_ROUTING)
  61. return NULL;
  62. srh = (struct ipv6_sr_hdr *)(hdr + 1);
  63. len = (srh->hdrlen + 1) << 3;
  64. if (!pskb_may_pull(skb, sizeof(*hdr) + len))
  65. return NULL;
  66. if (!seg6_validate_srh(srh, len))
  67. return NULL;
  68. return srh;
  69. }
  70. static struct ipv6_sr_hdr *get_and_validate_srh(struct sk_buff *skb)
  71. {
  72. struct ipv6_sr_hdr *srh;
  73. srh = get_srh(skb);
  74. if (!srh)
  75. return NULL;
  76. if (srh->segments_left == 0)
  77. return NULL;
  78. #ifdef CONFIG_IPV6_SEG6_HMAC
  79. if (!seg6_hmac_validate_skb(skb))
  80. return NULL;
  81. #endif
  82. return srh;
  83. }
  84. /* regular endpoint function */
  85. static int input_action_end(struct sk_buff *skb, struct seg6_local_lwt *slwt)
  86. {
  87. struct ipv6_sr_hdr *srh;
  88. struct in6_addr *addr;
  89. srh = get_and_validate_srh(skb);
  90. if (!srh)
  91. goto drop;
  92. srh->segments_left--;
  93. addr = srh->segments + srh->segments_left;
  94. ipv6_hdr(skb)->daddr = *addr;
  95. skb_dst_drop(skb);
  96. ip6_route_input(skb);
  97. return dst_input(skb);
  98. drop:
  99. kfree_skb(skb);
  100. return -EINVAL;
  101. }
  102. /* regular endpoint, and forward to specified nexthop */
  103. static int input_action_end_x(struct sk_buff *skb, struct seg6_local_lwt *slwt)
  104. {
  105. struct net *net = dev_net(skb->dev);
  106. struct ipv6_sr_hdr *srh;
  107. struct dst_entry *dst;
  108. struct in6_addr *addr;
  109. struct ipv6hdr *hdr;
  110. struct flowi6 fl6;
  111. int flags;
  112. srh = get_and_validate_srh(skb);
  113. if (!srh)
  114. goto drop;
  115. srh->segments_left--;
  116. addr = srh->segments + srh->segments_left;
  117. hdr = ipv6_hdr(skb);
  118. hdr->daddr = *addr;
  119. skb_dst_drop(skb);
  120. fl6.flowi6_iif = skb->dev->ifindex;
  121. fl6.daddr = slwt->nh6;
  122. fl6.saddr = hdr->saddr;
  123. fl6.flowlabel = ip6_flowinfo(hdr);
  124. fl6.flowi6_mark = skb->mark;
  125. fl6.flowi6_proto = hdr->nexthdr;
  126. flags = RT6_LOOKUP_F_HAS_SADDR | RT6_LOOKUP_F_IFACE |
  127. RT6_LOOKUP_F_REACHABLE;
  128. dst = ip6_route_input_lookup(net, skb->dev, &fl6, flags);
  129. if (dst->dev->flags & IFF_LOOPBACK)
  130. goto drop;
  131. skb_dst_set(skb, dst);
  132. return dst_input(skb);
  133. drop:
  134. kfree_skb(skb);
  135. return -EINVAL;
  136. }
  137. /* decapsulate and forward to specified nexthop */
  138. static int input_action_end_dx6(struct sk_buff *skb,
  139. struct seg6_local_lwt *slwt)
  140. {
  141. struct net *net = dev_net(skb->dev);
  142. struct ipv6hdr *inner_hdr;
  143. struct ipv6_sr_hdr *srh;
  144. struct dst_entry *dst;
  145. unsigned int off = 0;
  146. struct flowi6 fl6;
  147. bool use_nh;
  148. int flags;
  149. /* this function accepts IPv6 encapsulated packets, with either
  150. * an SRH with SL=0, or no SRH.
  151. */
  152. srh = get_srh(skb);
  153. if (srh && srh->segments_left > 0)
  154. goto drop;
  155. #ifdef CONFIG_IPV6_SEG6_HMAC
  156. if (srh && !seg6_hmac_validate_skb(skb))
  157. goto drop;
  158. #endif
  159. if (ipv6_find_hdr(skb, &off, IPPROTO_IPV6, NULL, NULL) < 0)
  160. goto drop;
  161. if (!pskb_pull(skb, off))
  162. goto drop;
  163. skb_postpull_rcsum(skb, skb_network_header(skb), off);
  164. skb_reset_network_header(skb);
  165. skb_reset_transport_header(skb);
  166. skb->encapsulation = 0;
  167. inner_hdr = ipv6_hdr(skb);
  168. /* The inner packet is not associated to any local interface,
  169. * so we do not call netif_rx().
  170. *
  171. * If slwt->nh6 is set to ::, then lookup the nexthop for the
  172. * inner packet's DA. Otherwise, use the specified nexthop.
  173. */
  174. use_nh = !ipv6_addr_any(&slwt->nh6);
  175. skb_dst_drop(skb);
  176. fl6.flowi6_iif = skb->dev->ifindex;
  177. fl6.daddr = use_nh ? slwt->nh6 : inner_hdr->daddr;
  178. fl6.saddr = inner_hdr->saddr;
  179. fl6.flowlabel = ip6_flowinfo(inner_hdr);
  180. fl6.flowi6_mark = skb->mark;
  181. fl6.flowi6_proto = inner_hdr->nexthdr;
  182. flags = RT6_LOOKUP_F_HAS_SADDR | RT6_LOOKUP_F_REACHABLE;
  183. if (use_nh)
  184. flags |= RT6_LOOKUP_F_IFACE;
  185. dst = ip6_route_input_lookup(net, skb->dev, &fl6, flags);
  186. if (dst->dev->flags & IFF_LOOPBACK)
  187. goto drop;
  188. skb_dst_set(skb, dst);
  189. return dst_input(skb);
  190. drop:
  191. kfree_skb(skb);
  192. return -EINVAL;
  193. }
  194. /* push an SRH on top of the current one */
  195. static int input_action_end_b6(struct sk_buff *skb, struct seg6_local_lwt *slwt)
  196. {
  197. struct ipv6_sr_hdr *srh;
  198. int err = -EINVAL;
  199. srh = get_and_validate_srh(skb);
  200. if (!srh)
  201. goto drop;
  202. err = seg6_do_srh_inline(skb, slwt->srh);
  203. if (err)
  204. goto drop;
  205. ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
  206. skb_set_transport_header(skb, sizeof(struct ipv6hdr));
  207. skb_dst_drop(skb);
  208. ip6_route_input(skb);
  209. return dst_input(skb);
  210. drop:
  211. kfree_skb(skb);
  212. return err;
  213. }
  214. /* encapsulate within an outer IPv6 header and a specified SRH */
  215. static int input_action_end_b6_encap(struct sk_buff *skb,
  216. struct seg6_local_lwt *slwt)
  217. {
  218. struct ipv6_sr_hdr *srh;
  219. struct in6_addr *addr;
  220. int err = -EINVAL;
  221. srh = get_and_validate_srh(skb);
  222. if (!srh)
  223. goto drop;
  224. srh->segments_left--;
  225. addr = srh->segments + srh->segments_left;
  226. ipv6_hdr(skb)->daddr = *addr;
  227. skb_reset_inner_headers(skb);
  228. skb->encapsulation = 1;
  229. err = seg6_do_srh_encap(skb, slwt->srh);
  230. if (err)
  231. goto drop;
  232. ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
  233. skb_set_transport_header(skb, sizeof(struct ipv6hdr));
  234. skb_dst_drop(skb);
  235. ip6_route_input(skb);
  236. return dst_input(skb);
  237. drop:
  238. kfree_skb(skb);
  239. return err;
  240. }
  241. static struct seg6_action_desc seg6_action_table[] = {
  242. {
  243. .action = SEG6_LOCAL_ACTION_END,
  244. .attrs = 0,
  245. .input = input_action_end,
  246. },
  247. {
  248. .action = SEG6_LOCAL_ACTION_END_X,
  249. .attrs = (1 << SEG6_LOCAL_NH6),
  250. .input = input_action_end_x,
  251. },
  252. {
  253. .action = SEG6_LOCAL_ACTION_END_DX6,
  254. .attrs = (1 << SEG6_LOCAL_NH6),
  255. .input = input_action_end_dx6,
  256. },
  257. {
  258. .action = SEG6_LOCAL_ACTION_END_B6,
  259. .attrs = (1 << SEG6_LOCAL_SRH),
  260. .input = input_action_end_b6,
  261. },
  262. {
  263. .action = SEG6_LOCAL_ACTION_END_B6_ENCAP,
  264. .attrs = (1 << SEG6_LOCAL_SRH),
  265. .input = input_action_end_b6_encap,
  266. .static_headroom = sizeof(struct ipv6hdr),
  267. }
  268. };
  269. static struct seg6_action_desc *__get_action_desc(int action)
  270. {
  271. struct seg6_action_desc *desc;
  272. int i, count;
  273. count = sizeof(seg6_action_table) / sizeof(struct seg6_action_desc);
  274. for (i = 0; i < count; i++) {
  275. desc = &seg6_action_table[i];
  276. if (desc->action == action)
  277. return desc;
  278. }
  279. return NULL;
  280. }
  281. static int seg6_local_input(struct sk_buff *skb)
  282. {
  283. struct dst_entry *orig_dst = skb_dst(skb);
  284. struct seg6_action_desc *desc;
  285. struct seg6_local_lwt *slwt;
  286. slwt = seg6_local_lwtunnel(orig_dst->lwtstate);
  287. desc = slwt->desc;
  288. return desc->input(skb, slwt);
  289. }
  290. static const struct nla_policy seg6_local_policy[SEG6_LOCAL_MAX + 1] = {
  291. [SEG6_LOCAL_ACTION] = { .type = NLA_U32 },
  292. [SEG6_LOCAL_SRH] = { .type = NLA_BINARY },
  293. [SEG6_LOCAL_TABLE] = { .type = NLA_U32 },
  294. [SEG6_LOCAL_NH4] = { .type = NLA_BINARY,
  295. .len = sizeof(struct in_addr) },
  296. [SEG6_LOCAL_NH6] = { .type = NLA_BINARY,
  297. .len = sizeof(struct in6_addr) },
  298. [SEG6_LOCAL_IIF] = { .type = NLA_U32 },
  299. [SEG6_LOCAL_OIF] = { .type = NLA_U32 },
  300. };
  301. static int parse_nla_srh(struct nlattr **attrs, struct seg6_local_lwt *slwt)
  302. {
  303. struct ipv6_sr_hdr *srh;
  304. int len;
  305. srh = nla_data(attrs[SEG6_LOCAL_SRH]);
  306. len = nla_len(attrs[SEG6_LOCAL_SRH]);
  307. /* SRH must contain at least one segment */
  308. if (len < sizeof(*srh) + sizeof(struct in6_addr))
  309. return -EINVAL;
  310. if (!seg6_validate_srh(srh, len))
  311. return -EINVAL;
  312. slwt->srh = kmalloc(len, GFP_KERNEL);
  313. if (!slwt->srh)
  314. return -ENOMEM;
  315. memcpy(slwt->srh, srh, len);
  316. slwt->headroom += len;
  317. return 0;
  318. }
  319. static int put_nla_srh(struct sk_buff *skb, struct seg6_local_lwt *slwt)
  320. {
  321. struct ipv6_sr_hdr *srh;
  322. struct nlattr *nla;
  323. int len;
  324. srh = slwt->srh;
  325. len = (srh->hdrlen + 1) << 3;
  326. nla = nla_reserve(skb, SEG6_LOCAL_SRH, len);
  327. if (!nla)
  328. return -EMSGSIZE;
  329. memcpy(nla_data(nla), srh, len);
  330. return 0;
  331. }
  332. static int cmp_nla_srh(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
  333. {
  334. int len = (a->srh->hdrlen + 1) << 3;
  335. if (len != ((b->srh->hdrlen + 1) << 3))
  336. return 1;
  337. return memcmp(a->srh, b->srh, len);
  338. }
  339. static int parse_nla_table(struct nlattr **attrs, struct seg6_local_lwt *slwt)
  340. {
  341. slwt->table = nla_get_u32(attrs[SEG6_LOCAL_TABLE]);
  342. return 0;
  343. }
  344. static int put_nla_table(struct sk_buff *skb, struct seg6_local_lwt *slwt)
  345. {
  346. if (nla_put_u32(skb, SEG6_LOCAL_TABLE, slwt->table))
  347. return -EMSGSIZE;
  348. return 0;
  349. }
  350. static int cmp_nla_table(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
  351. {
  352. if (a->table != b->table)
  353. return 1;
  354. return 0;
  355. }
  356. static int parse_nla_nh4(struct nlattr **attrs, struct seg6_local_lwt *slwt)
  357. {
  358. memcpy(&slwt->nh4, nla_data(attrs[SEG6_LOCAL_NH4]),
  359. sizeof(struct in_addr));
  360. return 0;
  361. }
  362. static int put_nla_nh4(struct sk_buff *skb, struct seg6_local_lwt *slwt)
  363. {
  364. struct nlattr *nla;
  365. nla = nla_reserve(skb, SEG6_LOCAL_NH4, sizeof(struct in_addr));
  366. if (!nla)
  367. return -EMSGSIZE;
  368. memcpy(nla_data(nla), &slwt->nh4, sizeof(struct in_addr));
  369. return 0;
  370. }
  371. static int cmp_nla_nh4(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
  372. {
  373. return memcmp(&a->nh4, &b->nh4, sizeof(struct in_addr));
  374. }
  375. static int parse_nla_nh6(struct nlattr **attrs, struct seg6_local_lwt *slwt)
  376. {
  377. memcpy(&slwt->nh6, nla_data(attrs[SEG6_LOCAL_NH6]),
  378. sizeof(struct in6_addr));
  379. return 0;
  380. }
  381. static int put_nla_nh6(struct sk_buff *skb, struct seg6_local_lwt *slwt)
  382. {
  383. struct nlattr *nla;
  384. nla = nla_reserve(skb, SEG6_LOCAL_NH6, sizeof(struct in6_addr));
  385. if (!nla)
  386. return -EMSGSIZE;
  387. memcpy(nla_data(nla), &slwt->nh6, sizeof(struct in6_addr));
  388. return 0;
  389. }
  390. static int cmp_nla_nh6(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
  391. {
  392. return memcmp(&a->nh6, &b->nh6, sizeof(struct in6_addr));
  393. }
  394. static int parse_nla_iif(struct nlattr **attrs, struct seg6_local_lwt *slwt)
  395. {
  396. slwt->iif = nla_get_u32(attrs[SEG6_LOCAL_IIF]);
  397. return 0;
  398. }
  399. static int put_nla_iif(struct sk_buff *skb, struct seg6_local_lwt *slwt)
  400. {
  401. if (nla_put_u32(skb, SEG6_LOCAL_IIF, slwt->iif))
  402. return -EMSGSIZE;
  403. return 0;
  404. }
  405. static int cmp_nla_iif(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
  406. {
  407. if (a->iif != b->iif)
  408. return 1;
  409. return 0;
  410. }
  411. static int parse_nla_oif(struct nlattr **attrs, struct seg6_local_lwt *slwt)
  412. {
  413. slwt->oif = nla_get_u32(attrs[SEG6_LOCAL_OIF]);
  414. return 0;
  415. }
  416. static int put_nla_oif(struct sk_buff *skb, struct seg6_local_lwt *slwt)
  417. {
  418. if (nla_put_u32(skb, SEG6_LOCAL_OIF, slwt->oif))
  419. return -EMSGSIZE;
  420. return 0;
  421. }
  422. static int cmp_nla_oif(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
  423. {
  424. if (a->oif != b->oif)
  425. return 1;
  426. return 0;
  427. }
  428. struct seg6_action_param {
  429. int (*parse)(struct nlattr **attrs, struct seg6_local_lwt *slwt);
  430. int (*put)(struct sk_buff *skb, struct seg6_local_lwt *slwt);
  431. int (*cmp)(struct seg6_local_lwt *a, struct seg6_local_lwt *b);
  432. };
  433. static struct seg6_action_param seg6_action_params[SEG6_LOCAL_MAX + 1] = {
  434. [SEG6_LOCAL_SRH] = { .parse = parse_nla_srh,
  435. .put = put_nla_srh,
  436. .cmp = cmp_nla_srh },
  437. [SEG6_LOCAL_TABLE] = { .parse = parse_nla_table,
  438. .put = put_nla_table,
  439. .cmp = cmp_nla_table },
  440. [SEG6_LOCAL_NH4] = { .parse = parse_nla_nh4,
  441. .put = put_nla_nh4,
  442. .cmp = cmp_nla_nh4 },
  443. [SEG6_LOCAL_NH6] = { .parse = parse_nla_nh6,
  444. .put = put_nla_nh6,
  445. .cmp = cmp_nla_nh6 },
  446. [SEG6_LOCAL_IIF] = { .parse = parse_nla_iif,
  447. .put = put_nla_iif,
  448. .cmp = cmp_nla_iif },
  449. [SEG6_LOCAL_OIF] = { .parse = parse_nla_oif,
  450. .put = put_nla_oif,
  451. .cmp = cmp_nla_oif },
  452. };
  453. static int parse_nla_action(struct nlattr **attrs, struct seg6_local_lwt *slwt)
  454. {
  455. struct seg6_action_param *param;
  456. struct seg6_action_desc *desc;
  457. int i, err;
  458. desc = __get_action_desc(slwt->action);
  459. if (!desc)
  460. return -EINVAL;
  461. if (!desc->input)
  462. return -EOPNOTSUPP;
  463. slwt->desc = desc;
  464. slwt->headroom += desc->static_headroom;
  465. for (i = 0; i < SEG6_LOCAL_MAX + 1; i++) {
  466. if (desc->attrs & (1 << i)) {
  467. if (!attrs[i])
  468. return -EINVAL;
  469. param = &seg6_action_params[i];
  470. err = param->parse(attrs, slwt);
  471. if (err < 0)
  472. return err;
  473. }
  474. }
  475. return 0;
  476. }
  477. static int seg6_local_build_state(struct nlattr *nla, unsigned int family,
  478. const void *cfg, struct lwtunnel_state **ts,
  479. struct netlink_ext_ack *extack)
  480. {
  481. struct nlattr *tb[SEG6_LOCAL_MAX + 1];
  482. struct lwtunnel_state *newts;
  483. struct seg6_local_lwt *slwt;
  484. int err;
  485. err = nla_parse_nested(tb, SEG6_LOCAL_MAX, nla, seg6_local_policy,
  486. extack);
  487. if (err < 0)
  488. return err;
  489. if (!tb[SEG6_LOCAL_ACTION])
  490. return -EINVAL;
  491. newts = lwtunnel_state_alloc(sizeof(*slwt));
  492. if (!newts)
  493. return -ENOMEM;
  494. slwt = seg6_local_lwtunnel(newts);
  495. slwt->action = nla_get_u32(tb[SEG6_LOCAL_ACTION]);
  496. err = parse_nla_action(tb, slwt);
  497. if (err < 0)
  498. goto out_free;
  499. newts->type = LWTUNNEL_ENCAP_SEG6_LOCAL;
  500. newts->flags = LWTUNNEL_STATE_INPUT_REDIRECT;
  501. newts->headroom = slwt->headroom;
  502. *ts = newts;
  503. return 0;
  504. out_free:
  505. kfree(slwt->srh);
  506. kfree(newts);
  507. return err;
  508. }
  509. static void seg6_local_destroy_state(struct lwtunnel_state *lwt)
  510. {
  511. struct seg6_local_lwt *slwt = seg6_local_lwtunnel(lwt);
  512. kfree(slwt->srh);
  513. }
  514. static int seg6_local_fill_encap(struct sk_buff *skb,
  515. struct lwtunnel_state *lwt)
  516. {
  517. struct seg6_local_lwt *slwt = seg6_local_lwtunnel(lwt);
  518. struct seg6_action_param *param;
  519. int i, err;
  520. if (nla_put_u32(skb, SEG6_LOCAL_ACTION, slwt->action))
  521. return -EMSGSIZE;
  522. for (i = 0; i < SEG6_LOCAL_MAX + 1; i++) {
  523. if (slwt->desc->attrs & (1 << i)) {
  524. param = &seg6_action_params[i];
  525. err = param->put(skb, slwt);
  526. if (err < 0)
  527. return err;
  528. }
  529. }
  530. return 0;
  531. }
  532. static int seg6_local_get_encap_size(struct lwtunnel_state *lwt)
  533. {
  534. struct seg6_local_lwt *slwt = seg6_local_lwtunnel(lwt);
  535. unsigned long attrs;
  536. int nlsize;
  537. nlsize = nla_total_size(4); /* action */
  538. attrs = slwt->desc->attrs;
  539. if (attrs & (1 << SEG6_LOCAL_SRH))
  540. nlsize += nla_total_size((slwt->srh->hdrlen + 1) << 3);
  541. if (attrs & (1 << SEG6_LOCAL_TABLE))
  542. nlsize += nla_total_size(4);
  543. if (attrs & (1 << SEG6_LOCAL_NH4))
  544. nlsize += nla_total_size(4);
  545. if (attrs & (1 << SEG6_LOCAL_NH6))
  546. nlsize += nla_total_size(16);
  547. if (attrs & (1 << SEG6_LOCAL_IIF))
  548. nlsize += nla_total_size(4);
  549. if (attrs & (1 << SEG6_LOCAL_OIF))
  550. nlsize += nla_total_size(4);
  551. return nlsize;
  552. }
  553. static int seg6_local_cmp_encap(struct lwtunnel_state *a,
  554. struct lwtunnel_state *b)
  555. {
  556. struct seg6_local_lwt *slwt_a, *slwt_b;
  557. struct seg6_action_param *param;
  558. int i;
  559. slwt_a = seg6_local_lwtunnel(a);
  560. slwt_b = seg6_local_lwtunnel(b);
  561. if (slwt_a->action != slwt_b->action)
  562. return 1;
  563. if (slwt_a->desc->attrs != slwt_b->desc->attrs)
  564. return 1;
  565. for (i = 0; i < SEG6_LOCAL_MAX + 1; i++) {
  566. if (slwt_a->desc->attrs & (1 << i)) {
  567. param = &seg6_action_params[i];
  568. if (param->cmp(slwt_a, slwt_b))
  569. return 1;
  570. }
  571. }
  572. return 0;
  573. }
  574. static const struct lwtunnel_encap_ops seg6_local_ops = {
  575. .build_state = seg6_local_build_state,
  576. .destroy_state = seg6_local_destroy_state,
  577. .input = seg6_local_input,
  578. .fill_encap = seg6_local_fill_encap,
  579. .get_encap_size = seg6_local_get_encap_size,
  580. .cmp_encap = seg6_local_cmp_encap,
  581. .owner = THIS_MODULE,
  582. };
  583. int __init seg6_local_init(void)
  584. {
  585. return lwtunnel_encap_add_ops(&seg6_local_ops,
  586. LWTUNNEL_ENCAP_SEG6_LOCAL);
  587. }
  588. void seg6_local_exit(void)
  589. {
  590. lwtunnel_encap_del_ops(&seg6_local_ops, LWTUNNEL_ENCAP_SEG6_LOCAL);
  591. }