Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions common/parsing_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,15 @@ struct icmphdr_common {

/* Allow users of header file to redefine VLAN max depth */
#ifndef VLAN_MAX_DEPTH
#define VLAN_MAX_DEPTH 4
#define VLAN_MAX_DEPTH 2
#endif

#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
/* Struct for collecting VLANs after parsing via parse_ethhdr_vlan */
struct collect_vlans {
__u16 id[VLAN_MAX_DEPTH];
};

static __always_inline int proto_is_vlan(__u16 h_proto)
{
return !!(h_proto == bpf_htons(ETH_P_8021Q) ||
Expand All @@ -70,8 +76,10 @@ static __always_inline int proto_is_vlan(__u16 h_proto)
* Ethernet header. Thus, caller can look at eth->h_proto to see if this was a
* VLAN tagged packet.
*/
static __always_inline int parse_ethhdr(struct hdr_cursor *nh, void *data_end,
struct ethhdr **ethhdr)
static __always_inline int parse_ethhdr_vlan(struct hdr_cursor *nh,
void *data_end,
struct ethhdr **ethhdr,
struct collect_vlans *vlans)
{
struct ethhdr *eth = nh->pos;
int hdrsize = sizeof(*eth);
Expand Down Expand Up @@ -102,13 +110,25 @@ static __always_inline int parse_ethhdr(struct hdr_cursor *nh, void *data_end,
break;

h_proto = vlh->h_vlan_encapsulated_proto;
if (vlans) /* collect VLAN ids */
vlans->id[i] =
(bpf_ntohs(vlh->h_vlan_TCI) & VLAN_VID_MASK);

vlh++;
}

nh->pos = vlh;
return h_proto; /* network-byte-order */
}

static __always_inline int parse_ethhdr(struct hdr_cursor *nh,
void *data_end,
struct ethhdr **ethhdr)
{
/* Expect compiler removes the code that collects VLAN ids */
return parse_ethhdr_vlan(nh, data_end, ethhdr, NULL);
}

static __always_inline int parse_ip6hdr(struct hdr_cursor *nh,
void *data_end,
struct ipv6hdr **ip6hdr)
Expand Down
21 changes: 15 additions & 6 deletions packet-solutions/xdp_vlan02_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@
#define VLAN_MAX_DEPTH 10
#include "../common/parsing_helpers.h"

#if 0
#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
struct vlans {
struct collect_vlans {
__u16 id[VLAN_MAX_DEPTH];
};
#endif

#if 0 /* moved to parsing_helpers.h */
/* Based on parse_ethhdr() */
static __always_inline int __parse_ethhdr_vlan(struct hdr_cursor *nh,
void *data_end,
struct ethhdr **ethhdr,
struct vlans *vlans)
struct collect_vlans *vlans)
{
struct ethhdr *eth = nh->pos;
int hdrsize = sizeof(*eth);
Expand Down Expand Up @@ -51,14 +54,16 @@ static __always_inline int __parse_ethhdr_vlan(struct hdr_cursor *nh,

h_proto = vlh->h_vlan_encapsulated_proto;
if (vlans) {
vlans->id[i] = vlh->h_vlan_TCI & VLAN_VID_MASK;
vlans->id[i] =
bpf_ntohs(vlh->h_vlan_TCI) & VLAN_VID_MASK;
}
vlh++;
}

nh->pos = vlh;
return h_proto; /* network-byte-order */
}
#endif

SEC("xdp_vlan02")
int xdp_vlan_02(struct xdp_md *ctx)
Expand All @@ -71,13 +76,17 @@ int xdp_vlan_02(struct xdp_md *ctx)
int eth_type;
nh.pos = data;

struct vlans vlans;
struct collect_vlans vlans;

struct ethhdr *eth;
eth_type = __parse_ethhdr_vlan(&nh, data_end, &eth, &vlans);

eth_type = parse_ethhdr_vlan(&nh, data_end, &eth, &vlans);
if (eth_type < 0)
return XDP_ABORTED;
/* The eth_type have skipped VLAN-types, but collected VLAN ids. The
* eth ptr still points to Ethernet header, thus to check if this is a
* VLAN packet do proto_is_vlan(eth->h_proto).
*/

/* The LLVM compiler is very clever, it sees that program only access
* 2nd "inner" vlan (array index 1), and only does loop unroll of 2, and
Expand Down Expand Up @@ -112,7 +121,7 @@ int xdp_vlan_02(struct xdp_md *ctx)
}
#endif
/* Hint: to inspect BPF byte-code run:
* llvm-objdump -S xdp_vlan02_kern.o
* llvm-objdump --no-show-raw-insn -S xdp_vlan02_kern.o
*/
return XDP_PASS;
}