Skip to content

Commit cd9c0c1

Browse files
committed
Add xdp_vlan02_kern.c to investigate more compiler optimizations
This contains a more advanced version of parse_ethhdr() named __parse_ethhdr_vlan(), that will populate an array of VLAN ids while walking the VLAN headers. Again it turns out, that the compile can figure out if this expansion of code is actually needed or not. This this example is mostly to point out the experiences with the LLVM optimizer. Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
1 parent c117051 commit cd9c0c1

File tree

2 files changed

+119
-0
lines changed

2 files changed

+119
-0
lines changed

packet-solutions/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
XDP_TARGETS := xdp_prog_kern_02 xdp_prog_kern_03
44
XDP_TARGETS += xdp_vlan01_kern
5+
XDP_TARGETS += xdp_vlan02_kern
56
USER_TARGETS := xdp_prog_user
67

78
LIBBPF_DIR = ../libbpf/src/

packet-solutions/xdp_vlan02_kern.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2+
#include <linux/bpf.h>
3+
#include <linux/if_ether.h>
4+
#include <linux/in.h>
5+
6+
#include "bpf_helpers.h"
7+
#include "bpf_endian.h"
8+
9+
/* NOTICE: Re-defining VLAN header levels to parse */
10+
#define VLAN_MAX_DEPTH 10
11+
#include "../common/parsing_helpers.h"
12+
13+
#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
14+
struct vlans {
15+
__u16 id[VLAN_MAX_DEPTH];
16+
};
17+
18+
/* Based on parse_ethhdr() */
19+
static __always_inline int __parse_ethhdr_vlan(struct hdr_cursor *nh,
20+
void *data_end,
21+
struct ethhdr **ethhdr,
22+
struct vlans* vlans)
23+
{
24+
struct ethhdr *eth = nh->pos;
25+
int hdrsize = sizeof(*eth);
26+
struct vlan_hdr *vlh;
27+
__u16 h_proto;
28+
int i;
29+
30+
/* Byte-count bounds check; check if current pointer + size of header
31+
* is after data_end.
32+
*/
33+
if (nh->pos + hdrsize > data_end)
34+
return -1;
35+
36+
nh->pos += hdrsize;
37+
*ethhdr = eth;
38+
vlh = nh->pos;
39+
h_proto = eth->h_proto;
40+
41+
/* Use loop unrolling to avoid the verifier restriction on loops;
42+
* support up to VLAN_MAX_DEPTH layers of VLAN encapsulation.
43+
*/
44+
#pragma unroll
45+
for (i = 0; i < VLAN_MAX_DEPTH; i++) {
46+
if (!proto_is_vlan(h_proto))
47+
break;
48+
49+
if (vlh + 1 > data_end)
50+
break;
51+
52+
h_proto = vlh->h_vlan_encapsulated_proto;
53+
if (vlans) {
54+
vlans->id[i] = vlh->h_vlan_TCI & VLAN_VID_MASK;
55+
}
56+
vlh++;
57+
}
58+
59+
nh->pos = vlh;
60+
return bpf_ntohs(h_proto);
61+
}
62+
63+
SEC("xdp_vlan02")
64+
int xdp_vlan_02(struct xdp_md *ctx)
65+
{
66+
void *data_end = (void *)(long)ctx->data_end;
67+
void *data = (void *)(long)ctx->data;
68+
69+
/* These keep track of the next header type and iterator pointer */
70+
struct hdr_cursor nh;
71+
int eth_type;
72+
nh.pos = data;
73+
74+
struct vlans vlans;
75+
76+
struct ethhdr *eth;
77+
eth_type = __parse_ethhdr_vlan(&nh, data_end, &eth, &vlans);
78+
79+
if (eth_type < 0)
80+
return XDP_ABORTED;
81+
82+
/* The LLVM compiler is very clever, it sees that program only access
83+
* 2nd "inner" vlan (array index 1), and only does loop unroll of 2, and
84+
* only does the VLAN_VID_MASK in the 2nd "inner" vlan case.
85+
*/
86+
if (vlans.id[1] == 42)
87+
return XDP_ABORTED;
88+
89+
/* If using eth_type (even compare against zero), it will cause full
90+
* loop unroll and walking all VLANs (for VLAN_MAX_DEPTH). Still only
91+
* "inner" VLAN is masked out.
92+
*/
93+
#if 0
94+
if (eth_type == 0)
95+
return XDP_PASS;
96+
#endif
97+
98+
/* Unless we only want to manipulate VLAN, then next step will naturally
99+
* be parsing the next L3 headers. This (also) cause compiler to create
100+
* VLAN loop, as this uses nh->pos
101+
*/
102+
#if 0
103+
int ip_type;
104+
struct iphdr *iphdr;
105+
if (eth_type == ETH_P_IP) {
106+
ip_type = parse_iphdr(&nh, data_end, &iphdr);
107+
if (eth_type < 0)
108+
return XDP_ABORTED;
109+
110+
if (ip_type == IPPROTO_UDP)
111+
return XDP_DROP;
112+
}
113+
#endif
114+
/* Hint: to inspect BPF byte-code run:
115+
* llvm-objdump -S xdp_vlan02_kern.o
116+
*/
117+
return XDP_PASS;
118+
}

0 commit comments

Comments
 (0)