Prepare Open vSwitch 1.1.2 release.
[sliver-openvswitch.git] / datapath / vlan.h
1 /*
2  * Copyright (c) 2011 Nicira Networks.
3  * Distributed under the terms of the GNU GPL version 2.
4  *
5  * Significant portions of this file may be copied from parts of the Linux
6  * kernel, by Linus Torvalds and others.
7  */
8
9 #ifndef VLAN_H
10 #define VLAN_H 1
11
12 #include <linux/if_vlan.h>
13 #include <linux/skbuff.h>
14 #include <linux/version.h>
15
16 /**
17  * DOC: VLAN tag manipulation.
18  *
19  * &struct sk_buff handling of VLAN tags has evolved over time:
20  *
21  * In 2.6.26 and earlier, VLAN tags did not have any generic representation in
22  * an skb, other than as a raw 802.1Q header inside the packet data.
23  *
24  * In 2.6.27 &struct sk_buff added a @vlan_tci member.  Between 2.6.27 and
25  * 2.6.32, its value was the raw contents of the 802.1Q TCI field, or zero if
26  * no 802.1Q header was present.  This worked OK except for the corner case of
27  * an 802.1Q header with an all-0-bits TCI, which could not be represented.
28  *
29  * In 2.6.33, @vlan_tci semantics changed.  Now, if an 802.1Q header is
30  * present, then the VLAN_TAG_PRESENT bit is always set.  This fixes the
31  * all-0-bits TCI corner case.
32  *
33  * For compatibility we emulate the 2.6.33+ behavior on earlier kernel
34  * versions.  The client must not access @vlan_tci directly.  Instead, use
35  * vlan_get_tci() to read it or vlan_set_tci() to write it, with semantics
36  * equivalent to those on 2.6.33+.
37  */
38
39 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
40 #define NEED_VLAN_FIELD
41 #endif
42
43 #ifndef NEED_VLAN_FIELD
44 static inline void vlan_copy_skb_tci(struct sk_buff *skb) { }
45
46 static inline u16 vlan_get_tci(struct sk_buff *skb)
47 {
48 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
49         if (skb->vlan_tci)
50                 return skb->vlan_tci | VLAN_TAG_PRESENT;
51 #endif
52         return skb->vlan_tci;
53 }
54
55 static inline void vlan_set_tci(struct sk_buff *skb, u16 vlan_tci)
56 {
57 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
58         vlan_tci &= ~VLAN_TAG_PRESENT;
59 #endif
60         skb->vlan_tci = vlan_tci;
61 }
62 #else
63 void vlan_copy_skb_tci(struct sk_buff *skb);
64 u16 vlan_get_tci(struct sk_buff *skb);
65 void vlan_set_tci(struct sk_buff *skb, u16 vlan_tci);
66
67 #undef vlan_tx_tag_present
68 bool vlan_tx_tag_present(struct sk_buff *skb);
69
70 #undef vlan_tx_tag_get
71 u16 vlan_tx_tag_get(struct sk_buff *skb);
72
73 #define __vlan_hwaccel_put_tag rpl__vlan_hwaccel_put_tag
74 struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, u16 vlan_tci);
75 #endif /* NEED_VLAN_FIELD */
76
77 static inline int vlan_deaccel_tag(struct sk_buff *skb)
78 {
79         if (!vlan_tx_tag_present(skb))
80                 return 0;
81
82         skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
83         if (unlikely(!skb))
84                 return -ENOMEM;
85
86         vlan_set_tci(skb, 0);
87         return 0;
88 }
89
90 #endif /* vlan.h */