root/net/mpls/mpls_gso.c

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

DEFINITIONS

This source file includes following definitions.
  1. mpls_gso_segment
  2. mpls_gso_init
  3. mpls_gso_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *      MPLS GSO Support
   4  *
   5  *      Authors: Simon Horman (horms@verge.net.au)
   6  *
   7  *      Based on: GSO portions of net/ipv4/gre.c
   8  */
   9 
  10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  11 
  12 #include <linux/err.h>
  13 #include <linux/module.h>
  14 #include <linux/netdev_features.h>
  15 #include <linux/netdevice.h>
  16 #include <linux/skbuff.h>
  17 
  18 static struct sk_buff *mpls_gso_segment(struct sk_buff *skb,
  19                                        netdev_features_t features)
  20 {
  21         struct sk_buff *segs = ERR_PTR(-EINVAL);
  22         u16 mac_offset = skb->mac_header;
  23         netdev_features_t mpls_features;
  24         u16 mac_len = skb->mac_len;
  25         __be16 mpls_protocol;
  26         unsigned int mpls_hlen;
  27 
  28         skb_reset_network_header(skb);
  29         mpls_hlen = skb_inner_network_header(skb) - skb_network_header(skb);
  30         if (unlikely(!pskb_may_pull(skb, mpls_hlen)))
  31                 goto out;
  32 
  33         /* Setup inner SKB. */
  34         mpls_protocol = skb->protocol;
  35         skb->protocol = skb->inner_protocol;
  36 
  37         __skb_pull(skb, mpls_hlen);
  38 
  39         skb->mac_len = 0;
  40         skb_reset_mac_header(skb);
  41 
  42         /* Segment inner packet. */
  43         mpls_features = skb->dev->mpls_features & features;
  44         segs = skb_mac_gso_segment(skb, mpls_features);
  45         if (IS_ERR_OR_NULL(segs)) {
  46                 skb_gso_error_unwind(skb, mpls_protocol, mpls_hlen, mac_offset,
  47                                      mac_len);
  48                 goto out;
  49         }
  50         skb = segs;
  51 
  52         mpls_hlen += mac_len;
  53         do {
  54                 skb->mac_len = mac_len;
  55                 skb->protocol = mpls_protocol;
  56 
  57                 skb_reset_inner_network_header(skb);
  58 
  59                 __skb_push(skb, mpls_hlen);
  60 
  61                 skb_reset_mac_header(skb);
  62                 skb_set_network_header(skb, mac_len);
  63         } while ((skb = skb->next));
  64 
  65 out:
  66         return segs;
  67 }
  68 
  69 static struct packet_offload mpls_mc_offload __read_mostly = {
  70         .type = cpu_to_be16(ETH_P_MPLS_MC),
  71         .priority = 15,
  72         .callbacks = {
  73                 .gso_segment    =       mpls_gso_segment,
  74         },
  75 };
  76 
  77 static struct packet_offload mpls_uc_offload __read_mostly = {
  78         .type = cpu_to_be16(ETH_P_MPLS_UC),
  79         .priority = 15,
  80         .callbacks = {
  81                 .gso_segment    =       mpls_gso_segment,
  82         },
  83 };
  84 
  85 static int __init mpls_gso_init(void)
  86 {
  87         pr_info("MPLS GSO support\n");
  88 
  89         dev_add_offload(&mpls_uc_offload);
  90         dev_add_offload(&mpls_mc_offload);
  91 
  92         return 0;
  93 }
  94 
  95 static void __exit mpls_gso_exit(void)
  96 {
  97         dev_remove_offload(&mpls_uc_offload);
  98         dev_remove_offload(&mpls_mc_offload);
  99 }
 100 
 101 module_init(mpls_gso_init);
 102 module_exit(mpls_gso_exit);
 103 
 104 MODULE_DESCRIPTION("MPLS GSO support");
 105 MODULE_AUTHOR("Simon Horman (horms@verge.net.au)");
 106 MODULE_LICENSE("GPL");

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