]> git.proxmox.com Git - ovs.git/blob - datapath/linux/compat/include/net/erspan.h
9fdae97b5fc4d681f0f01f1b64852d825a210598
[ovs.git] / datapath / linux / compat / include / net / erspan.h
1 #ifndef USE_UPSTREAM_TUNNEL
2 #ifndef __LINUX_ERSPAN_H
3 #define __LINUX_ERSPAN_H
4
5 /*
6 * GRE header for ERSPAN encapsulation (8 octets [34:41]) -- 8 bytes
7 * 0 1 2 3
8 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
9 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
10 * |0|0|0|1|0|00000|000000000|00000| Protocol Type for ERSPAN |
11 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12 * | Sequence Number (increments per packet per session) |
13 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14 *
15 * Note that in the above GRE header [RFC1701] out of the C, R, K, S,
16 * s, Recur, Flags, Version fields only S (bit 03) is set to 1. The
17 * other fields are set to zero, so only a sequence number follows.
18 *
19 * ERSPAN Version 1 (Type II) header (8 octets [42:49])
20 * 0 1 2 3
21 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
22 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23 * | Ver | VLAN | COS | En|T| Session ID |
24 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25 * | Reserved | Index |
26 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27 *
28 *
29 * ERSPAN Version 2 (Type III) header (12 octets [42:49])
30 * 0 1 2 3
31 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
32 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33 * | Ver | VLAN | COS |BSO|T| Session ID |
34 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 * | Timestamp |
36 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 * | SGT |P| FT | Hw ID |D|Gra|O|
38 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 *
40 * Platform Specific SubHeader (8 octets, optional)
41 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 * | Platf ID | Platform Specific Info |
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 * | Platform Specific Info |
45 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 *
47 * GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB
48 */
49
50 /* #include <uapi/linux/erspan.h> */
51 /* Just insert uapi/linux/erspan.h here since
52 * we don't pull in uapi to compat
53 */
54 /* ERSPAN version 2 metadata header */
55 struct erspan_md2 {
56 __be32 timestamp;
57 __be16 sgt; /* security group tag */
58 #if defined(__LITTLE_ENDIAN_BITFIELD)
59 __u8 hwid_upper:2,
60 ft:5,
61 p:1;
62 __u8 o:1,
63 gra:2,
64 dir:1,
65 hwid:4;
66 #elif defined(__BIG_ENDIAN_BITFIELD)
67 __u8 p:1,
68 ft:5,
69 hwid_upper:2;
70 __u8 hwid:4,
71 dir:1,
72 gra:2,
73 o:1;
74 #else
75 #error "Please fix <asm/byteorder.h>"
76 #endif
77 };
78
79 struct erspan_metadata {
80 int version;
81 union {
82 __be32 index; /* Version 1 (type II)*/
83 struct erspan_md2 md2; /* Version 2 (type III) */
84 } u;
85 };
86
87 #define ERSPAN_VERSION 0x1 /* ERSPAN type II */
88 #define VER_MASK 0xf000
89 #define VLAN_MASK 0x0fff
90 #define COS_MASK 0xe000
91 #define EN_MASK 0x1800
92 #define T_MASK 0x0400
93 #define ID_MASK 0x03ff
94 #define INDEX_MASK 0xfffff
95
96 #define ERSPAN_VERSION2 0x2 /* ERSPAN type III*/
97 #define BSO_MASK EN_MASK
98 #define SGT_MASK 0xffff0000
99 #define P_MASK 0x8000
100 #define FT_MASK 0x7c00
101 #define HWID_MASK 0x03f0
102 #define DIR_MASK 0x0008
103 #define GRA_MASK 0x0006
104 #define O_MASK 0x0001
105
106 #define HWID_OFFSET 4
107 #define DIR_OFFSET 3
108
109 enum erspan_encap_type {
110 ERSPAN_ENCAP_NOVLAN = 0x0, /* originally without VLAN tag */
111 ERSPAN_ENCAP_ISL = 0x1, /* originally ISL encapsulated */
112 ERSPAN_ENCAP_8021Q = 0x2, /* originally 802.1Q encapsulated */
113 ERSPAN_ENCAP_INFRAME = 0x3, /* VLAN tag perserved in frame */
114 };
115
116 #define ERSPAN_V1_MDSIZE 4
117 #define ERSPAN_V2_MDSIZE 8
118
119 struct erspan_base_hdr {
120 #if defined(__LITTLE_ENDIAN_BITFIELD)
121 __u8 vlan_upper:4,
122 ver:4;
123 __u8 vlan:8;
124 __u8 session_id_upper:2,
125 t:1,
126 en:2,
127 cos:3;
128 __u8 session_id:8;
129 #elif defined(__BIG_ENDIAN_BITFIELD)
130 __u8 ver: 4,
131 vlan_upper:4;
132 __u8 vlan:8;
133 __u8 cos:3,
134 en:2,
135 t:1,
136 session_id_upper:2;
137 __u8 session_id:8;
138 #else
139 #error "Please fix <asm/byteorder.h>"
140 #endif
141 };
142
143 static inline void set_session_id(struct erspan_base_hdr *ershdr, u16 id)
144 {
145 ershdr->session_id = id & 0xff;
146 ershdr->session_id_upper = (id >> 8) & 0x3;
147 }
148
149 static inline u16 get_session_id(const struct erspan_base_hdr *ershdr)
150 {
151 return (ershdr->session_id_upper << 8) + ershdr->session_id;
152 }
153
154 static inline void set_vlan(struct erspan_base_hdr *ershdr, u16 vlan)
155 {
156 ershdr->vlan = vlan & 0xff;
157 ershdr->vlan_upper = (vlan >> 8) & 0xf;
158 }
159
160 static inline u16 get_vlan(const struct erspan_base_hdr *ershdr)
161 {
162 return (ershdr->vlan_upper << 8) + ershdr->vlan;
163 }
164
165 static inline void set_hwid(struct erspan_md2 *md2, u8 hwid)
166 {
167 md2->hwid = hwid & 0xf;
168 md2->hwid_upper = (hwid >> 4) & 0x3;
169 }
170
171 static inline u8 get_hwid(const struct erspan_md2 *md2)
172 {
173 return (md2->hwid_upper << 4) + md2->hwid;
174 }
175
176 static inline int erspan_hdr_len(int version)
177 {
178 return sizeof(struct erspan_base_hdr) +
179 (version == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE);
180 }
181
182 static inline u8 tos_to_cos(u8 tos)
183 {
184 u8 dscp, cos;
185
186 dscp = tos >> 2;
187 cos = dscp >> 3;
188 return cos;
189 }
190
191 static inline void erspan_build_header(struct sk_buff *skb,
192 u32 id, u32 index,
193 bool truncate, bool is_ipv4)
194 {
195 struct ethhdr *eth = (struct ethhdr *)skb->data;
196 enum erspan_encap_type enc_type;
197 struct erspan_base_hdr *ershdr;
198 struct qtag_prefix {
199 __be16 eth_type;
200 __be16 tci;
201 } *qp;
202 u16 vlan_tci = 0;
203 u8 tos;
204 __be32 *idx;
205
206 tos = is_ipv4 ? ip_hdr(skb)->tos :
207 (ipv6_hdr(skb)->priority << 4) +
208 (ipv6_hdr(skb)->flow_lbl[0] >> 4);
209
210 enc_type = ERSPAN_ENCAP_NOVLAN;
211
212 /* If mirrored packet has vlan tag, extract tci and
213 * perserve vlan header in the mirrored frame.
214 */
215 if (eth->h_proto == htons(ETH_P_8021Q)) {
216 qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN);
217 vlan_tci = ntohs(qp->tci);
218 enc_type = ERSPAN_ENCAP_INFRAME;
219 }
220
221 skb_push(skb, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
222 ershdr = (struct erspan_base_hdr *)skb->data;
223 memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
224
225 /* Build base header */
226 ershdr->ver = ERSPAN_VERSION;
227 ershdr->cos = tos_to_cos(tos);
228 ershdr->en = enc_type;
229 ershdr->t = truncate;
230 set_vlan(ershdr, vlan_tci);
231 set_session_id(ershdr, id);
232
233 /* Build metadata */
234 idx = (__be32 *)(ershdr + 1);
235 *idx = htonl(index & INDEX_MASK);
236 }
237
238 /* ERSPAN GRA: timestamp granularity
239 * 00b --> granularity = 100 microseconds
240 * 01b --> granularity = 100 nanoseconds
241 * 10b --> granularity = IEEE 1588
242 * Here we only support 100 microseconds.
243 */
244 static inline __be32 erspan_get_timestamp(void)
245 {
246 u64 h_usecs;
247 ktime_t kt;
248
249 kt = ktime_get_real();
250 h_usecs = ktime_divns(kt, 100 * NSEC_PER_USEC);
251
252 /* ERSPAN base header only has 32-bit,
253 * so it wraps around 4 days.
254 */
255 return htonl((u32)h_usecs);
256 }
257
258 static inline void erspan_build_header_v2(struct sk_buff *skb,
259 u32 id, u8 direction, u16 hwid,
260 bool truncate, bool is_ipv4)
261 {
262 struct ethhdr *eth = (struct ethhdr *)skb->data;
263 struct erspan_base_hdr *ershdr;
264 struct erspan_md2 *md2;
265 struct qtag_prefix {
266 __be16 eth_type;
267 __be16 tci;
268 } *qp;
269 u16 vlan_tci = 0;
270 u8 gra = 0; /* 100 usec */
271 u8 bso = truncate; /* Bad/Short/Oversized */
272 u8 sgt = 0;
273 u8 tos;
274
275 tos = is_ipv4 ? ip_hdr(skb)->tos :
276 (ipv6_hdr(skb)->priority << 4) +
277 (ipv6_hdr(skb)->flow_lbl[0] >> 4);
278
279 /* Unlike v1, v2 does not have En field,
280 * so only extract vlan tci field.
281 */
282 if (eth->h_proto == htons(ETH_P_8021Q)) {
283 qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN);
284 vlan_tci = ntohs(qp->tci);
285 }
286
287 skb_push(skb, sizeof(*ershdr) + ERSPAN_V2_MDSIZE);
288 ershdr = (struct erspan_base_hdr *)skb->data;
289 memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V2_MDSIZE);
290
291 /* Build base header */
292 ershdr->ver = ERSPAN_VERSION2;
293 ershdr->cos = tos_to_cos(tos);
294 ershdr->en = bso;
295 ershdr->t = truncate;
296 set_vlan(ershdr, vlan_tci);
297 set_session_id(ershdr, id);
298
299 /* Build metadata */
300 md2 = (struct erspan_md2 *)(ershdr + 1);
301 md2->timestamp = erspan_get_timestamp();
302 md2->sgt = htons(sgt);
303 md2->p = 1;
304 md2->ft = 0;
305 md2->dir = direction;
306 md2->gra = gra;
307 md2->o = 0;
308 set_hwid(md2, hwid);
309 }
310
311 #endif
312 #else
313 #include_next <net/erspan.h>
314 #endif