datapath: Add support for kernel 4.4
[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 #include "datapath.h"
6
7 typedef void (*gso_fix_segment_t)(struct sk_buff *);
8
9 struct ovs_gso_cb {
10         struct ovs_skb_cb dp_cb;
11 #ifndef USE_UPSTREAM_TUNNEL
12         struct metadata_dst     *tun_dst;
13 #endif
14 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
15         gso_fix_segment_t fix_segment;
16 #endif
17 #ifndef HAVE_INNER_PROTOCOL
18         __be16          inner_protocol;
19 #endif
20 #ifndef HAVE_NDO_FILL_METADATA_DST
21         /* Keep original tunnel info during userspace action execution. */
22         struct metadata_dst *fill_md_dst;
23 #endif
24         bool ipv6;
25 };
26 #define OVS_GSO_CB(skb) ((struct ovs_gso_cb *)(skb)->cb)
27
28
29 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
30 #include <linux/netdevice.h>
31 #include <linux/skbuff.h>
32 #include <net/protocol.h>
33
34 static inline void skb_clear_ovs_gso_cb(struct sk_buff *skb)
35 {
36         OVS_GSO_CB(skb)->fix_segment = NULL;
37 }
38 #else
39 static inline void skb_clear_ovs_gso_cb(struct sk_buff *skb)
40 {
41
42 }
43 #endif
44
45 #ifndef HAVE_INNER_PROTOCOL
46 static inline void ovs_skb_init_inner_protocol(struct sk_buff *skb)
47 {
48         OVS_GSO_CB(skb)->inner_protocol = htons(0);
49 }
50
51 static inline void ovs_skb_set_inner_protocol(struct sk_buff *skb,
52                                               __be16 ethertype)
53 {
54         OVS_GSO_CB(skb)->inner_protocol = ethertype;
55 }
56
57 static inline __be16 ovs_skb_get_inner_protocol(struct sk_buff *skb)
58 {
59         return OVS_GSO_CB(skb)->inner_protocol;
60 }
61
62 #else
63
64 static inline void ovs_skb_init_inner_protocol(struct sk_buff *skb)
65 {
66         /* Nothing to do. The inner_protocol is either zero or
67          * has been set to a value by another user.
68          * Either way it may be considered initialised.
69          */
70 }
71
72 static inline __be16 ovs_skb_get_inner_protocol(struct sk_buff *skb)
73 {
74         return skb->inner_protocol;
75 }
76
77 #ifdef ENCAP_TYPE_ETHER
78 #define ovs_skb_set_inner_protocol skb_set_inner_protocol
79 #else
80 static inline void ovs_skb_set_inner_protocol(struct sk_buff *skb,
81                                               __be16 ethertype)
82 {
83         skb->inner_protocol = ethertype;
84 }
85 #endif /* ENCAP_TYPE_ETHER */
86 #endif /* HAVE_INNER_PROTOCOL */
87
88 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
89 static inline int skb_inner_mac_offset(const struct sk_buff *skb)
90 {
91         return skb_inner_mac_header(skb) - skb->data;
92 }
93
94 #define ip_local_out rpl_ip_local_out
95 int rpl_ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
96
97 #define ip6_local_out rpl_ip6_local_out
98 int rpl_ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
99 #else
100
101 static inline int rpl_ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
102 {
103         memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
104 #ifdef HAVE_IP_LOCAL_OUT_TAKES_NET
105         /* net and sk parameters are added at same time. */
106         return ip_local_out(net, sk, skb);
107 #else
108         return ip_local_out(skb);
109 #endif
110 }
111 #define ip_local_out rpl_ip_local_out
112
113 static inline int rpl_ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
114 {
115         memset(IP6CB(skb), 0, sizeof (*IP6CB(skb)));
116 #ifdef HAVE_IP_LOCAL_OUT_TAKES_NET
117         return ip6_local_out(net, sk, skb);
118 #else
119         return ip6_local_out(skb);
120 #endif
121 }
122 #define ip6_local_out rpl_ip6_local_out
123
124 #endif /* 3.18 */
125
126 #ifndef USE_UPSTREAM_TUNNEL
127 /* We need two separate functions to manage different dst in this case.
128  * First is dst_entry and second is tunnel-dst.
129  * So define ovs_* separate functions for tun_dst.
130  */
131 static inline void ovs_skb_dst_set(struct sk_buff *skb, void *dst)
132 {
133         OVS_GSO_CB(skb)->tun_dst = (void *)dst;
134 }
135
136 static inline struct ip_tunnel_info *ovs_skb_tunnel_info(struct sk_buff *skb)
137 {
138         if (likely(OVS_GSO_CB(skb)->tun_dst))
139                 return &OVS_GSO_CB(skb)->tun_dst->u.tun_info;
140         else
141                 return NULL;
142 }
143
144 static inline void ovs_skb_dst_drop(struct sk_buff *skb)
145 {
146         OVS_GSO_CB(skb)->tun_dst = NULL;
147 }
148
149 static inline void ovs_dst_hold(void *dst)
150 {
151 }
152
153 static inline void ovs_dst_release(struct dst_entry *dst)
154 {
155         struct metadata_dst *tun_dst = (struct metadata_dst *) dst;
156
157         dst_cache_destroy(&tun_dst->u.tun_info.dst_cache);
158         kfree(dst);
159 }
160
161 #else
162 #define ovs_skb_dst_set skb_dst_set
163 #define ovs_skb_dst_drop skb_dst_drop
164 #define ovs_dst_hold dst_hold
165 #define ovs_dst_release dst_release
166 #endif
167
168 #ifndef HAVE_NDO_FILL_METADATA_DST
169 #define SKB_INIT_FILL_METADATA_DST(skb) OVS_GSO_CB(skb)->fill_md_dst = NULL;
170
171 #define SKB_RESTORE_FILL_METADATA_DST(skb)      do {                    \
172         if (OVS_GSO_CB(skb)->fill_md_dst) {                                     \
173                 kfree(OVS_GSO_CB(skb)->tun_dst);                        \
174                 OVS_GSO_CB(skb)->tun_dst = OVS_GSO_CB(skb)->fill_md_dst;        \
175         }                                                               \
176 } while (0)
177
178
179 #define SKB_SETUP_FILL_METADATA_DST(skb) ({                     \
180         struct metadata_dst *new_md_dst;                        \
181         struct metadata_dst *md_dst;                            \
182         int md_size;                                            \
183         int ret = 1;                                            \
184                                                                 \
185         SKB_RESTORE_FILL_METADATA_DST(skb);                     \
186         new_md_dst = kmalloc(sizeof(struct metadata_dst) + 256, GFP_ATOMIC); \
187         if (new_md_dst) {                                               \
188                 md_dst = OVS_GSO_CB(skb)->tun_dst;                      \
189                 md_size = new_md_dst->u.tun_info.options_len;           \
190                 memcpy(&new_md_dst->u.tun_info, &md_dst->u.tun_info,    \
191                         sizeof(struct ip_tunnel_info) + md_size);       \
192                                                                         \
193                 OVS_GSO_CB(skb)->fill_md_dst = md_dst;                          \
194                 OVS_GSO_CB(skb)->tun_dst = new_md_dst;                  \
195                 ret = 1;                                                \
196         } else {                                                        \
197                 ret = 0;                                                \
198         }                                                               \
199         ret;                                                            \
200 })
201
202 #else
203 #define SKB_INIT_FILL_METADATA_DST(skb)         do {} while(0)
204 #define SKB_SETUP_FILL_METADATA_DST(skb)        (true)
205 #define SKB_RESTORE_FILL_METADATA_DST(skb)      do {} while(0)
206 #endif
207
208 #endif