0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/types.h>
0010 #include <linux/skbuff.h>
0011 #include <linux/net.h>
0012 #include <linux/module.h>
0013 #include <net/ip.h>
0014 #include <net/ip_tunnels.h>
0015 #include <net/lwtunnel.h>
0016 #include <net/netevent.h>
0017 #include <net/netns/generic.h>
0018 #include <net/ip6_fib.h>
0019 #include <net/route.h>
0020 #include <net/seg6.h>
0021 #include <linux/seg6.h>
0022 #include <linux/seg6_iptunnel.h>
0023 #include <net/addrconf.h>
0024 #include <net/ip6_route.h>
0025 #include <net/dst_cache.h>
0026 #ifdef CONFIG_IPV6_SEG6_HMAC
0027 #include <net/seg6_hmac.h>
0028 #endif
0029 #include <linux/netfilter.h>
0030
0031 static size_t seg6_lwt_headroom(struct seg6_iptunnel_encap *tuninfo)
0032 {
0033 int head = 0;
0034
0035 switch (tuninfo->mode) {
0036 case SEG6_IPTUN_MODE_INLINE:
0037 break;
0038 case SEG6_IPTUN_MODE_ENCAP:
0039 case SEG6_IPTUN_MODE_ENCAP_RED:
0040 head = sizeof(struct ipv6hdr);
0041 break;
0042 case SEG6_IPTUN_MODE_L2ENCAP:
0043 case SEG6_IPTUN_MODE_L2ENCAP_RED:
0044 return 0;
0045 }
0046
0047 return ((tuninfo->srh->hdrlen + 1) << 3) + head;
0048 }
0049
0050 struct seg6_lwt {
0051 struct dst_cache cache;
0052 struct seg6_iptunnel_encap tuninfo[];
0053 };
0054
0055 static inline struct seg6_lwt *seg6_lwt_lwtunnel(struct lwtunnel_state *lwt)
0056 {
0057 return (struct seg6_lwt *)lwt->data;
0058 }
0059
0060 static inline struct seg6_iptunnel_encap *
0061 seg6_encap_lwtunnel(struct lwtunnel_state *lwt)
0062 {
0063 return seg6_lwt_lwtunnel(lwt)->tuninfo;
0064 }
0065
0066 static const struct nla_policy seg6_iptunnel_policy[SEG6_IPTUNNEL_MAX + 1] = {
0067 [SEG6_IPTUNNEL_SRH] = { .type = NLA_BINARY },
0068 };
0069
0070 static int nla_put_srh(struct sk_buff *skb, int attrtype,
0071 struct seg6_iptunnel_encap *tuninfo)
0072 {
0073 struct seg6_iptunnel_encap *data;
0074 struct nlattr *nla;
0075 int len;
0076
0077 len = SEG6_IPTUN_ENCAP_SIZE(tuninfo);
0078
0079 nla = nla_reserve(skb, attrtype, len);
0080 if (!nla)
0081 return -EMSGSIZE;
0082
0083 data = nla_data(nla);
0084 memcpy(data, tuninfo, len);
0085
0086 return 0;
0087 }
0088
0089 static void set_tun_src(struct net *net, struct net_device *dev,
0090 struct in6_addr *daddr, struct in6_addr *saddr)
0091 {
0092 struct seg6_pernet_data *sdata = seg6_pernet(net);
0093 struct in6_addr *tun_src;
0094
0095 rcu_read_lock();
0096
0097 tun_src = rcu_dereference(sdata->tun_src);
0098
0099 if (!ipv6_addr_any(tun_src)) {
0100 memcpy(saddr, tun_src, sizeof(struct in6_addr));
0101 } else {
0102 ipv6_dev_get_saddr(net, dev, daddr, IPV6_PREFER_SRC_PUBLIC,
0103 saddr);
0104 }
0105
0106 rcu_read_unlock();
0107 }
0108
0109
0110 static __be32 seg6_make_flowlabel(struct net *net, struct sk_buff *skb,
0111 struct ipv6hdr *inner_hdr)
0112 {
0113 int do_flowlabel = net->ipv6.sysctl.seg6_flowlabel;
0114 __be32 flowlabel = 0;
0115 u32 hash;
0116
0117 if (do_flowlabel > 0) {
0118 hash = skb_get_hash(skb);
0119 hash = rol32(hash, 16);
0120 flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
0121 } else if (!do_flowlabel && skb->protocol == htons(ETH_P_IPV6)) {
0122 flowlabel = ip6_flowlabel(inner_hdr);
0123 }
0124 return flowlabel;
0125 }
0126
0127
0128 int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
0129 {
0130 struct dst_entry *dst = skb_dst(skb);
0131 struct net *net = dev_net(dst->dev);
0132 struct ipv6hdr *hdr, *inner_hdr;
0133 struct ipv6_sr_hdr *isrh;
0134 int hdrlen, tot_len, err;
0135 __be32 flowlabel;
0136
0137 hdrlen = (osrh->hdrlen + 1) << 3;
0138 tot_len = hdrlen + sizeof(*hdr);
0139
0140 err = skb_cow_head(skb, tot_len + skb->mac_len);
0141 if (unlikely(err))
0142 return err;
0143
0144 inner_hdr = ipv6_hdr(skb);
0145 flowlabel = seg6_make_flowlabel(net, skb, inner_hdr);
0146
0147 skb_push(skb, tot_len);
0148 skb_reset_network_header(skb);
0149 skb_mac_header_rebuild(skb);
0150 hdr = ipv6_hdr(skb);
0151
0152
0153
0154
0155
0156
0157 if (skb->protocol == htons(ETH_P_IPV6)) {
0158 ip6_flow_hdr(hdr, ip6_tclass(ip6_flowinfo(inner_hdr)),
0159 flowlabel);
0160 hdr->hop_limit = inner_hdr->hop_limit;
0161 } else {
0162 ip6_flow_hdr(hdr, 0, flowlabel);
0163 hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb));
0164
0165 memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
0166
0167
0168
0169
0170
0171
0172
0173 IP6CB(skb)->iif = skb->skb_iif;
0174 }
0175
0176 hdr->nexthdr = NEXTHDR_ROUTING;
0177
0178 isrh = (void *)hdr + sizeof(*hdr);
0179 memcpy(isrh, osrh, hdrlen);
0180
0181 isrh->nexthdr = proto;
0182
0183 hdr->daddr = isrh->segments[isrh->first_segment];
0184 set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
0185
0186 #ifdef CONFIG_IPV6_SEG6_HMAC
0187 if (sr_has_hmac(isrh)) {
0188 err = seg6_push_hmac(net, &hdr->saddr, isrh);
0189 if (unlikely(err))
0190 return err;
0191 }
0192 #endif
0193
0194 hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
0195
0196 skb_postpush_rcsum(skb, hdr, tot_len);
0197
0198 return 0;
0199 }
0200 EXPORT_SYMBOL_GPL(seg6_do_srh_encap);
0201
0202
0203 static int seg6_do_srh_encap_red(struct sk_buff *skb,
0204 struct ipv6_sr_hdr *osrh, int proto)
0205 {
0206 __u8 first_seg = osrh->first_segment;
0207 struct dst_entry *dst = skb_dst(skb);
0208 struct net *net = dev_net(dst->dev);
0209 struct ipv6hdr *hdr, *inner_hdr;
0210 int hdrlen = ipv6_optlen(osrh);
0211 int red_tlv_offset, tlv_offset;
0212 struct ipv6_sr_hdr *isrh;
0213 bool skip_srh = false;
0214 __be32 flowlabel;
0215 int tot_len, err;
0216 int red_hdrlen;
0217 int tlvs_len;
0218
0219 if (first_seg > 0) {
0220 red_hdrlen = hdrlen - sizeof(struct in6_addr);
0221 } else {
0222
0223
0224
0225
0226 skip_srh = !sr_has_hmac(osrh);
0227
0228 red_hdrlen = skip_srh ? 0 : hdrlen;
0229 }
0230
0231 tot_len = red_hdrlen + sizeof(struct ipv6hdr);
0232
0233 err = skb_cow_head(skb, tot_len + skb->mac_len);
0234 if (unlikely(err))
0235 return err;
0236
0237 inner_hdr = ipv6_hdr(skb);
0238 flowlabel = seg6_make_flowlabel(net, skb, inner_hdr);
0239
0240 skb_push(skb, tot_len);
0241 skb_reset_network_header(skb);
0242 skb_mac_header_rebuild(skb);
0243 hdr = ipv6_hdr(skb);
0244
0245
0246 if (skb->protocol == htons(ETH_P_IPV6)) {
0247 ip6_flow_hdr(hdr, ip6_tclass(ip6_flowinfo(inner_hdr)),
0248 flowlabel);
0249 hdr->hop_limit = inner_hdr->hop_limit;
0250 } else {
0251 ip6_flow_hdr(hdr, 0, flowlabel);
0252 hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb));
0253
0254 memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
0255 IP6CB(skb)->iif = skb->skb_iif;
0256 }
0257
0258
0259
0260
0261 hdr->daddr = osrh->segments[first_seg];
0262
0263 if (skip_srh) {
0264 hdr->nexthdr = proto;
0265
0266 set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
0267 goto out;
0268 }
0269
0270
0271
0272 hdr->nexthdr = NEXTHDR_ROUTING;
0273 isrh = (void *)hdr + sizeof(struct ipv6hdr);
0274
0275 if (unlikely(!first_seg)) {
0276
0277
0278
0279
0280 memcpy(isrh, osrh, hdrlen);
0281 goto srcaddr;
0282 }
0283
0284 tlv_offset = sizeof(*osrh) + (first_seg + 1) * sizeof(struct in6_addr);
0285 red_tlv_offset = tlv_offset - sizeof(struct in6_addr);
0286
0287 memcpy(isrh, osrh, red_tlv_offset);
0288
0289 tlvs_len = hdrlen - tlv_offset;
0290 if (unlikely(tlvs_len > 0)) {
0291 const void *s = (const void *)osrh + tlv_offset;
0292 void *d = (void *)isrh + red_tlv_offset;
0293
0294 memcpy(d, s, tlvs_len);
0295 }
0296
0297 --isrh->first_segment;
0298 isrh->hdrlen -= 2;
0299
0300 srcaddr:
0301 isrh->nexthdr = proto;
0302 set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
0303
0304 #ifdef CONFIG_IPV6_SEG6_HMAC
0305 if (unlikely(!skip_srh && sr_has_hmac(isrh))) {
0306 err = seg6_push_hmac(net, &hdr->saddr, isrh);
0307 if (unlikely(err))
0308 return err;
0309 }
0310 #endif
0311
0312 out:
0313 hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
0314
0315 skb_postpush_rcsum(skb, hdr, tot_len);
0316
0317 return 0;
0318 }
0319
0320
0321 int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
0322 {
0323 struct ipv6hdr *hdr, *oldhdr;
0324 struct ipv6_sr_hdr *isrh;
0325 int hdrlen, err;
0326
0327 hdrlen = (osrh->hdrlen + 1) << 3;
0328
0329 err = skb_cow_head(skb, hdrlen + skb->mac_len);
0330 if (unlikely(err))
0331 return err;
0332
0333 oldhdr = ipv6_hdr(skb);
0334
0335 skb_pull(skb, sizeof(struct ipv6hdr));
0336 skb_postpull_rcsum(skb, skb_network_header(skb),
0337 sizeof(struct ipv6hdr));
0338
0339 skb_push(skb, sizeof(struct ipv6hdr) + hdrlen);
0340 skb_reset_network_header(skb);
0341 skb_mac_header_rebuild(skb);
0342
0343 hdr = ipv6_hdr(skb);
0344
0345 memmove(hdr, oldhdr, sizeof(*hdr));
0346
0347 isrh = (void *)hdr + sizeof(*hdr);
0348 memcpy(isrh, osrh, hdrlen);
0349
0350 isrh->nexthdr = hdr->nexthdr;
0351 hdr->nexthdr = NEXTHDR_ROUTING;
0352
0353 isrh->segments[0] = hdr->daddr;
0354 hdr->daddr = isrh->segments[isrh->first_segment];
0355
0356 #ifdef CONFIG_IPV6_SEG6_HMAC
0357 if (sr_has_hmac(isrh)) {
0358 struct net *net = dev_net(skb_dst(skb)->dev);
0359
0360 err = seg6_push_hmac(net, &hdr->saddr, isrh);
0361 if (unlikely(err))
0362 return err;
0363 }
0364 #endif
0365
0366 hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
0367
0368 skb_postpush_rcsum(skb, hdr, sizeof(struct ipv6hdr) + hdrlen);
0369
0370 return 0;
0371 }
0372 EXPORT_SYMBOL_GPL(seg6_do_srh_inline);
0373
0374 static int seg6_do_srh(struct sk_buff *skb)
0375 {
0376 struct dst_entry *dst = skb_dst(skb);
0377 struct seg6_iptunnel_encap *tinfo;
0378 int proto, err = 0;
0379
0380 tinfo = seg6_encap_lwtunnel(dst->lwtstate);
0381
0382 switch (tinfo->mode) {
0383 case SEG6_IPTUN_MODE_INLINE:
0384 if (skb->protocol != htons(ETH_P_IPV6))
0385 return -EINVAL;
0386
0387 err = seg6_do_srh_inline(skb, tinfo->srh);
0388 if (err)
0389 return err;
0390 break;
0391 case SEG6_IPTUN_MODE_ENCAP:
0392 case SEG6_IPTUN_MODE_ENCAP_RED:
0393 err = iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6);
0394 if (err)
0395 return err;
0396
0397 if (skb->protocol == htons(ETH_P_IPV6))
0398 proto = IPPROTO_IPV6;
0399 else if (skb->protocol == htons(ETH_P_IP))
0400 proto = IPPROTO_IPIP;
0401 else
0402 return -EINVAL;
0403
0404 if (tinfo->mode == SEG6_IPTUN_MODE_ENCAP)
0405 err = seg6_do_srh_encap(skb, tinfo->srh, proto);
0406 else
0407 err = seg6_do_srh_encap_red(skb, tinfo->srh, proto);
0408
0409 if (err)
0410 return err;
0411
0412 skb_set_inner_transport_header(skb, skb_transport_offset(skb));
0413 skb_set_inner_protocol(skb, skb->protocol);
0414 skb->protocol = htons(ETH_P_IPV6);
0415 break;
0416 case SEG6_IPTUN_MODE_L2ENCAP:
0417 case SEG6_IPTUN_MODE_L2ENCAP_RED:
0418 if (!skb_mac_header_was_set(skb))
0419 return -EINVAL;
0420
0421 if (pskb_expand_head(skb, skb->mac_len, 0, GFP_ATOMIC) < 0)
0422 return -ENOMEM;
0423
0424 skb_mac_header_rebuild(skb);
0425 skb_push(skb, skb->mac_len);
0426
0427 if (tinfo->mode == SEG6_IPTUN_MODE_L2ENCAP)
0428 err = seg6_do_srh_encap(skb, tinfo->srh,
0429 IPPROTO_ETHERNET);
0430 else
0431 err = seg6_do_srh_encap_red(skb, tinfo->srh,
0432 IPPROTO_ETHERNET);
0433
0434 if (err)
0435 return err;
0436
0437 skb->protocol = htons(ETH_P_IPV6);
0438 break;
0439 }
0440
0441 skb_set_transport_header(skb, sizeof(struct ipv6hdr));
0442 nf_reset_ct(skb);
0443
0444 return 0;
0445 }
0446
0447 static int seg6_input_finish(struct net *net, struct sock *sk,
0448 struct sk_buff *skb)
0449 {
0450 return dst_input(skb);
0451 }
0452
0453 static int seg6_input_core(struct net *net, struct sock *sk,
0454 struct sk_buff *skb)
0455 {
0456 struct dst_entry *orig_dst = skb_dst(skb);
0457 struct dst_entry *dst = NULL;
0458 struct seg6_lwt *slwt;
0459 int err;
0460
0461 err = seg6_do_srh(skb);
0462 if (unlikely(err)) {
0463 kfree_skb(skb);
0464 return err;
0465 }
0466
0467 slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
0468
0469 preempt_disable();
0470 dst = dst_cache_get(&slwt->cache);
0471 preempt_enable();
0472
0473 skb_dst_drop(skb);
0474
0475 if (!dst) {
0476 ip6_route_input(skb);
0477 dst = skb_dst(skb);
0478 if (!dst->error) {
0479 preempt_disable();
0480 dst_cache_set_ip6(&slwt->cache, dst,
0481 &ipv6_hdr(skb)->saddr);
0482 preempt_enable();
0483 }
0484 } else {
0485 skb_dst_set(skb, dst);
0486 }
0487
0488 err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
0489 if (unlikely(err))
0490 return err;
0491
0492 if (static_branch_unlikely(&nf_hooks_lwtunnel_enabled))
0493 return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
0494 dev_net(skb->dev), NULL, skb, NULL,
0495 skb_dst(skb)->dev, seg6_input_finish);
0496
0497 return seg6_input_finish(dev_net(skb->dev), NULL, skb);
0498 }
0499
0500 static int seg6_input_nf(struct sk_buff *skb)
0501 {
0502 struct net_device *dev = skb_dst(skb)->dev;
0503 struct net *net = dev_net(skb->dev);
0504
0505 switch (skb->protocol) {
0506 case htons(ETH_P_IP):
0507 return NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, net, NULL,
0508 skb, NULL, dev, seg6_input_core);
0509 case htons(ETH_P_IPV6):
0510 return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, net, NULL,
0511 skb, NULL, dev, seg6_input_core);
0512 }
0513
0514 return -EINVAL;
0515 }
0516
0517 static int seg6_input(struct sk_buff *skb)
0518 {
0519 if (static_branch_unlikely(&nf_hooks_lwtunnel_enabled))
0520 return seg6_input_nf(skb);
0521
0522 return seg6_input_core(dev_net(skb->dev), NULL, skb);
0523 }
0524
0525 static int seg6_output_core(struct net *net, struct sock *sk,
0526 struct sk_buff *skb)
0527 {
0528 struct dst_entry *orig_dst = skb_dst(skb);
0529 struct dst_entry *dst = NULL;
0530 struct seg6_lwt *slwt;
0531 int err;
0532
0533 err = seg6_do_srh(skb);
0534 if (unlikely(err))
0535 goto drop;
0536
0537 slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
0538
0539 preempt_disable();
0540 dst = dst_cache_get(&slwt->cache);
0541 preempt_enable();
0542
0543 if (unlikely(!dst)) {
0544 struct ipv6hdr *hdr = ipv6_hdr(skb);
0545 struct flowi6 fl6;
0546
0547 memset(&fl6, 0, sizeof(fl6));
0548 fl6.daddr = hdr->daddr;
0549 fl6.saddr = hdr->saddr;
0550 fl6.flowlabel = ip6_flowinfo(hdr);
0551 fl6.flowi6_mark = skb->mark;
0552 fl6.flowi6_proto = hdr->nexthdr;
0553
0554 dst = ip6_route_output(net, NULL, &fl6);
0555 if (dst->error) {
0556 err = dst->error;
0557 dst_release(dst);
0558 goto drop;
0559 }
0560
0561 preempt_disable();
0562 dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr);
0563 preempt_enable();
0564 }
0565
0566 skb_dst_drop(skb);
0567 skb_dst_set(skb, dst);
0568
0569 err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
0570 if (unlikely(err))
0571 goto drop;
0572
0573 if (static_branch_unlikely(&nf_hooks_lwtunnel_enabled))
0574 return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk, skb,
0575 NULL, skb_dst(skb)->dev, dst_output);
0576
0577 return dst_output(net, sk, skb);
0578 drop:
0579 kfree_skb(skb);
0580 return err;
0581 }
0582
0583 static int seg6_output_nf(struct net *net, struct sock *sk, struct sk_buff *skb)
0584 {
0585 struct net_device *dev = skb_dst(skb)->dev;
0586
0587 switch (skb->protocol) {
0588 case htons(ETH_P_IP):
0589 return NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, net, sk, skb,
0590 NULL, dev, seg6_output_core);
0591 case htons(ETH_P_IPV6):
0592 return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, net, sk, skb,
0593 NULL, dev, seg6_output_core);
0594 }
0595
0596 return -EINVAL;
0597 }
0598
0599 static int seg6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
0600 {
0601 if (static_branch_unlikely(&nf_hooks_lwtunnel_enabled))
0602 return seg6_output_nf(net, sk, skb);
0603
0604 return seg6_output_core(net, sk, skb);
0605 }
0606
0607 static int seg6_build_state(struct net *net, struct nlattr *nla,
0608 unsigned int family, const void *cfg,
0609 struct lwtunnel_state **ts,
0610 struct netlink_ext_ack *extack)
0611 {
0612 struct nlattr *tb[SEG6_IPTUNNEL_MAX + 1];
0613 struct seg6_iptunnel_encap *tuninfo;
0614 struct lwtunnel_state *newts;
0615 int tuninfo_len, min_size;
0616 struct seg6_lwt *slwt;
0617 int err;
0618
0619 if (family != AF_INET && family != AF_INET6)
0620 return -EINVAL;
0621
0622 err = nla_parse_nested_deprecated(tb, SEG6_IPTUNNEL_MAX, nla,
0623 seg6_iptunnel_policy, extack);
0624
0625 if (err < 0)
0626 return err;
0627
0628 if (!tb[SEG6_IPTUNNEL_SRH])
0629 return -EINVAL;
0630
0631 tuninfo = nla_data(tb[SEG6_IPTUNNEL_SRH]);
0632 tuninfo_len = nla_len(tb[SEG6_IPTUNNEL_SRH]);
0633
0634
0635
0636
0637 min_size = sizeof(*tuninfo) + sizeof(struct ipv6_sr_hdr) +
0638 sizeof(struct in6_addr);
0639 if (tuninfo_len < min_size)
0640 return -EINVAL;
0641
0642 switch (tuninfo->mode) {
0643 case SEG6_IPTUN_MODE_INLINE:
0644 if (family != AF_INET6)
0645 return -EINVAL;
0646
0647 break;
0648 case SEG6_IPTUN_MODE_ENCAP:
0649 break;
0650 case SEG6_IPTUN_MODE_L2ENCAP:
0651 break;
0652 case SEG6_IPTUN_MODE_ENCAP_RED:
0653 break;
0654 case SEG6_IPTUN_MODE_L2ENCAP_RED:
0655 break;
0656 default:
0657 return -EINVAL;
0658 }
0659
0660
0661 if (!seg6_validate_srh(tuninfo->srh, tuninfo_len - sizeof(*tuninfo), false))
0662 return -EINVAL;
0663
0664 newts = lwtunnel_state_alloc(tuninfo_len + sizeof(*slwt));
0665 if (!newts)
0666 return -ENOMEM;
0667
0668 slwt = seg6_lwt_lwtunnel(newts);
0669
0670 err = dst_cache_init(&slwt->cache, GFP_ATOMIC);
0671 if (err) {
0672 kfree(newts);
0673 return err;
0674 }
0675
0676 memcpy(&slwt->tuninfo, tuninfo, tuninfo_len);
0677
0678 newts->type = LWTUNNEL_ENCAP_SEG6;
0679 newts->flags |= LWTUNNEL_STATE_INPUT_REDIRECT;
0680
0681 if (tuninfo->mode != SEG6_IPTUN_MODE_L2ENCAP)
0682 newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT;
0683
0684 newts->headroom = seg6_lwt_headroom(tuninfo);
0685
0686 *ts = newts;
0687
0688 return 0;
0689 }
0690
0691 static void seg6_destroy_state(struct lwtunnel_state *lwt)
0692 {
0693 dst_cache_destroy(&seg6_lwt_lwtunnel(lwt)->cache);
0694 }
0695
0696 static int seg6_fill_encap_info(struct sk_buff *skb,
0697 struct lwtunnel_state *lwtstate)
0698 {
0699 struct seg6_iptunnel_encap *tuninfo = seg6_encap_lwtunnel(lwtstate);
0700
0701 if (nla_put_srh(skb, SEG6_IPTUNNEL_SRH, tuninfo))
0702 return -EMSGSIZE;
0703
0704 return 0;
0705 }
0706
0707 static int seg6_encap_nlsize(struct lwtunnel_state *lwtstate)
0708 {
0709 struct seg6_iptunnel_encap *tuninfo = seg6_encap_lwtunnel(lwtstate);
0710
0711 return nla_total_size(SEG6_IPTUN_ENCAP_SIZE(tuninfo));
0712 }
0713
0714 static int seg6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
0715 {
0716 struct seg6_iptunnel_encap *a_hdr = seg6_encap_lwtunnel(a);
0717 struct seg6_iptunnel_encap *b_hdr = seg6_encap_lwtunnel(b);
0718 int len = SEG6_IPTUN_ENCAP_SIZE(a_hdr);
0719
0720 if (len != SEG6_IPTUN_ENCAP_SIZE(b_hdr))
0721 return 1;
0722
0723 return memcmp(a_hdr, b_hdr, len);
0724 }
0725
0726 static const struct lwtunnel_encap_ops seg6_iptun_ops = {
0727 .build_state = seg6_build_state,
0728 .destroy_state = seg6_destroy_state,
0729 .output = seg6_output,
0730 .input = seg6_input,
0731 .fill_encap = seg6_fill_encap_info,
0732 .get_encap_size = seg6_encap_nlsize,
0733 .cmp_encap = seg6_encap_cmp,
0734 .owner = THIS_MODULE,
0735 };
0736
0737 int __init seg6_iptunnel_init(void)
0738 {
0739 return lwtunnel_encap_add_ops(&seg6_iptun_ops, LWTUNNEL_ENCAP_SEG6);
0740 }
0741
0742 void seg6_iptunnel_exit(void)
0743 {
0744 lwtunnel_encap_del_ops(&seg6_iptun_ops, LWTUNNEL_ENCAP_SEG6);
0745 }