Back to home page

OSCL-LXR

 
 

    


0001 #ifndef __LINUX_ERSPAN_H
0002 #define __LINUX_ERSPAN_H
0003 
0004 /*
0005  * GRE header for ERSPAN type I encapsulation (4 octets [34:37])
0006  *      0                   1                   2                   3
0007  *      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
0008  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0009  *     |0|0|0|0|0|00000|000000000|00000|    Protocol Type for ERSPAN   |
0010  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0011  *
0012  *  The Type I ERSPAN frame format is based on the barebones IP + GRE
0013  *  encapsulation (as described above) on top of the raw mirrored frame.
0014  *  There is no extra ERSPAN header.
0015  *
0016  *
0017  * GRE header for ERSPAN type II and II encapsulation (8 octets [34:41])
0018  *       0                   1                   2                   3
0019  *      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
0020  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0021  *     |0|0|0|1|0|00000|000000000|00000|    Protocol Type for ERSPAN   |
0022  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0023  *     |      Sequence Number (increments per packet per session)      |
0024  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0025  *
0026  *  Note that in the above GRE header [RFC1701] out of the C, R, K, S,
0027  *  s, Recur, Flags, Version fields only S (bit 03) is set to 1. The
0028  *  other fields are set to zero, so only a sequence number follows.
0029  *
0030  *  ERSPAN Version 1 (Type II) header (8 octets [42:49])
0031  *  0                   1                   2                   3
0032  *  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
0033  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0034  * |  Ver  |          VLAN         | COS | En|T|    Session ID     |
0035  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0036  * |      Reserved         |                  Index                |
0037  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0038  *
0039  *
0040  *  ERSPAN Version 2 (Type III) header (12 octets [42:49])
0041  *  0                   1                   2                   3
0042  *  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
0043  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0044  * |  Ver  |          VLAN         | COS |BSO|T|     Session ID    |
0045  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0046  * |                          Timestamp                            |
0047  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0048  * |             SGT               |P|    FT   |   Hw ID   |D|Gra|O|
0049  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0050  *
0051  *      Platform Specific SubHeader (8 octets, optional)
0052  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0053  * |  Platf ID |               Platform Specific Info              |
0054  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0055  * |                  Platform Specific Info                       |
0056  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0057  *
0058  * GRE proto ERSPAN type I/II = 0x88BE, type III = 0x22EB
0059  */
0060 
0061 #include <linux/ip.h>
0062 #include <linux/ipv6.h>
0063 #include <linux/skbuff.h>
0064 #include <uapi/linux/erspan.h>
0065 
0066 #define ERSPAN_VERSION  0x1 /* ERSPAN type II */
0067 #define VER_MASK    0xf000
0068 #define VLAN_MASK   0x0fff
0069 #define COS_MASK    0xe000
0070 #define EN_MASK     0x1800
0071 #define T_MASK      0x0400
0072 #define ID_MASK     0x03ff
0073 #define INDEX_MASK  0xfffff
0074 
0075 #define ERSPAN_VERSION2 0x2 /* ERSPAN type III*/
0076 #define BSO_MASK    EN_MASK
0077 #define SGT_MASK    0xffff0000
0078 #define P_MASK      0x8000
0079 #define FT_MASK     0x7c00
0080 #define HWID_MASK   0x03f0
0081 #define DIR_MASK    0x0008
0082 #define GRA_MASK    0x0006
0083 #define O_MASK      0x0001
0084 
0085 #define HWID_OFFSET    4
0086 #define DIR_OFFSET     3
0087 
0088 enum erspan_encap_type {
0089     ERSPAN_ENCAP_NOVLAN = 0x0,  /* originally without VLAN tag */
0090     ERSPAN_ENCAP_ISL = 0x1,     /* originally ISL encapsulated */
0091     ERSPAN_ENCAP_8021Q = 0x2,   /* originally 802.1Q encapsulated */
0092     ERSPAN_ENCAP_INFRAME = 0x3, /* VLAN tag perserved in frame */
0093 };
0094 
0095 #define ERSPAN_V1_MDSIZE    4
0096 #define ERSPAN_V2_MDSIZE    8
0097 
0098 struct erspan_base_hdr {
0099 #if defined(__LITTLE_ENDIAN_BITFIELD)
0100     __u8    vlan_upper:4,
0101         ver:4;
0102     __u8    vlan:8;
0103     __u8    session_id_upper:2,
0104         t:1,
0105         en:2,
0106         cos:3;
0107     __u8    session_id:8;
0108 #elif defined(__BIG_ENDIAN_BITFIELD)
0109     __u8    ver: 4,
0110         vlan_upper:4;
0111     __u8    vlan:8;
0112     __u8    cos:3,
0113         en:2,
0114         t:1,
0115         session_id_upper:2;
0116     __u8    session_id:8;
0117 #else
0118 #error "Please fix <asm/byteorder.h>"
0119 #endif
0120 };
0121 
0122 static inline void set_session_id(struct erspan_base_hdr *ershdr, u16 id)
0123 {
0124     ershdr->session_id = id & 0xff;
0125     ershdr->session_id_upper = (id >> 8) & 0x3;
0126 }
0127 
0128 static inline u16 get_session_id(const struct erspan_base_hdr *ershdr)
0129 {
0130     return (ershdr->session_id_upper << 8) + ershdr->session_id;
0131 }
0132 
0133 static inline void set_vlan(struct erspan_base_hdr *ershdr, u16 vlan)
0134 {
0135     ershdr->vlan = vlan & 0xff;
0136     ershdr->vlan_upper = (vlan >> 8) & 0xf;
0137 }
0138 
0139 static inline u16 get_vlan(const struct erspan_base_hdr *ershdr)
0140 {
0141     return (ershdr->vlan_upper << 8) + ershdr->vlan;
0142 }
0143 
0144 static inline void set_hwid(struct erspan_md2 *md2, u8 hwid)
0145 {
0146     md2->hwid = hwid & 0xf;
0147     md2->hwid_upper = (hwid >> 4) & 0x3;
0148 }
0149 
0150 static inline u8 get_hwid(const struct erspan_md2 *md2)
0151 {
0152     return (md2->hwid_upper << 4) + md2->hwid;
0153 }
0154 
0155 static inline int erspan_hdr_len(int version)
0156 {
0157     if (version == 0)
0158         return 0;
0159 
0160     return sizeof(struct erspan_base_hdr) +
0161            (version == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE);
0162 }
0163 
0164 static inline u8 tos_to_cos(u8 tos)
0165 {
0166     u8 dscp, cos;
0167 
0168     dscp = tos >> 2;
0169     cos = dscp >> 3;
0170     return cos;
0171 }
0172 
0173 static inline void erspan_build_header(struct sk_buff *skb,
0174                 u32 id, u32 index,
0175                 bool truncate, bool is_ipv4)
0176 {
0177     struct ethhdr *eth = (struct ethhdr *)skb->data;
0178     enum erspan_encap_type enc_type;
0179     struct erspan_base_hdr *ershdr;
0180     struct qtag_prefix {
0181         __be16 eth_type;
0182         __be16 tci;
0183     } *qp;
0184     u16 vlan_tci = 0;
0185     u8 tos;
0186     __be32 *idx;
0187 
0188     tos = is_ipv4 ? ip_hdr(skb)->tos :
0189             (ipv6_hdr(skb)->priority << 4) +
0190             (ipv6_hdr(skb)->flow_lbl[0] >> 4);
0191 
0192     enc_type = ERSPAN_ENCAP_NOVLAN;
0193 
0194     /* If mirrored packet has vlan tag, extract tci and
0195      *  perserve vlan header in the mirrored frame.
0196      */
0197     if (eth->h_proto == htons(ETH_P_8021Q)) {
0198         qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN);
0199         vlan_tci = ntohs(qp->tci);
0200         enc_type = ERSPAN_ENCAP_INFRAME;
0201     }
0202 
0203     skb_push(skb, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
0204     ershdr = (struct erspan_base_hdr *)skb->data;
0205     memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
0206 
0207     /* Build base header */
0208     ershdr->ver = ERSPAN_VERSION;
0209     ershdr->cos = tos_to_cos(tos);
0210     ershdr->en = enc_type;
0211     ershdr->t = truncate;
0212     set_vlan(ershdr, vlan_tci);
0213     set_session_id(ershdr, id);
0214 
0215     /* Build metadata */
0216     idx = (__be32 *)(ershdr + 1);
0217     *idx = htonl(index & INDEX_MASK);
0218 }
0219 
0220 /* ERSPAN GRA: timestamp granularity
0221  *   00b --> granularity = 100 microseconds
0222  *   01b --> granularity = 100 nanoseconds
0223  *   10b --> granularity = IEEE 1588
0224  * Here we only support 100 microseconds.
0225  */
0226 static inline __be32 erspan_get_timestamp(void)
0227 {
0228     u64 h_usecs;
0229     ktime_t kt;
0230 
0231     kt = ktime_get_real();
0232     h_usecs = ktime_divns(kt, 100 * NSEC_PER_USEC);
0233 
0234     /* ERSPAN base header only has 32-bit,
0235      * so it wraps around 4 days.
0236      */
0237     return htonl((u32)h_usecs);
0238 }
0239 
0240 /* ERSPAN BSO (Bad/Short/Oversized), see RFC1757
0241  *   00b --> Good frame with no error, or unknown integrity
0242  *   01b --> Payload is a Short Frame
0243  *   10b --> Payload is an Oversized Frame
0244  *   11b --> Payload is a Bad Frame with CRC or Alignment Error
0245  */
0246 enum erspan_bso {
0247     BSO_NOERROR = 0x0,
0248     BSO_SHORT = 0x1,
0249     BSO_OVERSIZED = 0x2,
0250     BSO_BAD = 0x3,
0251 };
0252 
0253 static inline u8 erspan_detect_bso(struct sk_buff *skb)
0254 {
0255     /* BSO_BAD is not handled because the frame CRC
0256      * or alignment error information is in FCS.
0257      */
0258     if (skb->len < ETH_ZLEN)
0259         return BSO_SHORT;
0260 
0261     if (skb->len > ETH_FRAME_LEN)
0262         return BSO_OVERSIZED;
0263 
0264     return BSO_NOERROR;
0265 }
0266 
0267 static inline void erspan_build_header_v2(struct sk_buff *skb,
0268                       u32 id, u8 direction, u16 hwid,
0269                       bool truncate, bool is_ipv4)
0270 {
0271     struct ethhdr *eth = (struct ethhdr *)skb->data;
0272     struct erspan_base_hdr *ershdr;
0273     struct erspan_md2 *md2;
0274     struct qtag_prefix {
0275         __be16 eth_type;
0276         __be16 tci;
0277     } *qp;
0278     u16 vlan_tci = 0;
0279     u8 gra = 0; /* 100 usec */
0280     u8 bso = 0; /* Bad/Short/Oversized */
0281     u8 sgt = 0;
0282     u8 tos;
0283 
0284     tos = is_ipv4 ? ip_hdr(skb)->tos :
0285             (ipv6_hdr(skb)->priority << 4) +
0286             (ipv6_hdr(skb)->flow_lbl[0] >> 4);
0287 
0288     /* Unlike v1, v2 does not have En field,
0289      * so only extract vlan tci field.
0290      */
0291     if (eth->h_proto == htons(ETH_P_8021Q)) {
0292         qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN);
0293         vlan_tci = ntohs(qp->tci);
0294     }
0295 
0296     bso = erspan_detect_bso(skb);
0297     skb_push(skb, sizeof(*ershdr) + ERSPAN_V2_MDSIZE);
0298     ershdr = (struct erspan_base_hdr *)skb->data;
0299     memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V2_MDSIZE);
0300 
0301     /* Build base header */
0302     ershdr->ver = ERSPAN_VERSION2;
0303     ershdr->cos = tos_to_cos(tos);
0304     ershdr->en = bso;
0305     ershdr->t = truncate;
0306     set_vlan(ershdr, vlan_tci);
0307     set_session_id(ershdr, id);
0308 
0309     /* Build metadata */
0310     md2 = (struct erspan_md2 *)(ershdr + 1);
0311     md2->timestamp = erspan_get_timestamp();
0312     md2->sgt = htons(sgt);
0313     md2->p = 1;
0314     md2->ft = 0;
0315     md2->dir = direction;
0316     md2->gra = gra;
0317     md2->o = 0;
0318     set_hwid(md2, hwid);
0319 }
0320 
0321 #endif