8f5b07628682e312d3849408ff4747124b325968
[cascardo/ovs.git] / datapath / linux / compat / gso.h
1 #ifndef __LINUX_GSO_WRAPPER_H
2 #define __LINUX_GSO_WRAPPER_H
3
4 #include <linux/version.h>
5 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
6
7 #include <linux/netdevice.h>
8 #include <linux/skbuff.h>
9 #include <net/protocol.h>
10
11 #include "datapath.h"
12 typedef void (*gso_fix_segment_t)(struct sk_buff *);
13
14 struct ovs_gso_cb {
15         struct ovs_skb_cb dp_cb;
16         gso_fix_segment_t fix_segment;
17 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
18         __be16          inner_protocol;
19 #endif
20 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
21         unsigned int    inner_mac_header;
22 #endif
23 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
24         unsigned int    inner_network_header;
25 #endif
26 };
27 #define OVS_GSO_CB(skb) ((struct ovs_gso_cb *)(skb)->cb)
28
29 #endif
30
31 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
32 static inline unsigned char *skb_inner_mac_header(const struct sk_buff *skb)
33 {
34         return skb->head + OVS_GSO_CB(skb)->inner_mac_header;
35 }
36
37 static inline void skb_set_inner_mac_header(const struct sk_buff *skb,
38                                             int offset)
39 {
40         OVS_GSO_CB(skb)->inner_mac_header = (skb->data - skb->head) + offset;
41 }
42 #endif
43
44 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
45 static inline unsigned char *skb_inner_network_header(const struct sk_buff *skb)
46 {
47         return skb->head + OVS_GSO_CB(skb)->inner_network_header;
48 }
49
50 static inline int skb_inner_network_offset(const struct sk_buff *skb)
51 {
52         return skb_inner_network_header(skb) - skb->data;
53 }
54
55 /* We don't actually store the transport offset on backports because
56  * we don't use it anywhere. Slightly rename this version to avoid
57  * future users from picking it up accidentially.
58  */
59 static inline int ovs_skb_inner_transport_offset(const struct sk_buff *skb)
60 {
61         return 0;
62 }
63
64 static inline void skb_set_inner_network_header(const struct sk_buff *skb,
65                                                 int offset)
66 {
67         OVS_GSO_CB(skb)->inner_network_header = (skb->data - skb->head)
68                                                 + offset;
69 }
70
71 static inline void skb_set_inner_transport_header(const struct sk_buff *skb,
72                                                   int offset)
73 { }
74
75 #else
76
77 static inline int ovs_skb_inner_transport_offset(const struct sk_buff *skb)
78 {
79         return skb_inner_transport_header(skb) - skb->data;
80 }
81
82 #endif
83
84 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
85 static inline void ovs_skb_init_inner_protocol(struct sk_buff *skb) {
86         OVS_GSO_CB(skb)->inner_protocol = htons(0);
87 }
88
89 static inline void ovs_skb_set_inner_protocol(struct sk_buff *skb,
90                                               __be16 ethertype) {
91         OVS_GSO_CB(skb)->inner_protocol = ethertype;
92 }
93
94 static inline __be16 ovs_skb_get_inner_protocol(struct sk_buff *skb)
95 {
96         return OVS_GSO_CB(skb)->inner_protocol;
97 }
98
99 #else
100
101 static inline void ovs_skb_init_inner_protocol(struct sk_buff *skb) {
102         /* Nothing to do. The inner_protocol is either zero or
103          * has been set to a value by another user.
104          * Either way it may be considered initialised.
105          */
106 }
107
108 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
109 static inline void ovs_skb_set_inner_protocol(struct sk_buff *skb,
110                                               __be16 ethertype)
111 {
112         skb->inner_protocol = ethertype;
113 }
114 #else
115 static inline void ovs_skb_set_inner_protocol(struct sk_buff *skb,
116                                               __be16 ethertype)
117 {
118         skb_set_inner_protocol(skb, ethertype);
119 }
120 #endif
121
122 static inline __be16 ovs_skb_get_inner_protocol(struct sk_buff *skb)
123 {
124         return skb->inner_protocol;
125 }
126 #endif /* 3.11 */
127
128 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
129 #define ip_local_out rpl_ip_local_out
130 int rpl_ip_local_out(struct sk_buff *skb);
131
132 static inline int skb_inner_mac_offset(const struct sk_buff *skb)
133 {
134         return skb_inner_mac_header(skb) - skb->data;
135 }
136
137 #define skb_reset_inner_headers rpl_skb_reset_inner_headers
138 static inline void skb_reset_inner_headers(struct sk_buff *skb)
139 {
140         BUILD_BUG_ON(sizeof(struct ovs_gso_cb) > FIELD_SIZEOF(struct sk_buff, cb));
141         skb_set_inner_mac_header(skb, skb_mac_header(skb) - skb->data);
142         skb_set_inner_network_header(skb, skb_network_offset(skb));
143         skb_set_inner_transport_header(skb, skb_transport_offset(skb));
144 }
145 #endif /* 3.18 */
146
147 #endif