1 #ifndef __LINUX_ERSPAN_H 2 #define __LINUX_ERSPAN_H 3 4 /* 5 * GRE header for ERSPAN encapsulation (8 octets [34:41]) -- 8 bytes 6 * 0 1 2 3 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 13 * 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. 17 * 18 * ERSPAN Version 1 (Type II) header (8 octets [42:49]) 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 21 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 22 * | Ver | VLAN | COS | En|T| Session ID | 23 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 24 * | Reserved | Index | 25 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 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 * 46 * GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB 47 */ 48 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 54 #define T_MASK 0x0400 55 #define ID_MASK 0x03ff 56 #define INDEX_MASK 0xfffff 57 58 #define ERSPAN_VERSION2 0x2 /* ERSPAN type III*/ 59 #define BSO_MASK EN_MASK 60 #define SGT_MASK 0xffff0000 61 #define P_MASK 0x8000 62 #define FT_MASK 0x7c00 63 #define HWID_MASK 0x03f0 64 #define DIR_MASK 0x0008 65 #define GRA_MASK 0x0006 66 #define O_MASK 0x0001 67 68 /* ERSPAN version 2 metadata header */ 69 struct erspan_md2 { 70 __be32 timestamp; 71 __be16 sgt; /* security group tag */ 72 __be16 flags; 73 #define P_OFFSET 15 74 #define FT_OFFSET 10 75 #define HWID_OFFSET 4 76 #define DIR_OFFSET 3 77 #define GRA_OFFSET 1 78 }; 79 80 enum erspan_encap_type { 81 ERSPAN_ENCAP_NOVLAN = 0x0, /* originally without VLAN tag */ 82 ERSPAN_ENCAP_ISL = 0x1, /* originally ISL encapsulated */ 83 ERSPAN_ENCAP_8021Q = 0x2, /* originally 802.1Q encapsulated */ 84 ERSPAN_ENCAP_INFRAME = 0x3, /* VLAN tag perserved in frame */ 85 }; 86 87 #define ERSPAN_V1_MDSIZE 4 88 #define ERSPAN_V2_MDSIZE 8 89 struct erspan_metadata { 90 union { 91 __be32 index; /* Version 1 (type II)*/ 92 struct erspan_md2 md2; /* Version 2 (type III) */ 93 } u; 94 int version; 95 }; 96 97 struct erspan_base_hdr { 98 __be16 ver_vlan; 99 #define VER_OFFSET 12 100 __be16 session_id; 101 #define COS_OFFSET 13 102 #define EN_OFFSET 11 103 #define BSO_OFFSET EN_OFFSET 104 #define T_OFFSET 10 105 }; 106 107 static inline int erspan_hdr_len(int version) 108 { 109 return sizeof(struct erspan_base_hdr) + 110 (version == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE); 111 } 112 113 static inline u8 tos_to_cos(u8 tos) 114 { 115 u8 dscp, cos; 116 117 dscp = tos >> 2; 118 cos = dscp >> 3; 119 return cos; 120 } 121 122 static inline void erspan_build_header(struct sk_buff *skb, 123 __be32 id, u32 index, 124 bool truncate, bool is_ipv4) 125 { 126 struct ethhdr *eth = eth_hdr(skb); 127 enum erspan_encap_type enc_type; 128 struct erspan_base_hdr *ershdr; 129 struct erspan_metadata *ersmd; 130 struct qtag_prefix { 131 __be16 eth_type; 132 __be16 tci; 133 } *qp; 134 u16 vlan_tci = 0; 135 u8 tos; 136 137 tos = is_ipv4 ? ip_hdr(skb)->tos : 138 (ipv6_hdr(skb)->priority << 4) + 139 (ipv6_hdr(skb)->flow_lbl[0] >> 4); 140 141 enc_type = ERSPAN_ENCAP_NOVLAN; 142 143 /* If mirrored packet has vlan tag, extract tci and 144 * perserve vlan header in the mirrored frame. 145 */ 146 if (eth->h_proto == htons(ETH_P_8021Q)) { 147 qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN); 148 vlan_tci = ntohs(qp->tci); 149 enc_type = ERSPAN_ENCAP_INFRAME; 150 } 151 152 skb_push(skb, sizeof(*ershdr) + ERSPAN_V1_MDSIZE); 153 ershdr = (struct erspan_base_hdr *)skb->data; 154 memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V1_MDSIZE); 155 156 /* Build base header */ 157 ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) | 158 (ERSPAN_VERSION << VER_OFFSET)); 159 ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) | 160 ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) | 161 (enc_type << EN_OFFSET & EN_MASK) | 162 ((truncate << T_OFFSET) & T_MASK)); 163 164 /* Build metadata */ 165 ersmd = (struct erspan_metadata *)(ershdr + 1); 166 ersmd->u.index = htonl(index & INDEX_MASK); 167 } 168 169 /* ERSPAN GRA: timestamp granularity 170 * 00b --> granularity = 100 microseconds 171 * 01b --> granularity = 100 nanoseconds 172 * 10b --> granularity = IEEE 1588 173 * Here we only support 100 microseconds. 174 */ 175 static inline __be32 erspan_get_timestamp(void) 176 { 177 u64 h_usecs; 178 ktime_t kt; 179 180 kt = ktime_get_real(); 181 h_usecs = ktime_divns(kt, 100 * NSEC_PER_USEC); 182 183 /* ERSPAN base header only has 32-bit, 184 * so it wraps around 4 days. 185 */ 186 return htonl((u32)h_usecs); 187 } 188 189 static inline void erspan_build_header_v2(struct sk_buff *skb, 190 __be32 id, u8 direction, u16 hwid, 191 bool truncate, bool is_ipv4) 192 { 193 struct ethhdr *eth = eth_hdr(skb); 194 struct erspan_base_hdr *ershdr; 195 struct erspan_metadata *md; 196 struct qtag_prefix { 197 __be16 eth_type; 198 __be16 tci; 199 } *qp; 200 u16 vlan_tci = 0; 201 u16 session_id; 202 u8 gra = 0; /* 100 usec */ 203 u8 bso = 0; /* Bad/Short/Oversized */ 204 u8 sgt = 0; 205 u8 tos; 206 207 tos = is_ipv4 ? ip_hdr(skb)->tos : 208 (ipv6_hdr(skb)->priority << 4) + 209 (ipv6_hdr(skb)->flow_lbl[0] >> 4); 210 211 /* Unlike v1, v2 does not have En field, 212 * so only extract vlan tci field. 213 */ 214 if (eth->h_proto == htons(ETH_P_8021Q)) { 215 qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN); 216 vlan_tci = ntohs(qp->tci); 217 } 218 219 skb_push(skb, sizeof(*ershdr) + ERSPAN_V2_MDSIZE); 220 ershdr = (struct erspan_base_hdr *)skb->data; 221 memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V2_MDSIZE); 222 223 /* Build base header */ 224 ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) | 225 (ERSPAN_VERSION2 << VER_OFFSET)); 226 session_id = (u16)(ntohl(id) & ID_MASK) | 227 ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) | 228 (bso << BSO_OFFSET & BSO_MASK) | 229 ((truncate << T_OFFSET) & T_MASK); 230 ershdr->session_id = htons(session_id); 231 232 /* Build metadata */ 233 md = (struct erspan_metadata *)(ershdr + 1); 234 md->u.md2.timestamp = erspan_get_timestamp(); 235 md->u.md2.sgt = htons(sgt); 236 md->u.md2.flags = htons(((1 << P_OFFSET) & P_MASK) | 237 ((hwid << HWID_OFFSET) & HWID_MASK) | 238 ((direction << DIR_OFFSET) & DIR_MASK) | 239 ((gra << GRA_OFFSET) & GRA_MASK)); 240 } 241 242 #endif 243