2 * Copyright (c) 2010 Nicira Networks.
3 * Distributed under the terms of the GNU GPL version 2.
5 * Significant portions of this file may be copied from parts of the Linux
6 * kernel, by Linus Torvalds and others.
10 #include <linux/skbuff.h>
12 #include <linux/if_tunnel.h>
13 #include <linux/if_vlan.h>
18 #include <net/protocol.h>
22 #include "vport-generic.h"
25 * The GRE header is composed of a series of sections: a base and then a variable
28 #define GRE_HEADER_SECTION 4
35 static int gre_hdr_len(const struct tnl_port_config
*port_config
)
39 len
= GRE_HEADER_SECTION
;
41 if (port_config
->flags
& TNL_F_CSUM
)
42 len
+= GRE_HEADER_SECTION
;
44 if (port_config
->out_key
||
45 port_config
->flags
& TNL_F_OUT_KEY_ACTION
)
46 len
+= GRE_HEADER_SECTION
;
51 static struct sk_buff
*gre_build_header(struct sk_buff
*skb
,
52 const struct vport
*vport
,
53 const struct tnl_mutable_config
*mutable,
54 struct dst_entry
*dst
)
56 struct gre_base_hdr
*greh
= (struct gre_base_hdr
*)skb_transport_header(skb
);
57 __be32
*options
= (__be32
*)(skb_network_header(skb
) + mutable->tunnel_hlen
58 - GRE_HEADER_SECTION
);
60 greh
->protocol
= htons(ETH_P_TEB
);
63 /* Work backwards over the options so the checksum is last. */
64 if (mutable->port_config
.out_key
||
65 mutable->port_config
.flags
& TNL_F_OUT_KEY_ACTION
) {
66 greh
->flags
|= GRE_KEY
;
68 if (mutable->port_config
.flags
& TNL_F_OUT_KEY_ACTION
)
69 *options
= OVS_CB(skb
)->tun_id
;
71 *options
= mutable->port_config
.out_key
;
76 if (mutable->port_config
.flags
& TNL_F_CSUM
) {
77 greh
->flags
|= GRE_CSUM
;
80 *(__sum16
*)options
= csum_fold(skb_checksum(skb
,
82 skb
->len
- sizeof(struct iphdr
),
87 * Allow our local IP stack to fragment the outer packet even if the
88 * DF bit is set as a last resort.
95 static int parse_header(struct iphdr
*iph
, __be16
*flags
, __be32
*key
)
97 /* IP and ICMP protocol handlers check that the IHL is valid. */
98 struct gre_base_hdr
*greh
= (struct gre_base_hdr
*)((u8
*)iph
+ (iph
->ihl
<< 2));
99 __be32
*options
= (__be32
*)(greh
+ 1);
102 *flags
= greh
->flags
;
104 if (unlikely(greh
->flags
& (GRE_VERSION
| GRE_ROUTING
)))
107 if (unlikely(greh
->protocol
!= htons(ETH_P_TEB
)))
110 hdr_len
= GRE_HEADER_SECTION
;
112 if (greh
->flags
& GRE_CSUM
) {
113 hdr_len
+= GRE_HEADER_SECTION
;
117 if (greh
->flags
& GRE_KEY
) {
118 hdr_len
+= GRE_HEADER_SECTION
;
125 if (unlikely(greh
->flags
& GRE_SEQ
))
126 hdr_len
+= GRE_HEADER_SECTION
;
131 /* Called with rcu_read_lock and BH disabled. */
132 static void gre_err(struct sk_buff
*skb
, u32 info
)
135 const struct tnl_mutable_config
*mutable;
136 const int type
= icmp_hdr(skb
)->type
;
137 const int code
= icmp_hdr(skb
)->code
;
138 int mtu
= ntohs(icmp_hdr(skb
)->un
.frag
.mtu
);
143 int tunnel_hdr_len
, tot_hdr_len
;
144 unsigned int orig_mac_header
;
145 unsigned int orig_nw_header
;
147 if (type
!= ICMP_DEST_UNREACH
|| code
!= ICMP_FRAG_NEEDED
)
151 * The mimimum size packet that we would actually be able to process:
152 * encapsulating IP header, minimum GRE header, Ethernet header,
155 if (!pskb_may_pull(skb
, sizeof(struct iphdr
) + GRE_HEADER_SECTION
+
156 ETH_HLEN
+ sizeof(struct iphdr
)))
159 iph
= (struct iphdr
*)skb
->data
;
161 tunnel_hdr_len
= parse_header(iph
, &flags
, &key
);
162 if (tunnel_hdr_len
< 0)
165 vport
= tnl_find_port(iph
->saddr
, iph
->daddr
, key
,
166 TNL_T_PROTO_GRE
| TNL_T_KEY_EITHER
, &mutable);
171 * Packets received by this function were previously sent by us, so
172 * any comparisons should be to the output values, not the input.
173 * However, it's not really worth it to have a hash table based on
174 * output keys (especially since ICMP error handling of tunneled packets
175 * isn't that reliable anyways). Therefore, we do a lookup based on the
176 * out key as if it were the in key and then check to see if the input
177 * and output keys are the same.
179 if (mutable->port_config
.in_key
!= mutable->port_config
.out_key
)
182 if (!!(mutable->port_config
.flags
& TNL_F_IN_KEY_MATCH
) !=
183 !!(mutable->port_config
.flags
& TNL_F_OUT_KEY_ACTION
))
186 if ((mutable->port_config
.flags
& TNL_F_CSUM
) && !(flags
& GRE_CSUM
))
189 tunnel_hdr_len
+= iph
->ihl
<< 2;
191 orig_mac_header
= skb_mac_header(skb
) - skb
->data
;
192 orig_nw_header
= skb_network_header(skb
) - skb
->data
;
193 skb_set_mac_header(skb
, tunnel_hdr_len
);
195 tot_hdr_len
= tunnel_hdr_len
+ ETH_HLEN
;
197 skb
->protocol
= eth_hdr(skb
)->h_proto
;
198 if (skb
->protocol
== htons(ETH_P_8021Q
)) {
199 tot_hdr_len
+= VLAN_HLEN
;
200 skb
->protocol
= vlan_eth_hdr(skb
)->h_vlan_encapsulated_proto
;
203 skb_set_network_header(skb
, tot_hdr_len
);
206 if (skb
->protocol
== htons(ETH_P_IP
))
207 tot_hdr_len
+= sizeof(struct iphdr
);
208 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
209 else if (skb
->protocol
== htons(ETH_P_IPV6
))
210 tot_hdr_len
+= sizeof(struct ipv6hdr
);
215 if (!pskb_may_pull(skb
, tot_hdr_len
))
218 if (skb
->protocol
== htons(ETH_P_IP
)) {
219 if (mtu
< IP_MIN_MTU
) {
220 if (ntohs(ip_hdr(skb
)->tot_len
) >= IP_MIN_MTU
)
227 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
228 else if (skb
->protocol
== htons(ETH_P_IPV6
)) {
229 if (mtu
< IPV6_MIN_MTU
) {
230 unsigned int packet_length
= sizeof(struct ipv6hdr
) +
231 ntohs(ipv6_hdr(skb
)->payload_len
);
233 if (packet_length
>= IPV6_MIN_MTU
234 || ntohs(ipv6_hdr(skb
)->payload_len
) == 0)
242 __skb_pull(skb
, tunnel_hdr_len
);
243 tnl_frag_needed(vport
, mutable, skb
, mtu
, key
);
244 __skb_push(skb
, tunnel_hdr_len
);
247 skb_set_mac_header(skb
, orig_mac_header
);
248 skb_set_network_header(skb
, orig_nw_header
);
249 skb
->protocol
= htons(ETH_P_IP
);
252 static bool check_checksum(struct sk_buff
*skb
)
254 struct iphdr
*iph
= ip_hdr(skb
);
255 struct gre_base_hdr
*greh
= (struct gre_base_hdr
*)(iph
+ 1);
258 if (greh
->flags
& GRE_CSUM
) {
259 switch (skb
->ip_summed
) {
260 case CHECKSUM_COMPLETE
:
261 csum
= csum_fold(skb
->csum
);
269 csum
= __skb_checksum_complete(skb
);
270 skb
->ip_summed
= CHECKSUM_COMPLETE
;
278 /* Called with rcu_read_lock and BH disabled. */
279 static int gre_rcv(struct sk_buff
*skb
)
282 const struct tnl_mutable_config
*mutable;
288 if (unlikely(!pskb_may_pull(skb
, sizeof(struct gre_base_hdr
) + ETH_HLEN
)))
291 if (unlikely(!check_checksum(skb
)))
294 hdr_len
= parse_header(ip_hdr(skb
), &flags
, &key
);
295 if (unlikely(hdr_len
< 0))
298 if (unlikely(!pskb_may_pull(skb
, hdr_len
+ ETH_HLEN
)))
302 vport
= tnl_find_port(iph
->daddr
, iph
->saddr
, key
,
303 TNL_T_PROTO_GRE
| TNL_T_KEY_EITHER
, &mutable);
304 if (unlikely(!vport
)) {
305 icmp_send(skb
, ICMP_DEST_UNREACH
, ICMP_PORT_UNREACH
, 0);
309 if (mutable->port_config
.flags
& TNL_F_IN_KEY_MATCH
)
310 OVS_CB(skb
)->tun_id
= key
;
312 OVS_CB(skb
)->tun_id
= 0;
314 __skb_pull(skb
, hdr_len
);
315 skb_postpull_rcsum(skb
, skb_transport_header(skb
), hdr_len
+ ETH_HLEN
);
325 struct tnl_ops gre_tnl_ops
= {
326 .tunnel_type
= TNL_T_PROTO_GRE
,
327 .ipproto
= IPPROTO_GRE
,
328 .hdr_len
= gre_hdr_len
,
329 .build_header
= gre_build_header
,
332 static struct vport
*gre_create(const char *name
, const void __user
*config
)
334 return tnl_create(name
, config
, &gre_vport_ops
, &gre_tnl_ops
);
337 static struct net_protocol gre_protocol_handlers
= {
339 .err_handler
= gre_err
,
342 static int gre_init(void)
346 err
= inet_add_protocol(&gre_protocol_handlers
, IPPROTO_GRE
);
348 printk(KERN_WARNING
"openvswitch: cannot register gre protocol handler\n");
358 static void gre_exit(void)
361 inet_del_protocol(&gre_protocol_handlers
, IPPROTO_GRE
);
364 struct vport_ops gre_vport_ops
= {
366 .flags
= VPORT_F_GEN_STATS
| VPORT_F_TUN_ID
,
369 .create
= gre_create
,
370 .modify
= tnl_modify
,
371 .destroy
= tnl_destroy
,
372 .set_mtu
= tnl_set_mtu
,
373 .set_addr
= tnl_set_addr
,
374 .get_name
= tnl_get_name
,
375 .get_addr
= tnl_get_addr
,
376 .get_dev_flags
= vport_gen_get_dev_flags
,
377 .is_running
= vport_gen_is_running
,
378 .get_operstate
= vport_gen_get_operstate
,
379 .get_mtu
= tnl_get_mtu
,