1 #ifndef __LINUX_ERSPAN_H
2 #define __LINUX_ERSPAN_H
5 * GRE header for ERSPAN encapsulation (8 octets [34:41]) -- 8 bytes
7 * 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
8 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
9 * |0|0|0|1|0|00000|000000000|00000| Protocol Type for ERSPAN |
10 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
11 * | Sequence Number (increments per packet per session) |
12 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14 * Note that in the above GRE header [RFC1701] out of the C, R, K, S,
15 * s, Recur, Flags, Version fields only S (bit 03) is set to 1. The
16 * other fields are set to zero, so only a sequence number follows.
18 * ERSPAN Version 1 (Type II) header (8 octets [42:49])
20 * 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
21 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22 * | Ver | VLAN | COS | En|T| Session ID |
23 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24 * | Reserved | Index |
25 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28 * ERSPAN Version 2 (Type III) header (12 octets [42:49])
30 * 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
31 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 * | Ver | VLAN | COS |BSO|T| Session ID |
33 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * | SGT |P| FT | Hw ID |D|Gra|O|
37 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 * Platform Specific SubHeader (8 octets, optional)
40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 * | Platf ID | Platform Specific Info |
42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 * | Platform Specific Info |
44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 * GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB
49 #define ERSPAN_VERSION 0x1 /* ERSPAN type II */
50 #define VER_MASK 0xf000
51 #define VLAN_MASK 0x0fff
52 #define COS_MASK 0xe000
53 #define EN_MASK 0x1800
55 #define ID_MASK 0x03ff
56 #define INDEX_MASK 0xfffff
58 #define ERSPAN_VERSION2 0x2 /* ERSPAN type III*/
59 #define BSO_MASK EN_MASK
60 #define SGT_MASK 0xffff0000
62 #define FT_MASK 0x7c00
63 #define HWID_MASK 0x03f0
64 #define DIR_MASK 0x0008
65 #define GRA_MASK 0x0006
71 /* ERSPAN version 2 metadata header */
74 __be16 sgt; /* security group tag */
75 #if defined(__LITTLE_ENDIAN_BITFIELD)
83 #elif defined(__BIG_ENDIAN_BITFIELD)
94 enum erspan_encap_type {
95 ERSPAN_ENCAP_NOVLAN = 0x0, /* originally without VLAN tag */
96 ERSPAN_ENCAP_ISL = 0x1, /* originally ISL encapsulated */
97 ERSPAN_ENCAP_8021Q = 0x2, /* originally 802.1Q encapsulated */
98 ERSPAN_ENCAP_INFRAME = 0x3, /* VLAN tag perserved in frame */
101 #define ERSPAN_V1_MDSIZE 4
102 #define ERSPAN_V2_MDSIZE 8
103 struct erspan_metadata {
105 __be32 index; /* Version 1 (type II)*/
106 struct erspan_md2 md2; /* Version 2 (type III) */
111 struct erspan_base_hdr {
112 #if defined(__LITTLE_ENDIAN_BITFIELD)
116 __u8 session_id_upper:2,
121 #elif defined(__BIG_ENDIAN_BITFIELD)
131 #error "Please fix <asm/byteorder.h>"
135 static inline void set_session_id(struct erspan_base_hdr *ershdr, u16 id)
137 ershdr->session_id = id & 0xff;
138 ershdr->session_id_upper = (id >> 8) & 0x3;
141 static inline u16 get_session_id(const struct erspan_base_hdr *ershdr)
143 return (ershdr->session_id_upper << 8) + ershdr->session_id;
146 static inline void set_vlan(struct erspan_base_hdr *ershdr, u16 vlan)
148 ershdr->vlan = vlan & 0xff;
149 ershdr->vlan_upper = (vlan >> 8) & 0xf;
152 static inline u16 get_vlan(const struct erspan_base_hdr *ershdr)
154 return (ershdr->vlan_upper << 8) + ershdr->vlan;
157 static inline void set_hwid(struct erspan_md2 *md2, u8 hwid)
159 md2->hwid = hwid & 0xf;
160 md2->hwid_upper = (hwid >> 4) & 0x3;
163 static inline u8 get_hwid(const struct erspan_md2 *md2)
165 return (md2->hwid_upper << 4) + md2->hwid;
168 static inline int erspan_hdr_len(int version)
170 return sizeof(struct erspan_base_hdr) +
171 (version == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE);
174 static inline u8 tos_to_cos(u8 tos)
183 static inline void erspan_build_header(struct sk_buff *skb,
185 bool truncate, bool is_ipv4)
187 struct ethhdr *eth = (struct ethhdr *)skb->data;
188 enum erspan_encap_type enc_type;
189 struct erspan_base_hdr *ershdr;
190 struct erspan_metadata *ersmd;
198 tos = is_ipv4 ? ip_hdr(skb)->tos :
199 (ipv6_hdr(skb)->priority << 4) +
200 (ipv6_hdr(skb)->flow_lbl[0] >> 4);
202 enc_type = ERSPAN_ENCAP_NOVLAN;
204 /* If mirrored packet has vlan tag, extract tci and
205 * perserve vlan header in the mirrored frame.
207 if (eth->h_proto == htons(ETH_P_8021Q)) {
208 qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN);
209 vlan_tci = ntohs(qp->tci);
210 enc_type = ERSPAN_ENCAP_INFRAME;
213 skb_push(skb, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
214 ershdr = (struct erspan_base_hdr *)skb->data;
215 memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
217 /* Build base header */
218 ershdr->ver = ERSPAN_VERSION;
219 ershdr->cos = tos_to_cos(tos);
220 ershdr->en = enc_type;
221 ershdr->t = truncate;
222 set_vlan(ershdr, vlan_tci);
223 set_session_id(ershdr, id);
226 ersmd = (struct erspan_metadata *)(ershdr + 1);
227 ersmd->u.index = htonl(index & INDEX_MASK);
230 /* ERSPAN GRA: timestamp granularity
231 * 00b --> granularity = 100 microseconds
232 * 01b --> granularity = 100 nanoseconds
233 * 10b --> granularity = IEEE 1588
234 * Here we only support 100 microseconds.
236 static inline __be32 erspan_get_timestamp(void)
241 kt = ktime_get_real();
242 h_usecs = ktime_divns(kt, 100 * NSEC_PER_USEC);
244 /* ERSPAN base header only has 32-bit,
245 * so it wraps around 4 days.
247 return htonl((u32)h_usecs);
250 static inline void erspan_build_header_v2(struct sk_buff *skb,
251 u32 id, u8 direction, u16 hwid,
252 bool truncate, bool is_ipv4)
254 struct ethhdr *eth = (struct ethhdr *)skb->data;
255 struct erspan_base_hdr *ershdr;
256 struct erspan_metadata *md;
262 u8 gra = 0; /* 100 usec */
263 u8 bso = 0; /* Bad/Short/Oversized */
267 tos = is_ipv4 ? ip_hdr(skb)->tos :
268 (ipv6_hdr(skb)->priority << 4) +
269 (ipv6_hdr(skb)->flow_lbl[0] >> 4);
271 /* Unlike v1, v2 does not have En field,
272 * so only extract vlan tci field.
274 if (eth->h_proto == htons(ETH_P_8021Q)) {
275 qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN);
276 vlan_tci = ntohs(qp->tci);
279 skb_push(skb, sizeof(*ershdr) + ERSPAN_V2_MDSIZE);
280 ershdr = (struct erspan_base_hdr *)skb->data;
281 memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V2_MDSIZE);
283 /* Build base header */
284 ershdr->ver = ERSPAN_VERSION2;
285 ershdr->cos = tos_to_cos(tos);
287 ershdr->t = truncate;
288 set_vlan(ershdr, vlan_tci);
289 set_session_id(ershdr, id);
292 md = (struct erspan_metadata *)(ershdr + 1);
293 md->u.md2.timestamp = erspan_get_timestamp();
294 md->u.md2.sgt = htons(sgt);
297 md->u.md2.dir = direction;
300 set_hwid(&md->u.md2, hwid);