diff options
| -rw-r--r-- | include/linux/netdev_features.h | 4 | ||||
| -rw-r--r-- | include/linux/netdevice.h | 2 | ||||
| -rw-r--r-- | include/linux/skbuff.h | 123 | ||||
| -rw-r--r-- | net/Kconfig | 1 | ||||
| -rw-r--r-- | net/Makefile | 1 | ||||
| -rw-r--r-- | net/core/dev.c | 4 | ||||
| -rw-r--r-- | net/core/ethtool.c | 1 | ||||
| -rw-r--r-- | net/ipv4/af_inet.c | 1 | ||||
| -rw-r--r-- | net/ipv4/tcp.c | 1 | ||||
| -rw-r--r-- | net/ipv4/udp.c | 2 | ||||
| -rw-r--r-- | net/ipv6/ip6_offload.c | 1 | ||||
| -rw-r--r-- | net/ipv6/udp_offload.c | 3 | ||||
| -rw-r--r-- | net/mpls/Kconfig | 9 | ||||
| -rw-r--r-- | net/mpls/Makefile | 4 | ||||
| -rw-r--r-- | net/mpls/mpls_gso.c | 108 |
15 files changed, 149 insertions, 116 deletions
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index 09906b7ca47d..a2a89a5c7be5 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h | |||
| @@ -43,8 +43,9 @@ enum { | |||
| 43 | NETIF_F_FSO_BIT, /* ... FCoE segmentation */ | 43 | NETIF_F_FSO_BIT, /* ... FCoE segmentation */ |
| 44 | NETIF_F_GSO_GRE_BIT, /* ... GRE with TSO */ | 44 | NETIF_F_GSO_GRE_BIT, /* ... GRE with TSO */ |
| 45 | NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */ | 45 | NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */ |
| 46 | NETIF_F_GSO_MPLS_BIT, /* ... MPLS segmentation */ | ||
| 46 | /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */ | 47 | /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */ |
| 47 | NETIF_F_GSO_UDP_TUNNEL_BIT, | 48 | NETIF_F_GSO_MPLS_BIT, |
| 48 | 49 | ||
| 49 | NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */ | 50 | NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */ |
| 50 | NETIF_F_SCTP_CSUM_BIT, /* SCTP checksum offload */ | 51 | NETIF_F_SCTP_CSUM_BIT, /* SCTP checksum offload */ |
| @@ -107,6 +108,7 @@ enum { | |||
| 107 | #define NETIF_F_RXALL __NETIF_F(RXALL) | 108 | #define NETIF_F_RXALL __NETIF_F(RXALL) |
| 108 | #define NETIF_F_GSO_GRE __NETIF_F(GSO_GRE) | 109 | #define NETIF_F_GSO_GRE __NETIF_F(GSO_GRE) |
| 109 | #define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) | 110 | #define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) |
| 111 | #define NETIF_F_GSO_MPLS __NETIF_F(GSO_MPLS) | ||
| 110 | #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) | 112 | #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) |
| 111 | #define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) | 113 | #define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) |
| 112 | #define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX) | 114 | #define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX) |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index ea7b6bce9ea0..6b2bb460d1d7 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
| @@ -1088,6 +1088,8 @@ struct net_device { | |||
| 1088 | * need to set them appropriately. | 1088 | * need to set them appropriately. |
| 1089 | */ | 1089 | */ |
| 1090 | netdev_features_t hw_enc_features; | 1090 | netdev_features_t hw_enc_features; |
| 1091 | /* mask of fetures inheritable by MPLS */ | ||
| 1092 | netdev_features_t mpls_features; | ||
| 1091 | 1093 | ||
| 1092 | /* Interface index. Unique device identifier */ | 1094 | /* Interface index. Unique device identifier */ |
| 1093 | int ifindex; | 1095 | int ifindex; |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 2e0ced1af3b1..8f2b830772a8 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
| @@ -319,6 +319,8 @@ enum { | |||
| 319 | SKB_GSO_GRE = 1 << 6, | 319 | SKB_GSO_GRE = 1 << 6, |
| 320 | 320 | ||
| 321 | SKB_GSO_UDP_TUNNEL = 1 << 7, | 321 | SKB_GSO_UDP_TUNNEL = 1 << 7, |
| 322 | |||
| 323 | SKB_GSO_MPLS = 1 << 8, | ||
| 322 | }; | 324 | }; |
| 323 | 325 | ||
| 324 | #if BITS_PER_LONG > 32 | 326 | #if BITS_PER_LONG > 32 |
| @@ -389,6 +391,7 @@ typedef unsigned char *sk_buff_data_t; | |||
| 389 | * @dropcount: total number of sk_receive_queue overflows | 391 | * @dropcount: total number of sk_receive_queue overflows |
| 390 | * @vlan_proto: vlan encapsulation protocol | 392 | * @vlan_proto: vlan encapsulation protocol |
| 391 | * @vlan_tci: vlan tag control information | 393 | * @vlan_tci: vlan tag control information |
| 394 | * @inner_protocol: Protocol (encapsulation) | ||
| 392 | * @inner_transport_header: Inner transport layer header (encapsulation) | 395 | * @inner_transport_header: Inner transport layer header (encapsulation) |
| 393 | * @inner_network_header: Network layer header (encapsulation) | 396 | * @inner_network_header: Network layer header (encapsulation) |
| 394 | * @inner_mac_header: Link layer header (encapsulation) | 397 | * @inner_mac_header: Link layer header (encapsulation) |
| @@ -509,12 +512,13 @@ struct sk_buff { | |||
| 509 | __u32 reserved_tailroom; | 512 | __u32 reserved_tailroom; |
| 510 | }; | 513 | }; |
| 511 | 514 | ||
| 512 | sk_buff_data_t inner_transport_header; | 515 | __be16 inner_protocol; |
| 513 | sk_buff_data_t inner_network_header; | 516 | __u16 inner_transport_header; |
| 514 | sk_buff_data_t inner_mac_header; | 517 | __u16 inner_network_header; |
| 515 | sk_buff_data_t transport_header; | 518 | __u16 inner_mac_header; |
| 516 | sk_buff_data_t network_header; | 519 | __u16 transport_header; |
| 517 | sk_buff_data_t mac_header; | 520 | __u16 network_header; |
| 521 | __u16 mac_header; | ||
| 518 | /* These elements must be at the end, see alloc_skb() for details. */ | 522 | /* These elements must be at the end, see alloc_skb() for details. */ |
| 519 | sk_buff_data_t tail; | 523 | sk_buff_data_t tail; |
| 520 | sk_buff_data_t end; | 524 | sk_buff_data_t end; |
| @@ -1527,7 +1531,6 @@ static inline void skb_reset_mac_len(struct sk_buff *skb) | |||
| 1527 | skb->mac_len = skb->network_header - skb->mac_header; | 1531 | skb->mac_len = skb->network_header - skb->mac_header; |
| 1528 | } | 1532 | } |
| 1529 | 1533 | ||
| 1530 | #ifdef NET_SKBUFF_DATA_USES_OFFSET | ||
| 1531 | static inline unsigned char *skb_inner_transport_header(const struct sk_buff | 1534 | static inline unsigned char *skb_inner_transport_header(const struct sk_buff |
| 1532 | *skb) | 1535 | *skb) |
| 1533 | { | 1536 | { |
| @@ -1638,112 +1641,6 @@ static inline void skb_set_mac_header(struct sk_buff *skb, const int offset) | |||
| 1638 | skb->mac_header += offset; | 1641 | skb->mac_header += offset; |
| 1639 | } | 1642 | } |
| 1640 | 1643 | ||
| 1641 | #else /* NET_SKBUFF_DATA_USES_OFFSET */ | ||
| 1642 | static inline unsigned char *skb_inner_transport_header(const struct sk_buff | ||
| 1643 | *skb) | ||
| 1644 | { | ||
| 1645 | return skb->inner_transport_header; | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | static inline void skb_reset_inner_transport_header(struct sk_buff *skb) | ||
| 1649 | { | ||
| 1650 | skb->inner_transport_header = skb->data; | ||
| 1651 | } | ||
| 1652 | |||
| 1653 | static inline void skb_set_inner_transport_header(struct sk_buff *skb, | ||
| 1654 | const int offset) | ||
| 1655 | { | ||
| 1656 | skb->inner_transport_header = skb->data + offset; | ||
| 1657 | } | ||
| 1658 | |||
| 1659 | static inline unsigned char *skb_inner_network_header(const struct sk_buff *skb) | ||
| 1660 | { | ||
| 1661 | return skb->inner_network_header; | ||
| 1662 | } | ||
| 1663 | |||
| 1664 | static inline void skb_reset_inner_network_header(struct sk_buff *skb) | ||
| 1665 | { | ||
| 1666 | skb->inner_network_header = skb->data; | ||
| 1667 | } | ||
| 1668 | |||
| 1669 | static inline void skb_set_inner_network_header(struct sk_buff *skb, | ||
| 1670 | const int offset) | ||
| 1671 | { | ||
| 1672 | skb->inner_network_header = skb->data + offset; | ||
| 1673 | } | ||
| 1674 | |||
| 1675 | static inline unsigned char *skb_inner_mac_header(const struct sk_buff *skb) | ||
| 1676 | { | ||
| 1677 | return skb->inner_mac_header; | ||
| 1678 | } | ||
| 1679 | |||
| 1680 | static inline void skb_reset_inner_mac_header(struct sk_buff *skb) | ||
| 1681 | { | ||
| 1682 | skb->inner_mac_header = skb->data; | ||
| 1683 | } | ||
| 1684 | |||
| 1685 | static inline void skb_set_inner_mac_header(struct sk_buff *skb, | ||
| 1686 | const int offset) | ||
| 1687 | { | ||
| 1688 | skb->inner_mac_header = skb->data + offset; | ||
| 1689 | } | ||
| 1690 | static inline bool skb_transport_header_was_set(const struct sk_buff *skb) | ||
| 1691 | { | ||
| 1692 | return skb->transport_header != NULL; | ||
| 1693 | } | ||
| 1694 | |||
| 1695 | static inline unsigned char *skb_transport_header(const struct sk_buff *skb) | ||
| 1696 | { | ||
| 1697 | return skb->transport_header; | ||
| 1698 | } | ||
| 1699 | |||
| 1700 | static inline void skb_reset_transport_header(struct sk_buff *skb) | ||
| 1701 | { | ||
| 1702 | skb->transport_header = skb->data; | ||
| 1703 | } | ||
| 1704 | |||
| 1705 | static inline void skb_set_transport_header(struct sk_buff *skb, | ||
| 1706 | const int offset) | ||
| 1707 | { | ||
| 1708 | skb->transport_header = skb->data + offset; | ||
| 1709 | } | ||
| 1710 | |||
| 1711 | static inline unsigned char *skb_network_header(const struct sk_buff *skb) | ||
| 1712 | { | ||
| 1713 | return skb->network_header; | ||
| 1714 | } | ||
| 1715 | |||
| 1716 | static inline void skb_reset_network_header(struct sk_buff *skb) | ||
| 1717 | { | ||
| 1718 | skb->network_header = skb->data; | ||
| 1719 | } | ||
| 1720 | |||
| 1721 | static inline void skb_set_network_header(struct sk_buff *skb, const int offset) | ||
| 1722 | { | ||
| 1723 | skb->network_header = skb->data + offset; | ||
| 1724 | } | ||
| 1725 | |||
| 1726 | static inline unsigned char *skb_mac_header(const struct sk_buff *skb) | ||
| 1727 | { | ||
| 1728 | return skb->mac_header; | ||
| 1729 | } | ||
| 1730 | |||
| 1731 | static inline int skb_mac_header_was_set(const struct sk_buff *skb) | ||
| 1732 | { | ||
| 1733 | return skb->mac_header != NULL; | ||
| 1734 | } | ||
| 1735 | |||
| 1736 | static inline void skb_reset_mac_header(struct sk_buff *skb) | ||
| 1737 | { | ||
| 1738 | skb->mac_header = skb->data; | ||
| 1739 | } | ||
| 1740 | |||
| 1741 | static inline void skb_set_mac_header(struct sk_buff *skb, const int offset) | ||
| 1742 | { | ||
| 1743 | skb->mac_header = skb->data + offset; | ||
| 1744 | } | ||
| 1745 | #endif /* NET_SKBUFF_DATA_USES_OFFSET */ | ||
| 1746 | |||
| 1747 | static inline void skb_probe_transport_header(struct sk_buff *skb, | 1644 | static inline void skb_probe_transport_header(struct sk_buff *skb, |
| 1748 | const int offset_hint) | 1645 | const int offset_hint) |
| 1749 | { | 1646 | { |
diff --git a/net/Kconfig b/net/Kconfig index 08de901415ee..523e43e6da1b 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
| @@ -218,6 +218,7 @@ source "net/batman-adv/Kconfig" | |||
| 218 | source "net/openvswitch/Kconfig" | 218 | source "net/openvswitch/Kconfig" |
| 219 | source "net/vmw_vsock/Kconfig" | 219 | source "net/vmw_vsock/Kconfig" |
| 220 | source "net/netlink/Kconfig" | 220 | source "net/netlink/Kconfig" |
| 221 | source "net/mpls/Kconfig" | ||
| 221 | 222 | ||
| 222 | config RPS | 223 | config RPS |
| 223 | boolean | 224 | boolean |
diff --git a/net/Makefile b/net/Makefile index 091e7b04f301..9492e8cb64e9 100644 --- a/net/Makefile +++ b/net/Makefile | |||
| @@ -70,3 +70,4 @@ obj-$(CONFIG_BATMAN_ADV) += batman-adv/ | |||
| 70 | obj-$(CONFIG_NFC) += nfc/ | 70 | obj-$(CONFIG_NFC) += nfc/ |
| 71 | obj-$(CONFIG_OPENVSWITCH) += openvswitch/ | 71 | obj-$(CONFIG_OPENVSWITCH) += openvswitch/ |
| 72 | obj-$(CONFIG_VSOCKETS) += vmw_vsock/ | 72 | obj-$(CONFIG_VSOCKETS) += vmw_vsock/ |
| 73 | obj-$(CONFIG_NET_MPLS_GSO) += mpls/ | ||
diff --git a/net/core/dev.c b/net/core/dev.c index 50c02ded1d69..2f09cb29cc95 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -5277,6 +5277,10 @@ int register_netdevice(struct net_device *dev) | |||
| 5277 | */ | 5277 | */ |
| 5278 | dev->hw_enc_features |= NETIF_F_SG; | 5278 | dev->hw_enc_features |= NETIF_F_SG; |
| 5279 | 5279 | ||
| 5280 | /* Make NETIF_F_SG inheritable to MPLS. | ||
| 5281 | */ | ||
| 5282 | dev->mpls_features |= NETIF_F_SG; | ||
| 5283 | |||
| 5280 | ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev); | 5284 | ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev); |
| 5281 | ret = notifier_to_errno(ret); | 5285 | ret = notifier_to_errno(ret); |
| 5282 | if (ret) | 5286 | if (ret) |
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 22efdaa76ebf..4e6f63ade741 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
| @@ -82,6 +82,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] | |||
| 82 | [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation", | 82 | [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation", |
| 83 | [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation", | 83 | [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation", |
| 84 | [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation", | 84 | [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation", |
| 85 | [NETIF_F_GSO_MPLS_BIT] = "tx-mpls-segmentation", | ||
| 85 | 86 | ||
| 86 | [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc", | 87 | [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc", |
| 87 | [NETIF_F_SCTP_CSUM_BIT] = "tx-checksum-sctp", | 88 | [NETIF_F_SCTP_CSUM_BIT] = "tx-checksum-sctp", |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index d01be2a3ae53..b05ae96aec44 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
| @@ -1295,6 +1295,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
| 1295 | SKB_GSO_GRE | | 1295 | SKB_GSO_GRE | |
| 1296 | SKB_GSO_TCPV6 | | 1296 | SKB_GSO_TCPV6 | |
| 1297 | SKB_GSO_UDP_TUNNEL | | 1297 | SKB_GSO_UDP_TUNNEL | |
| 1298 | SKB_GSO_MPLS | | ||
| 1298 | 0))) | 1299 | 0))) |
| 1299 | goto out; | 1300 | goto out; |
| 1300 | 1301 | ||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index d87ce72ca8aa..ba4186e1dca9 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
| @@ -2917,6 +2917,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, | |||
| 2917 | SKB_GSO_TCP_ECN | | 2917 | SKB_GSO_TCP_ECN | |
| 2918 | SKB_GSO_TCPV6 | | 2918 | SKB_GSO_TCPV6 | |
| 2919 | SKB_GSO_GRE | | 2919 | SKB_GSO_GRE | |
| 2920 | SKB_GSO_MPLS | | ||
| 2920 | SKB_GSO_UDP_TUNNEL | | 2921 | SKB_GSO_UDP_TUNNEL | |
| 2921 | 0) || | 2922 | 0) || |
| 2922 | !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))) | 2923 | !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))) |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0bf5d399a03c..aa5eff46d137 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
| @@ -2381,7 +2381,7 @@ struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | |||
| 2381 | 2381 | ||
| 2382 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | | 2382 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | |
| 2383 | SKB_GSO_UDP_TUNNEL | | 2383 | SKB_GSO_UDP_TUNNEL | |
| 2384 | SKB_GSO_GRE) || | 2384 | SKB_GSO_GRE | SKB_GSO_MPLS) || |
| 2385 | !(type & (SKB_GSO_UDP)))) | 2385 | !(type & (SKB_GSO_UDP)))) |
| 2386 | goto out; | 2386 | goto out; |
| 2387 | 2387 | ||
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 71b766ee821d..a263b990ee11 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c | |||
| @@ -98,6 +98,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, | |||
| 98 | SKB_GSO_TCP_ECN | | 98 | SKB_GSO_TCP_ECN | |
| 99 | SKB_GSO_GRE | | 99 | SKB_GSO_GRE | |
| 100 | SKB_GSO_UDP_TUNNEL | | 100 | SKB_GSO_UDP_TUNNEL | |
| 101 | SKB_GSO_MPLS | | ||
| 101 | SKB_GSO_TCPV6 | | 102 | SKB_GSO_TCPV6 | |
| 102 | 0))) | 103 | 0))) |
| 103 | goto out; | 104 | goto out; |
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 3bb3a891a424..76d401a93c7a 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c | |||
| @@ -63,7 +63,8 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | |||
| 63 | if (unlikely(type & ~(SKB_GSO_UDP | | 63 | if (unlikely(type & ~(SKB_GSO_UDP | |
| 64 | SKB_GSO_DODGY | | 64 | SKB_GSO_DODGY | |
| 65 | SKB_GSO_UDP_TUNNEL | | 65 | SKB_GSO_UDP_TUNNEL | |
| 66 | SKB_GSO_GRE) || | 66 | SKB_GSO_GRE | |
| 67 | SKB_GSO_MPLS) || | ||
| 67 | !(type & (SKB_GSO_UDP)))) | 68 | !(type & (SKB_GSO_UDP)))) |
| 68 | goto out; | 69 | goto out; |
| 69 | 70 | ||
diff --git a/net/mpls/Kconfig b/net/mpls/Kconfig new file mode 100644 index 000000000000..37421db88965 --- /dev/null +++ b/net/mpls/Kconfig | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | # | ||
| 2 | # MPLS configuration | ||
| 3 | # | ||
| 4 | config NET_MPLS_GSO | ||
| 5 | tristate "MPLS: GSO support" | ||
| 6 | help | ||
| 7 | This is helper module to allow segmentation of non-MPLS GSO packets | ||
| 8 | that have had MPLS stack entries pushed onto them and thus | ||
| 9 | become MPLS GSO packets. | ||
diff --git a/net/mpls/Makefile b/net/mpls/Makefile new file mode 100644 index 000000000000..0a3c171be537 --- /dev/null +++ b/net/mpls/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | # | ||
| 2 | # Makefile for MPLS. | ||
| 3 | # | ||
| 4 | obj-y += mpls_gso.o | ||
diff --git a/net/mpls/mpls_gso.c b/net/mpls/mpls_gso.c new file mode 100644 index 000000000000..1bec1219ab81 --- /dev/null +++ b/net/mpls/mpls_gso.c | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | /* | ||
| 2 | * MPLS GSO Support | ||
| 3 | * | ||
| 4 | * Authors: Simon Horman (horms@verge.net.au) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * Based on: GSO portions of net/ipv4/gre.c | ||
| 12 | */ | ||
| 13 | |||
| 14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 15 | |||
| 16 | #include <linux/err.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/netdev_features.h> | ||
| 19 | #include <linux/netdevice.h> | ||
| 20 | #include <linux/skbuff.h> | ||
| 21 | |||
| 22 | static struct sk_buff *mpls_gso_segment(struct sk_buff *skb, | ||
| 23 | netdev_features_t features) | ||
| 24 | { | ||
| 25 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 26 | netdev_features_t mpls_features; | ||
| 27 | __be16 mpls_protocol; | ||
| 28 | |||
| 29 | if (unlikely(skb_shinfo(skb)->gso_type & | ||
| 30 | ~(SKB_GSO_TCPV4 | | ||
| 31 | SKB_GSO_TCPV6 | | ||
| 32 | SKB_GSO_UDP | | ||
| 33 | SKB_GSO_DODGY | | ||
| 34 | SKB_GSO_TCP_ECN | | ||
| 35 | SKB_GSO_GRE | | ||
| 36 | SKB_GSO_MPLS))) | ||
| 37 | goto out; | ||
| 38 | |||
| 39 | /* Setup inner SKB. */ | ||
| 40 | mpls_protocol = skb->protocol; | ||
| 41 | skb->protocol = skb->inner_protocol; | ||
| 42 | |||
| 43 | /* Push back the mac header that skb_mac_gso_segment() has pulled. | ||
| 44 | * It will be re-pulled by the call to skb_mac_gso_segment() below | ||
| 45 | */ | ||
| 46 | __skb_push(skb, skb->mac_len); | ||
| 47 | |||
| 48 | /* Segment inner packet. */ | ||
| 49 | mpls_features = skb->dev->mpls_features & netif_skb_features(skb); | ||
| 50 | segs = skb_mac_gso_segment(skb, mpls_features); | ||
| 51 | |||
| 52 | |||
| 53 | /* Restore outer protocol. */ | ||
| 54 | skb->protocol = mpls_protocol; | ||
| 55 | |||
| 56 | /* Re-pull the mac header that the call to skb_mac_gso_segment() | ||
| 57 | * above pulled. It will be re-pushed after returning | ||
| 58 | * skb_mac_gso_segment(), an indirect caller of this function. | ||
| 59 | */ | ||
| 60 | __skb_push(skb, skb->data - skb_mac_header(skb)); | ||
| 61 | |||
| 62 | out: | ||
| 63 | return segs; | ||
| 64 | } | ||
| 65 | |||
| 66 | static int mpls_gso_send_check(struct sk_buff *skb) | ||
| 67 | { | ||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | static struct packet_offload mpls_mc_offload = { | ||
| 72 | .type = cpu_to_be16(ETH_P_MPLS_MC), | ||
| 73 | .callbacks = { | ||
| 74 | .gso_send_check = mpls_gso_send_check, | ||
| 75 | .gso_segment = mpls_gso_segment, | ||
| 76 | }, | ||
| 77 | }; | ||
| 78 | |||
| 79 | static struct packet_offload mpls_uc_offload = { | ||
| 80 | .type = cpu_to_be16(ETH_P_MPLS_UC), | ||
| 81 | .callbacks = { | ||
| 82 | .gso_send_check = mpls_gso_send_check, | ||
| 83 | .gso_segment = mpls_gso_segment, | ||
| 84 | }, | ||
| 85 | }; | ||
| 86 | |||
| 87 | static int __init mpls_gso_init(void) | ||
| 88 | { | ||
| 89 | pr_info("MPLS GSO support\n"); | ||
| 90 | |||
| 91 | dev_add_offload(&mpls_uc_offload); | ||
| 92 | dev_add_offload(&mpls_mc_offload); | ||
| 93 | |||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | static void __exit mpls_gso_exit(void) | ||
| 98 | { | ||
| 99 | dev_remove_offload(&mpls_uc_offload); | ||
| 100 | dev_remove_offload(&mpls_mc_offload); | ||
| 101 | } | ||
| 102 | |||
| 103 | module_init(mpls_gso_init); | ||
| 104 | module_exit(mpls_gso_exit); | ||
| 105 | |||
| 106 | MODULE_DESCRIPTION("MPLS GSO support"); | ||
| 107 | MODULE_AUTHOR("Simon Horman (horms@verge.net.au)"); | ||
| 108 | MODULE_LICENSE("GPL"); | ||
