decode/erspan: support ERSPAN Type III

ERSPAN Type III is carried in GRE with protocol type 0x22EB. It has
a 12 byte header with version 2, optionally followed by an 8 byte
platform specific sub-header when the O flag is set.

Decode the header, store the VLAN id as is done for Type II and
pass the mirrored frame to the ethernet decoder. Frame types other
than ethernet set the new erspan.unsupported_encapsulation event.

Ticket: #8329
pull/16376/head
Gianni Tedesco 8 months ago committed by Johan Ryberg
parent 3752af6cd7
commit caf832eadc
No known key found for this signature in database
GPG Key ID: 9EAFBAC37BD836F5

@ -7109,6 +7109,10 @@
"type": "integer",
"description": "Number of packets with too many VLAN layers for ERSPAN"
},
"unsupported_encapsulation": {
"type": "integer",
"description": "Number of packets with unsupported encapsulation for ERSPAN"
},
"unsupported_version": {
"type": "integer",
"description": "Number of packets with unsupported version for ERSPAN"

@ -47,6 +47,14 @@ typedef struct ErspanHdr_ {
uint32_t padding;
} __attribute__((__packed__)) ErspanHdr;
typedef struct Erspan3Hdr_ {
uint16_t ver_vlan;
uint16_t flags_spanid;
uint32_t timestamp;
uint16_t sgt;
uint16_t flags;
} __attribute__((__packed__)) Erspan3Hdr;
/**
* \brief Functions to decode ERSPAN Type I and II packets
*/
@ -117,6 +125,69 @@ int DecodeERSPAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t
return DecodeEthernet(tv, dtv, p, pkt + sizeof(ErspanHdr), len - sizeof(ErspanHdr));
}
/**
* \brief ERSPAN Type III
*/
int DecodeERSPANTypeIII(
ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
{
DEBUG_VALIDATE_BUG_ON(pkt == NULL);
StatsCounterIncr(&tv->stats, dtv->counter_erspan);
if (len < sizeof(Erspan3Hdr)) {
ENGINE_SET_EVENT(p, ERSPAN_HEADER_TOO_SMALL);
return TM_ECODE_FAILED;
}
if (!PacketIncreaseCheckLayers(p)) {
return TM_ECODE_FAILED;
}
const Erspan3Hdr *ehdr = (const Erspan3Hdr *)pkt;
uint16_t version = SCNtohs(ehdr->ver_vlan) >> 12;
uint16_t vlan_id = SCNtohs(ehdr->ver_vlan) & 0x0fff;
uint16_t flags = SCNtohs(ehdr->flags);
pkt += sizeof(Erspan3Hdr);
len -= sizeof(Erspan3Hdr);
if (version != 2) {
ENGINE_SET_EVENT(p, ERSPAN_UNSUPPORTED_VERSION);
return TM_ECODE_FAILED;
}
/* If O flag is set, then the optional platform specific header is present.
* We need to skip past it.
*/
#define PLATFORM_SPECIFIC_HDR_SIZE 8
if (flags & 0x0001) {
if (len < PLATFORM_SPECIFIC_HDR_SIZE) {
ENGINE_SET_EVENT(p, ERSPAN_HEADER_TOO_SMALL);
return TM_ECODE_FAILED;
}
pkt += PLATFORM_SPECIFIC_HDR_SIZE;
len -= PLATFORM_SPECIFIC_HDR_SIZE;
}
if (vlan_id > 0) {
if (p->vlan_idx > VLAN_MAX_LAYER_IDX) {
ENGINE_SET_EVENT(p, ERSPAN_TOO_MANY_VLAN_LAYERS);
return TM_ECODE_FAILED;
}
p->vlan_id[p->vlan_idx] = vlan_id;
p->vlan_idx++;
}
switch ((flags & 0x7c00) >> 10) {
case 0x00: /* ethernet */
return DecodeEthernet(tv, dtv, p, pkt, len);
default:
ENGINE_SET_EVENT(p, ERSPAN_UNSUPPORTED_ENCAPSULATION);
return TM_ECODE_FAILED;
}
}
/**
* @}
*/

@ -46,6 +46,7 @@
#define ETHERNET_TYPE_LOOP 0x9000
#define ETHERNET_TYPE_8021QINQ 0x9100
#define ETHERNET_TYPE_ERSPAN 0x88BE
#define ETHERNET_TYPE_ERSPAN_III 0x22EB /* ERSPAN III */
#define ETHERNET_TYPE_DCE 0x8903 /* Data center ethernet,
* Cisco Fabric Path */
#define ETHERNET_TYPE_ETAG 0x893F /* 802.1BR */

@ -603,6 +603,10 @@ const struct DecodeEvents_ DEvents[] = {
"decoder.erspan.too_many_vlan_layers",
ERSPAN_TOO_MANY_VLAN_LAYERS,
},
{
"decoder.erspan.unsupported_encapsulation",
ERSPAN_UNSUPPORTED_ENCAPSULATION,
},
/* Cisco Fabric Path/DCE events. */
{

@ -221,6 +221,7 @@ enum {
ERSPAN_HEADER_TOO_SMALL,
ERSPAN_UNSUPPORTED_VERSION,
ERSPAN_TOO_MANY_VLAN_LAYERS,
ERSPAN_UNSUPPORTED_ENCAPSULATION,
/* Cisco Fabric Path/DCE events. */
DCE_PKT_TOO_SMALL,

@ -262,6 +262,15 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p
}
break;
}
case ETHERNET_TYPE_ERSPAN_III: {
Packet *tp = PacketTunnelPktSetup(
tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_ERSPANIII);
if (tp != NULL) {
PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE);
PacketEnqueueNoLock(&tv->decode_pq, tp);
}
break;
}
case ETHERNET_TYPE_BRIDGE:
{

@ -198,6 +198,8 @@ static int DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const
return DecodeVLAN(tv, dtv, p, pkt, len);
case DECODE_TUNNEL_ETHERNET:
return DecodeEthernet(tv, dtv, p, pkt, len);
case DECODE_TUNNEL_ERSPANIII:
return DecodeERSPANTypeIII(tv, dtv, p, pkt, len);
case DECODE_TUNNEL_ERSPANII:
return DecodeERSPAN(tv, dtv, p, pkt, len);
case DECODE_TUNNEL_ERSPANI:

@ -1142,6 +1142,7 @@ static inline void PacketTunnelSetVerdicted(Packet *p)
enum DecodeTunnelProto {
DECODE_TUNNEL_ETHERNET,
DECODE_TUNNEL_ERSPANIII,
DECODE_TUNNEL_ERSPANII,
DECODE_TUNNEL_ERSPANI,
DECODE_TUNNEL_VXLAN,
@ -1206,6 +1207,7 @@ int DecodeIEEE8021ah(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *
int DecodeGeneve(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeVXLAN(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeMPLS(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeERSPANTypeIII(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeERSPAN(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeERSPANTypeI(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeCHDLC(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);

Loading…
Cancel
Save