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