root/net/ipv6/seg6_iptunnel.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. seg6_lwt_lwtunnel
  2. seg6_encap_lwtunnel
  3. nla_put_srh
  4. set_tun_src
  5. seg6_make_flowlabel
  6. seg6_do_srh_encap
  7. seg6_do_srh_inline
  8. seg6_do_srh
  9. seg6_input
  10. seg6_output
  11. seg6_build_state
  12. seg6_destroy_state
  13. seg6_fill_encap_info
  14. seg6_encap_nlsize
  15. seg6_encap_cmp
  16. seg6_iptunnel_init
  17. seg6_iptunnel_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  SR-IPv6 implementation
   4  *
   5  *  Author:
   6  *  David Lebrun <david.lebrun@uclouvain.be>
   7  */
   8 
   9 #include <linux/types.h>
  10 #include <linux/skbuff.h>
  11 #include <linux/net.h>
  12 #include <linux/module.h>
  13 #include <net/ip.h>
  14 #include <net/ip_tunnels.h>
  15 #include <net/lwtunnel.h>
  16 #include <net/netevent.h>
  17 #include <net/netns/generic.h>
  18 #include <net/ip6_fib.h>
  19 #include <net/route.h>
  20 #include <net/seg6.h>
  21 #include <linux/seg6.h>
  22 #include <linux/seg6_iptunnel.h>
  23 #include <net/addrconf.h>
  24 #include <net/ip6_route.h>
  25 #include <net/dst_cache.h>
  26 #ifdef CONFIG_IPV6_SEG6_HMAC
  27 #include <net/seg6_hmac.h>
  28 #endif
  29 
  30 struct seg6_lwt {
  31         struct dst_cache cache;
  32         struct seg6_iptunnel_encap tuninfo[0];
  33 };
  34 
  35 static inline struct seg6_lwt *seg6_lwt_lwtunnel(struct lwtunnel_state *lwt)
  36 {
  37         return (struct seg6_lwt *)lwt->data;
  38 }
  39 
  40 static inline struct seg6_iptunnel_encap *
  41 seg6_encap_lwtunnel(struct lwtunnel_state *lwt)
  42 {
  43         return seg6_lwt_lwtunnel(lwt)->tuninfo;
  44 }
  45 
  46 static const struct nla_policy seg6_iptunnel_policy[SEG6_IPTUNNEL_MAX + 1] = {
  47         [SEG6_IPTUNNEL_SRH]     = { .type = NLA_BINARY },
  48 };
  49 
  50 static int nla_put_srh(struct sk_buff *skb, int attrtype,
  51                        struct seg6_iptunnel_encap *tuninfo)
  52 {
  53         struct seg6_iptunnel_encap *data;
  54         struct nlattr *nla;
  55         int len;
  56 
  57         len = SEG6_IPTUN_ENCAP_SIZE(tuninfo);
  58 
  59         nla = nla_reserve(skb, attrtype, len);
  60         if (!nla)
  61                 return -EMSGSIZE;
  62 
  63         data = nla_data(nla);
  64         memcpy(data, tuninfo, len);
  65 
  66         return 0;
  67 }
  68 
  69 static void set_tun_src(struct net *net, struct net_device *dev,
  70                         struct in6_addr *daddr, struct in6_addr *saddr)
  71 {
  72         struct seg6_pernet_data *sdata = seg6_pernet(net);
  73         struct in6_addr *tun_src;
  74 
  75         rcu_read_lock();
  76 
  77         tun_src = rcu_dereference(sdata->tun_src);
  78 
  79         if (!ipv6_addr_any(tun_src)) {
  80                 memcpy(saddr, tun_src, sizeof(struct in6_addr));
  81         } else {
  82                 ipv6_dev_get_saddr(net, dev, daddr, IPV6_PREFER_SRC_PUBLIC,
  83                                    saddr);
  84         }
  85 
  86         rcu_read_unlock();
  87 }
  88 
  89 /* Compute flowlabel for outer IPv6 header */
  90 static __be32 seg6_make_flowlabel(struct net *net, struct sk_buff *skb,
  91                                   struct ipv6hdr *inner_hdr)
  92 {
  93         int do_flowlabel = net->ipv6.sysctl.seg6_flowlabel;
  94         __be32 flowlabel = 0;
  95         u32 hash;
  96 
  97         if (do_flowlabel > 0) {
  98                 hash = skb_get_hash(skb);
  99                 hash = rol32(hash, 16);
 100                 flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
 101         } else if (!do_flowlabel && skb->protocol == htons(ETH_P_IPV6)) {
 102                 flowlabel = ip6_flowlabel(inner_hdr);
 103         }
 104         return flowlabel;
 105 }
 106 
 107 /* encapsulate an IPv6 packet within an outer IPv6 header with a given SRH */
 108 int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
 109 {
 110         struct dst_entry *dst = skb_dst(skb);
 111         struct net *net = dev_net(dst->dev);
 112         struct ipv6hdr *hdr, *inner_hdr;
 113         struct ipv6_sr_hdr *isrh;
 114         int hdrlen, tot_len, err;
 115         __be32 flowlabel;
 116 
 117         hdrlen = (osrh->hdrlen + 1) << 3;
 118         tot_len = hdrlen + sizeof(*hdr);
 119 
 120         err = skb_cow_head(skb, tot_len + skb->mac_len);
 121         if (unlikely(err))
 122                 return err;
 123 
 124         inner_hdr = ipv6_hdr(skb);
 125         flowlabel = seg6_make_flowlabel(net, skb, inner_hdr);
 126 
 127         skb_push(skb, tot_len);
 128         skb_reset_network_header(skb);
 129         skb_mac_header_rebuild(skb);
 130         hdr = ipv6_hdr(skb);
 131 
 132         /* inherit tc, flowlabel and hlim
 133          * hlim will be decremented in ip6_forward() afterwards and
 134          * decapsulation will overwrite inner hlim with outer hlim
 135          */
 136 
 137         if (skb->protocol == htons(ETH_P_IPV6)) {
 138                 ip6_flow_hdr(hdr, ip6_tclass(ip6_flowinfo(inner_hdr)),
 139                              flowlabel);
 140                 hdr->hop_limit = inner_hdr->hop_limit;
 141         } else {
 142                 ip6_flow_hdr(hdr, 0, flowlabel);
 143                 hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb));
 144 
 145                 memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
 146         }
 147 
 148         hdr->nexthdr = NEXTHDR_ROUTING;
 149 
 150         isrh = (void *)hdr + sizeof(*hdr);
 151         memcpy(isrh, osrh, hdrlen);
 152 
 153         isrh->nexthdr = proto;
 154 
 155         hdr->daddr = isrh->segments[isrh->first_segment];
 156         set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
 157 
 158 #ifdef CONFIG_IPV6_SEG6_HMAC
 159         if (sr_has_hmac(isrh)) {
 160                 err = seg6_push_hmac(net, &hdr->saddr, isrh);
 161                 if (unlikely(err))
 162                         return err;
 163         }
 164 #endif
 165 
 166         skb_postpush_rcsum(skb, hdr, tot_len);
 167 
 168         return 0;
 169 }
 170 EXPORT_SYMBOL_GPL(seg6_do_srh_encap);
 171 
 172 /* insert an SRH within an IPv6 packet, just after the IPv6 header */
 173 int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
 174 {
 175         struct ipv6hdr *hdr, *oldhdr;
 176         struct ipv6_sr_hdr *isrh;
 177         int hdrlen, err;
 178 
 179         hdrlen = (osrh->hdrlen + 1) << 3;
 180 
 181         err = skb_cow_head(skb, hdrlen + skb->mac_len);
 182         if (unlikely(err))
 183                 return err;
 184 
 185         oldhdr = ipv6_hdr(skb);
 186 
 187         skb_pull(skb, sizeof(struct ipv6hdr));
 188         skb_postpull_rcsum(skb, skb_network_header(skb),
 189                            sizeof(struct ipv6hdr));
 190 
 191         skb_push(skb, sizeof(struct ipv6hdr) + hdrlen);
 192         skb_reset_network_header(skb);
 193         skb_mac_header_rebuild(skb);
 194 
 195         hdr = ipv6_hdr(skb);
 196 
 197         memmove(hdr, oldhdr, sizeof(*hdr));
 198 
 199         isrh = (void *)hdr + sizeof(*hdr);
 200         memcpy(isrh, osrh, hdrlen);
 201 
 202         isrh->nexthdr = hdr->nexthdr;
 203         hdr->nexthdr = NEXTHDR_ROUTING;
 204 
 205         isrh->segments[0] = hdr->daddr;
 206         hdr->daddr = isrh->segments[isrh->first_segment];
 207 
 208 #ifdef CONFIG_IPV6_SEG6_HMAC
 209         if (sr_has_hmac(isrh)) {
 210                 struct net *net = dev_net(skb_dst(skb)->dev);
 211 
 212                 err = seg6_push_hmac(net, &hdr->saddr, isrh);
 213                 if (unlikely(err))
 214                         return err;
 215         }
 216 #endif
 217 
 218         skb_postpush_rcsum(skb, hdr, sizeof(struct ipv6hdr) + hdrlen);
 219 
 220         return 0;
 221 }
 222 EXPORT_SYMBOL_GPL(seg6_do_srh_inline);
 223 
 224 static int seg6_do_srh(struct sk_buff *skb)
 225 {
 226         struct dst_entry *dst = skb_dst(skb);
 227         struct seg6_iptunnel_encap *tinfo;
 228         int proto, err = 0;
 229 
 230         tinfo = seg6_encap_lwtunnel(dst->lwtstate);
 231 
 232         switch (tinfo->mode) {
 233         case SEG6_IPTUN_MODE_INLINE:
 234                 if (skb->protocol != htons(ETH_P_IPV6))
 235                         return -EINVAL;
 236 
 237                 err = seg6_do_srh_inline(skb, tinfo->srh);
 238                 if (err)
 239                         return err;
 240                 break;
 241         case SEG6_IPTUN_MODE_ENCAP:
 242                 err = iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6);
 243                 if (err)
 244                         return err;
 245 
 246                 if (skb->protocol == htons(ETH_P_IPV6))
 247                         proto = IPPROTO_IPV6;
 248                 else if (skb->protocol == htons(ETH_P_IP))
 249                         proto = IPPROTO_IPIP;
 250                 else
 251                         return -EINVAL;
 252 
 253                 err = seg6_do_srh_encap(skb, tinfo->srh, proto);
 254                 if (err)
 255                         return err;
 256 
 257                 skb_set_inner_transport_header(skb, skb_transport_offset(skb));
 258                 skb_set_inner_protocol(skb, skb->protocol);
 259                 skb->protocol = htons(ETH_P_IPV6);
 260                 break;
 261         case SEG6_IPTUN_MODE_L2ENCAP:
 262                 if (!skb_mac_header_was_set(skb))
 263                         return -EINVAL;
 264 
 265                 if (pskb_expand_head(skb, skb->mac_len, 0, GFP_ATOMIC) < 0)
 266                         return -ENOMEM;
 267 
 268                 skb_mac_header_rebuild(skb);
 269                 skb_push(skb, skb->mac_len);
 270 
 271                 err = seg6_do_srh_encap(skb, tinfo->srh, NEXTHDR_NONE);
 272                 if (err)
 273                         return err;
 274 
 275                 skb->protocol = htons(ETH_P_IPV6);
 276                 break;
 277         }
 278 
 279         ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
 280         skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 281 
 282         return 0;
 283 }
 284 
 285 static int seg6_input(struct sk_buff *skb)
 286 {
 287         struct dst_entry *orig_dst = skb_dst(skb);
 288         struct dst_entry *dst = NULL;
 289         struct seg6_lwt *slwt;
 290         int err;
 291 
 292         err = seg6_do_srh(skb);
 293         if (unlikely(err)) {
 294                 kfree_skb(skb);
 295                 return err;
 296         }
 297 
 298         slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
 299 
 300         preempt_disable();
 301         dst = dst_cache_get(&slwt->cache);
 302         preempt_enable();
 303 
 304         skb_dst_drop(skb);
 305 
 306         if (!dst) {
 307                 ip6_route_input(skb);
 308                 dst = skb_dst(skb);
 309                 if (!dst->error) {
 310                         preempt_disable();
 311                         dst_cache_set_ip6(&slwt->cache, dst,
 312                                           &ipv6_hdr(skb)->saddr);
 313                         preempt_enable();
 314                 }
 315         } else {
 316                 skb_dst_set(skb, dst);
 317         }
 318 
 319         err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
 320         if (unlikely(err))
 321                 return err;
 322 
 323         return dst_input(skb);
 324 }
 325 
 326 static int seg6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 327 {
 328         struct dst_entry *orig_dst = skb_dst(skb);
 329         struct dst_entry *dst = NULL;
 330         struct seg6_lwt *slwt;
 331         int err = -EINVAL;
 332 
 333         err = seg6_do_srh(skb);
 334         if (unlikely(err))
 335                 goto drop;
 336 
 337         slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
 338 
 339         preempt_disable();
 340         dst = dst_cache_get(&slwt->cache);
 341         preempt_enable();
 342 
 343         if (unlikely(!dst)) {
 344                 struct ipv6hdr *hdr = ipv6_hdr(skb);
 345                 struct flowi6 fl6;
 346 
 347                 memset(&fl6, 0, sizeof(fl6));
 348                 fl6.daddr = hdr->daddr;
 349                 fl6.saddr = hdr->saddr;
 350                 fl6.flowlabel = ip6_flowinfo(hdr);
 351                 fl6.flowi6_mark = skb->mark;
 352                 fl6.flowi6_proto = hdr->nexthdr;
 353 
 354                 dst = ip6_route_output(net, NULL, &fl6);
 355                 if (dst->error) {
 356                         err = dst->error;
 357                         dst_release(dst);
 358                         goto drop;
 359                 }
 360 
 361                 preempt_disable();
 362                 dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr);
 363                 preempt_enable();
 364         }
 365 
 366         skb_dst_drop(skb);
 367         skb_dst_set(skb, dst);
 368 
 369         err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
 370         if (unlikely(err))
 371                 goto drop;
 372 
 373         return dst_output(net, sk, skb);
 374 drop:
 375         kfree_skb(skb);
 376         return err;
 377 }
 378 
 379 static int seg6_build_state(struct nlattr *nla,
 380                             unsigned int family, const void *cfg,
 381                             struct lwtunnel_state **ts,
 382                             struct netlink_ext_ack *extack)
 383 {
 384         struct nlattr *tb[SEG6_IPTUNNEL_MAX + 1];
 385         struct seg6_iptunnel_encap *tuninfo;
 386         struct lwtunnel_state *newts;
 387         int tuninfo_len, min_size;
 388         struct seg6_lwt *slwt;
 389         int err;
 390 
 391         if (family != AF_INET && family != AF_INET6)
 392                 return -EINVAL;
 393 
 394         err = nla_parse_nested_deprecated(tb, SEG6_IPTUNNEL_MAX, nla,
 395                                           seg6_iptunnel_policy, extack);
 396 
 397         if (err < 0)
 398                 return err;
 399 
 400         if (!tb[SEG6_IPTUNNEL_SRH])
 401                 return -EINVAL;
 402 
 403         tuninfo = nla_data(tb[SEG6_IPTUNNEL_SRH]);
 404         tuninfo_len = nla_len(tb[SEG6_IPTUNNEL_SRH]);
 405 
 406         /* tuninfo must contain at least the iptunnel encap structure,
 407          * the SRH and one segment
 408          */
 409         min_size = sizeof(*tuninfo) + sizeof(struct ipv6_sr_hdr) +
 410                    sizeof(struct in6_addr);
 411         if (tuninfo_len < min_size)
 412                 return -EINVAL;
 413 
 414         switch (tuninfo->mode) {
 415         case SEG6_IPTUN_MODE_INLINE:
 416                 if (family != AF_INET6)
 417                         return -EINVAL;
 418 
 419                 break;
 420         case SEG6_IPTUN_MODE_ENCAP:
 421                 break;
 422         case SEG6_IPTUN_MODE_L2ENCAP:
 423                 break;
 424         default:
 425                 return -EINVAL;
 426         }
 427 
 428         /* verify that SRH is consistent */
 429         if (!seg6_validate_srh(tuninfo->srh, tuninfo_len - sizeof(*tuninfo)))
 430                 return -EINVAL;
 431 
 432         newts = lwtunnel_state_alloc(tuninfo_len + sizeof(*slwt));
 433         if (!newts)
 434                 return -ENOMEM;
 435 
 436         slwt = seg6_lwt_lwtunnel(newts);
 437 
 438         err = dst_cache_init(&slwt->cache, GFP_ATOMIC);
 439         if (err) {
 440                 kfree(newts);
 441                 return err;
 442         }
 443 
 444         memcpy(&slwt->tuninfo, tuninfo, tuninfo_len);
 445 
 446         newts->type = LWTUNNEL_ENCAP_SEG6;
 447         newts->flags |= LWTUNNEL_STATE_INPUT_REDIRECT;
 448 
 449         if (tuninfo->mode != SEG6_IPTUN_MODE_L2ENCAP)
 450                 newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT;
 451 
 452         newts->headroom = seg6_lwt_headroom(tuninfo);
 453 
 454         *ts = newts;
 455 
 456         return 0;
 457 }
 458 
 459 static void seg6_destroy_state(struct lwtunnel_state *lwt)
 460 {
 461         dst_cache_destroy(&seg6_lwt_lwtunnel(lwt)->cache);
 462 }
 463 
 464 static int seg6_fill_encap_info(struct sk_buff *skb,
 465                                 struct lwtunnel_state *lwtstate)
 466 {
 467         struct seg6_iptunnel_encap *tuninfo = seg6_encap_lwtunnel(lwtstate);
 468 
 469         if (nla_put_srh(skb, SEG6_IPTUNNEL_SRH, tuninfo))
 470                 return -EMSGSIZE;
 471 
 472         return 0;
 473 }
 474 
 475 static int seg6_encap_nlsize(struct lwtunnel_state *lwtstate)
 476 {
 477         struct seg6_iptunnel_encap *tuninfo = seg6_encap_lwtunnel(lwtstate);
 478 
 479         return nla_total_size(SEG6_IPTUN_ENCAP_SIZE(tuninfo));
 480 }
 481 
 482 static int seg6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
 483 {
 484         struct seg6_iptunnel_encap *a_hdr = seg6_encap_lwtunnel(a);
 485         struct seg6_iptunnel_encap *b_hdr = seg6_encap_lwtunnel(b);
 486         int len = SEG6_IPTUN_ENCAP_SIZE(a_hdr);
 487 
 488         if (len != SEG6_IPTUN_ENCAP_SIZE(b_hdr))
 489                 return 1;
 490 
 491         return memcmp(a_hdr, b_hdr, len);
 492 }
 493 
 494 static const struct lwtunnel_encap_ops seg6_iptun_ops = {
 495         .build_state = seg6_build_state,
 496         .destroy_state = seg6_destroy_state,
 497         .output = seg6_output,
 498         .input = seg6_input,
 499         .fill_encap = seg6_fill_encap_info,
 500         .get_encap_size = seg6_encap_nlsize,
 501         .cmp_encap = seg6_encap_cmp,
 502         .owner = THIS_MODULE,
 503 };
 504 
 505 int __init seg6_iptunnel_init(void)
 506 {
 507         return lwtunnel_encap_add_ops(&seg6_iptun_ops, LWTUNNEL_ENCAP_SEG6);
 508 }
 509 
 510 void seg6_iptunnel_exit(void)
 511 {
 512         lwtunnel_encap_del_ops(&seg6_iptun_ops, LWTUNNEL_ENCAP_SEG6);
 513 }

/* [<][>][^][v][top][bottom][index][help] */