Skip to content

Commit 9278fdc

Browse files
committed
Merge branch 'solutions'
2 parents dfb71e3 + 2366e38 commit 9278fdc

File tree

8 files changed

+222
-98
lines changed

8 files changed

+222
-98
lines changed

.gitignore

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,15 @@ Module.symvers
5353
Mkfile.old
5454
dkms.conf
5555

56-
# The xdp_loader program
56+
# Userspace programs
5757
xdp_loader
58+
xdp_stats
59+
xdp_pass_user
60+
xdp_load_and_stats
61+
xdp_prog_user
62+
63+
# tracing userspace programs
64+
trace_load_and_stats
65+
trace_load_and_stats
66+
trace_read
67+
xdp_sample_pkts_user

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
22

3-
LESSONS = $(wildcard basic??-*) $(wildcard packet??-*)
3+
LESSONS = $(wildcard basic??-*) $(wildcard packet*) $(wildcard tracing??-*)
44
LESSONS_CLEAN = $(addsuffix _clean,$(LESSONS))
55

66
.PHONY: clean $(LESSONS) $(LESSONS_CLEAN)

common/parsing_helpers.h

Lines changed: 35 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include <linux/ipv6.h>
2727
#include <linux/icmp.h>
2828
#include <linux/icmpv6.h>
29+
#include <linux/udp.h>
30+
#include <linux/tcp.h>
2931

3032
/* Header cursor to keep track of current parsing position */
3133
struct hdr_cursor {
@@ -185,77 +187,50 @@ static __always_inline int parse_icmphdr_common(struct hdr_cursor *nh,
185187
return h->type;
186188
}
187189

188-
static __always_inline struct ethhdr *get_ethhdr(struct hdr_cursor *nh,
189-
void *data_end)
190-
{
191-
struct ethhdr *eth = nh->pos;
192-
int hdrsize = sizeof(*eth);
193-
194-
/* Byte-count bounds check; check if current pointer + size of header
195-
* is after data_end.
196-
*/
197-
if (nh->pos + hdrsize > data_end)
198-
return NULL;
199-
200-
nh->pos += hdrsize;
201-
return eth;
202-
}
203-
204-
static __always_inline struct ipv6hdr *get_ip6hdr(struct ethhdr *eth,
205-
struct hdr_cursor *nh,
206-
void *data_end)
190+
/*
191+
* parse_tcphdr: parse the udp header and return the length of the udp payload
192+
*/
193+
static __always_inline int parse_udphdr(struct hdr_cursor *nh,
194+
void *data_end,
195+
struct udphdr **udphdr)
207196
{
208-
struct vlan_hdr *vlh = nh->pos;
209-
__u16 h_proto = eth->h_proto;
210-
struct ipv6hdr *ip6h;
211-
int i;
212-
213-
/* Use loop unrolling to avoid the verifier restriction on loops;
214-
* support up to VLAN_MAX_DEPTH layers of VLAN encapsulation.
215-
*/
216-
#pragma unroll
217-
for (i = 0; i < VLAN_MAX_DEPTH; i++) {
218-
if (!(h_proto == bpf_htons(ETH_P_8021Q) ||
219-
h_proto == bpf_htons(ETH_P_8021AD)))
220-
break;
221-
222-
if (vlh + 1 > data_end)
223-
return NULL;
197+
int len;
198+
struct udphdr *h = nh->pos;
224199

225-
h_proto = vlh->h_vlan_encapsulated_proto;
226-
vlh++;
227-
}
228-
229-
ip6h = (void *)vlh;
200+
if (h + 1 > data_end)
201+
return -1;
230202

231-
if (h_proto != bpf_htons(ETH_P_IPV6))
232-
return NULL;
203+
nh->pos = h + 1;
204+
*udphdr = h;
233205

234-
/* Pointer-arithmetic bounds check; pointer +1 points to after end of
235-
* thing being pointed to. We will be using this style in the remainder
236-
* of the tutorial.
237-
*/
238-
if (ip6h + 1 > data_end)
239-
return NULL;
206+
len = bpf_ntohs(h->len) - sizeof(struct udphdr);
207+
if (len < 0)
208+
return -1;
240209

241-
nh->pos = ip6h + 1;
242-
return ip6h;
210+
return len;
243211
}
244212

245-
static __always_inline struct icmp6hdr *get_icmp6hdr(struct ipv6hdr *ip6h,
246-
struct hdr_cursor *nh,
247-
void *data_end)
213+
/*
214+
* parse_tcphdr: parse and return the length of the tcp header
215+
*/
216+
static __always_inline int parse_tcphdr(struct hdr_cursor *nh,
217+
void *data_end,
218+
struct tcphdr **tcphdr)
248219
{
249-
struct icmp6hdr *icmp6h = nh->pos;
220+
int len;
221+
struct tcphdr *h = nh->pos;
250222

251-
if (ip6h->nexthdr != IPPROTO_ICMPV6)
252-
return NULL;
223+
if (h + 1 > data_end)
224+
return -1;
253225

254-
if (icmp6h + 1 > data_end)
255-
return NULL;
226+
len = h->doff * 4;
227+
if ((void *) h + len > data_end)
228+
return -1;
229+
230+
nh->pos = h + 1;
231+
*tcphdr = h;
256232

257-
nh->pos = icmp6h + 1;
258-
return icmp6h;
233+
return len;
259234
}
260235

261236
#endif /* __PARSING_HELPERS_H */

packet-solutions/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
22

3-
XDP_TARGETS := xdp_prog_kern
3+
XDP_TARGETS := xdp_prog_kern_02 xdp_prog_kern_03
44
USER_TARGETS := xdp_prog_user
55

66
LIBBPF_DIR = ../libbpf/src/

packet-solutions/README.org

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,71 @@ This directory contains solutions to all the assignments in the
66
[[file:../packet01-parsing/][packet01]],
77
[[file:../packet02-rewriting/][packet02]], and
88
[[file:../packet03-redirecting/][packet03]] lessons.
9+
10+
* Table of Contents :TOC:
11+
- [[#solutions][Solutions]]
12+
- [[#packet01-packet-parsing][Packet01: packet parsing]]
13+
- [[#packet02-packet-rewriting][Packet02: packet rewriting]]
14+
- [[#packet03-redirecting-packets][Packet03: redirecting packets]]
15+
16+
* Solutions
17+
18+
** Packet01: packet parsing
19+
20+
*** Assignment 1: Fix the bounds checking error
21+
22+
See the =parse_ethhdr= function from the [[file:../common/parsing_helpers.h][parsing_helpers.h]] file.
23+
24+
*** Assignment 2: Parsing the IP header
25+
26+
See the =parse_ip6hdr= function from the [[file:../common/parsing_helpers.h][parsing_helpers.h]] file.
27+
28+
*** Assignment 3: Parsing the ICMPv6 header and reacting to it
29+
30+
See the =parse_icmp6hdr= function from the [[file:../common/parsing_helpers.h][parsing_helpers.h]]
31+
file. The sequence number should be accessed as =bpf_ntohs(icmp6h->icmp6_sequence)=
32+
as it is a 2-byte value in the network order.
33+
34+
*** Assignment 4: Adding VLAN support
35+
36+
See the =parse_ethhdr= function from the [[file:../common/parsing_helpers.h][parsing_helpers.h]] file.
37+
38+
*** Assignment 5: Adding IPv4 support
39+
40+
See the =parse_iphdr= and =parse_icmphdr= functions from the [[file:../common/parsing_helpers.h][parsing_helpers.h]] file.
41+
42+
** Packet02: packet rewriting
43+
44+
*** Assignment 1: Rewrite port numbers
45+
46+
An example XDP program can be found in the =xdp_patch_ports= section in the [[file:xdp_prog_kern_02.c][xdp_prog_kern_02.c]] file. The program will decrease by one destination port number in any TCP or UDP packet.
47+
48+
*** Assignment 2: Remove the outermost VLAN tag
49+
50+
See the =vlan_tag_pop= function from the [[file:../common/rewrite_helpers.h][rewrite_helpers.h]] file.
51+
An example XDP program can be found in the =xdp_vlan_swap= section in the [[file:xdp_prog_kern_02.c][xdp_prog_kern_02.c]] file.
52+
53+
*** Assignment 3: Add back a missing VLAN tag
54+
55+
See the =vlan_tag_push= function from the [[file:../common/rewrite_helpers.h][rewrite_helpers.h]] file.
56+
An example XDP program can be found in the =xdp_vlan_swap= section in the [[file:xdp_prog_kern_02.c][xdp_prog_kern_02.c]] file.
57+
58+
** Packet03: redirecting packets
59+
60+
*** Assignment 1: Send packets back where they came from
61+
62+
See the =xdp_icmp_echo= program in the [[file:xdp_prog_kern_03.c][xdp_prog_kern_03.c]] file.
63+
64+
*** Assignment 2: Redirect packets between two interfaces
65+
66+
See the =xdp_redirect= program in the [[file:xdp_prog_kern_03.c][xdp_prog_kern_03.c]] file.
67+
68+
*** Assignment 3: Extend to a bidirectional router
69+
70+
See the =xdp_redirect_map= program in the [[file:xdp_prog_kern_03.c][xdp_prog_kern_03.c]] file.
71+
Userspace part of the assignment is implemented in the [[file:xdp_prog_user.c][xdp_prog_user.c]] file.
72+
73+
*** Assignment 4: Use the BPF helper for routing
74+
75+
See the =xdp_router= program in the [[file:xdp_prog_kern_03.c][xdp_prog_kern_03.c]] file.
76+
Userspace part of the assignment is implemented in the [[file:xdp_prog_user.c][xdp_prog_user.c]] file.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#include <linux/bpf.h>
3+
#include <linux/in.h>
4+
#include "bpf_helpers.h"
5+
#include "bpf_endian.h"
6+
7+
// The parsing helper functions from the packet01 lesson have moved here
8+
#include "../common/parsing_helpers.h"
9+
#include "../common/rewrite_helpers.h"
10+
11+
/* Defines xdp_stats_map */
12+
#include "../common/xdp_stats_kern_user.h"
13+
#include "../common/xdp_stats_kern.h"
14+
15+
/*
16+
* Solution to the assignment 1 in lesson packet02
17+
*/
18+
SEC("xdp_patch_ports")
19+
int xdp_patch_ports_func(struct xdp_md *ctx)
20+
{
21+
int action = XDP_PASS;
22+
int eth_type, ip_type;
23+
struct ethhdr *eth;
24+
struct iphdr *iphdr;
25+
struct ipv6hdr *ipv6hdr;
26+
struct udphdr *udphdr;
27+
struct tcphdr *tcphdr;
28+
void *data_end = (void *)(long)ctx->data_end;
29+
void *data = (void *)(long)ctx->data;
30+
struct hdr_cursor nh = { .pos = data };
31+
32+
eth_type = parse_ethhdr(&nh, data_end, &eth);
33+
if (eth_type < 0) {
34+
action = XDP_ABORTED;
35+
goto out;
36+
}
37+
38+
if (eth_type == ETH_P_IP) {
39+
ip_type = parse_iphdr(&nh, data_end, &iphdr);
40+
} else if (eth_type == ETH_P_IPV6) {
41+
ip_type = parse_ip6hdr(&nh, data_end, &ipv6hdr);
42+
} else {
43+
goto out;
44+
}
45+
46+
if (ip_type == IPPROTO_UDP) {
47+
if (parse_udphdr(&nh, data_end, &udphdr) < 0) {
48+
action = XDP_ABORTED;
49+
goto out;
50+
}
51+
udphdr->dest = bpf_htons(bpf_ntohs(udphdr->dest) - 1);
52+
} else if (ip_type == IPPROTO_TCP) {
53+
if (parse_tcphdr(&nh, data_end, &tcphdr) < 0) {
54+
action = XDP_ABORTED;
55+
goto out;
56+
}
57+
tcphdr->dest = bpf_htons(bpf_ntohs(tcphdr->dest) - 1);
58+
}
59+
60+
out:
61+
return xdp_stats_record_action(ctx, action);
62+
}
63+
64+
/*
65+
* Solution to the assignments 2 and 3 in lesson packet02: Will pop outermost
66+
* VLAN tag if it exists, otherwise push a new one with ID 1
67+
*/
68+
SEC("xdp_vlan_swap")
69+
int xdp_vlan_swap_func(struct xdp_md *ctx)
70+
{
71+
void *data_end = (void *)(long)ctx->data_end;
72+
void *data = (void *)(long)ctx->data;
73+
74+
/* These keep track of the next header type and iterator pointer */
75+
struct hdr_cursor nh;
76+
int nh_type;
77+
nh.pos = data;
78+
79+
struct ethhdr *eth;
80+
nh_type = parse_ethhdr(&nh, data_end, &eth);
81+
if (nh_type < 0)
82+
return XDP_PASS;
83+
84+
if (proto_is_vlan(eth->h_proto))
85+
vlan_tag_pop(ctx, eth);
86+
else
87+
vlan_tag_push(ctx, eth, 1);
88+
89+
return XDP_PASS;
90+
}
91+
92+
SEC("xdp_pass")
93+
int xdp_pass_func(struct xdp_md *ctx)
94+
{
95+
return XDP_PASS;
96+
}
97+
98+
char _license[] SEC("license") = "GPL";

packet-solutions/xdp_prog_kern.c renamed to packet-solutions/xdp_prog_kern_03.c

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,33 +30,6 @@ struct bpf_map_def SEC("maps") redirect_params = {
3030
.max_entries = 1,
3131
};
3232

33-
/* Solution to the assignments in lesson packet02: Will pop outermost VLAN tag
34-
* if it exists, otherwise push a new one with ID 1
35-
*/
36-
SEC("xdp_vlan_swap")
37-
int xdp_vlan_swap_func(struct xdp_md *ctx)
38-
{
39-
void *data_end = (void *)(long)ctx->data_end;
40-
void *data = (void *)(long)ctx->data;
41-
42-
/* These keep track of the next header type and iterator pointer */
43-
struct hdr_cursor nh;
44-
int nh_type;
45-
nh.pos = data;
46-
47-
struct ethhdr *eth;
48-
nh_type = parse_ethhdr(&nh, data_end, &eth);
49-
if (nh_type < 0)
50-
return XDP_PASS;
51-
52-
if (proto_is_vlan(eth->h_proto))
53-
vlan_tag_pop(ctx, eth);
54-
else
55-
vlan_tag_push(ctx, eth, 1);
56-
57-
return XDP_PASS;
58-
}
59-
6033
static __always_inline __u16 csum_fold_helper(__u32 csum)
6134
{
6235
return ~((csum & 0xffff) + (csum >> 16));
@@ -172,7 +145,7 @@ int xdp_icmp_echo_func(struct xdp_md *ctx)
172145
return xdp_stats_record_action(ctx, action);
173146
}
174147

175-
/* Assignment 2 */
148+
/* Solution to packet03/assignment-2 */
176149
SEC("xdp_redirect")
177150
int xdp_redirect_func(struct xdp_md *ctx)
178151
{
@@ -201,7 +174,7 @@ int xdp_redirect_func(struct xdp_md *ctx)
201174
return xdp_stats_record_action(ctx, action);
202175
}
203176

204-
/* Assignment 3 */
177+
/* Solution to packet03/assignment-3 */
205178
SEC("xdp_redirect_map")
206179
int xdp_redirect_map_func(struct xdp_md *ctx)
207180
{

0 commit comments

Comments
 (0)