1 #ifndef USE_UPSTREAM_TUNNEL
2 #ifndef __LINUX_ERSPAN_H
3 #define __LINUX_ERSPAN_H
6 * GRE header for ERSPAN encapsulation (8 octets [34:41]) -- 8 bytes
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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.
19 * ERSPAN Version 1 (Type II) header (8 octets [42:49])
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29 * ERSPAN Version 2 (Type III) header (12 octets [42:49])
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 * | SGT |P| FT | Hw ID |D|Gra|O|
38 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 * Platform Specific SubHeader (8 octets, optional)
41 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 * | Platf ID | Platform Specific Info |
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 * | Platform Specific Info |
45 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 * GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB
50 /* #include <uapi/linux/erspan.h> */
51 /* Just insert uapi/linux/erspan.h here since
52 * we don't pull in uapi to compat
54 /* ERSPAN version 2 metadata header */
57 __be16 sgt
; /* security group tag */
58 #if defined(__LITTLE_ENDIAN_BITFIELD)
66 #elif defined(__BIG_ENDIAN_BITFIELD)
75 #error "Please fix <asm/byteorder.h>"
79 struct erspan_metadata
{
82 __be32 index
; /* Version 1 (type II)*/
83 struct erspan_md2 md2
; /* Version 2 (type III) */
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
93 #define ID_MASK 0x03ff
94 #define INDEX_MASK 0xfffff
96 #define ERSPAN_VERSION2 0x2 /* ERSPAN type III*/
97 #define BSO_MASK EN_MASK
98 #define SGT_MASK 0xffff0000
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
106 #define HWID_OFFSET 4
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 */
116 #define ERSPAN_V1_MDSIZE 4
117 #define ERSPAN_V2_MDSIZE 8
119 struct erspan_base_hdr
{
120 #if defined(__LITTLE_ENDIAN_BITFIELD)
124 __u8 session_id_upper
:2,
129 #elif defined(__BIG_ENDIAN_BITFIELD)
139 #error "Please fix <asm/byteorder.h>"
143 static inline void set_session_id(struct erspan_base_hdr
*ershdr
, u16 id
)
145 ershdr
->session_id
= id
& 0xff;
146 ershdr
->session_id_upper
= (id
>> 8) & 0x3;
149 static inline u16
get_session_id(const struct erspan_base_hdr
*ershdr
)
151 return (ershdr
->session_id_upper
<< 8) + ershdr
->session_id
;
154 static inline void set_vlan(struct erspan_base_hdr
*ershdr
, u16 vlan
)
156 ershdr
->vlan
= vlan
& 0xff;
157 ershdr
->vlan_upper
= (vlan
>> 8) & 0xf;
160 static inline u16
get_vlan(const struct erspan_base_hdr
*ershdr
)
162 return (ershdr
->vlan_upper
<< 8) + ershdr
->vlan
;
165 static inline void set_hwid(struct erspan_md2
*md2
, u8 hwid
)
167 md2
->hwid
= hwid
& 0xf;
168 md2
->hwid_upper
= (hwid
>> 4) & 0x3;
171 static inline u8
get_hwid(const struct erspan_md2
*md2
)
173 return (md2
->hwid_upper
<< 4) + md2
->hwid
;
176 static inline int erspan_hdr_len(int version
)
178 return sizeof(struct erspan_base_hdr
) +
179 (version
== 1 ? ERSPAN_V1_MDSIZE
: ERSPAN_V2_MDSIZE
);
182 static inline u8
tos_to_cos(u8 tos
)
191 static inline void erspan_build_header(struct sk_buff
*skb
,
193 bool truncate
, bool is_ipv4
)
195 struct ethhdr
*eth
= (struct ethhdr
*)skb
->data
;
196 enum erspan_encap_type enc_type
;
197 struct erspan_base_hdr
*ershdr
;
206 tos
= is_ipv4
? ip_hdr(skb
)->tos
:
207 (ipv6_hdr(skb
)->priority
<< 4) +
208 (ipv6_hdr(skb
)->flow_lbl
[0] >> 4);
210 enc_type
= ERSPAN_ENCAP_NOVLAN
;
212 /* If mirrored packet has vlan tag, extract tci and
213 * perserve vlan header in the mirrored frame.
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
;
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
);
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
);
234 idx
= (__be32
*)(ershdr
+ 1);
235 *idx
= htonl(index
& INDEX_MASK
);
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.
244 static inline __be32
erspan_get_timestamp(void)
249 kt
= ktime_get_real();
250 h_usecs
= ktime_divns(kt
, 100 * NSEC_PER_USEC
);
252 /* ERSPAN base header only has 32-bit,
253 * so it wraps around 4 days.
255 return htonl((u32
)h_usecs
);
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
)
262 struct ethhdr
*eth
= (struct ethhdr
*)skb
->data
;
263 struct erspan_base_hdr
*ershdr
;
264 struct erspan_md2
*md2
;
270 u8 gra
= 0; /* 100 usec */
271 u8 bso
= truncate
; /* Bad/Short/Oversized */
275 tos
= is_ipv4
? ip_hdr(skb
)->tos
:
276 (ipv6_hdr(skb
)->priority
<< 4) +
277 (ipv6_hdr(skb
)->flow_lbl
[0] >> 4);
279 /* Unlike v1, v2 does not have En field,
280 * so only extract vlan tci field.
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
);
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
);
291 /* Build base header */
292 ershdr
->ver
= ERSPAN_VERSION2
;
293 ershdr
->cos
= tos_to_cos(tos
);
295 ershdr
->t
= truncate
;
296 set_vlan(ershdr
, vlan_tci
);
297 set_session_id(ershdr
, id
);
300 md2
= (struct erspan_md2
*)(ershdr
+ 1);
301 md2
->timestamp
= erspan_get_timestamp();
302 md2
->sgt
= htons(sgt
);
305 md2
->dir
= direction
;
313 #include_next <net/erspan.h>