forked from xdp-project/xdp-tutorial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxdp_prog_kern.c
153 lines (120 loc) · 3.79 KB
/
xdp_prog_kern.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/bpf.h>
#include <linux/in.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
// The parsing helper functions from the packet01 lesson have moved here
#include "../common/parsing_helpers.h"
/* Defines xdp_stats_map */
#include "../common/xdp_stats_kern_user.h"
#include "../common/xdp_stats_kern.h"
/* Pops the outermost VLAN tag off the packet. Returns the popped VLAN ID on
* success or -1 on failure.
*/
static __always_inline int vlan_tag_pop(struct xdp_md *ctx, struct ethhdr *eth)
{
/*
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr eth_cpy;
struct vlan_hdr *vlh;
__be16 h_proto;
*/
int vlid = -1;
/* Check if there is a vlan tag to pop */
/* Still need to do bounds checking */
/* Save vlan ID for returning, h_proto for updating Ethernet header */
/* Make a copy of the outer Ethernet header before we cut it off */
/* Actually adjust the head pointer */
/* Need to re-evaluate data *and* data_end and do new bounds checking
* after adjusting head
*/
/* Copy back the old Ethernet header and update the proto type */
return vlid;
}
/* Pushes a new VLAN tag after the Ethernet header. Returns 0 on success,
* -1 on failure.
*/
static __always_inline int vlan_tag_push(struct xdp_md *ctx,
struct ethhdr *eth, int vlid)
{
return 0;
}
/* Implement assignment 1 in this section */
SEC("xdp")
int xdp_port_rewrite_func(struct xdp_md *ctx)
{
return XDP_PASS;
}
/* VLAN swapper; will pop outermost VLAN tag if it exists, otherwise push a new
* one with ID 1. Use this for assignments 2 and 3.
*/
SEC("xdp")
int xdp_vlan_swap_func(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
/* These keep track of the next header type and iterator pointer */
struct hdr_cursor nh;
int nh_type;
nh.pos = data;
struct ethhdr *eth;
nh_type = parse_ethhdr(&nh, data_end, ð);
if (nh_type < 0)
return XDP_PASS;
/* Assignment 2 and 3 will implement these. For now they do nothing */
if (proto_is_vlan(eth->h_proto))
vlan_tag_pop(ctx, eth);
else
vlan_tag_push(ctx, eth, 1);
return XDP_PASS;
}
/* Solution to the parsing exercise in lesson packet01. Handles VLANs and legacy
* IP (via the helpers in parsing_helpers.h).
*/
SEC("xdp")
int xdp_parser_func(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
/* Default action XDP_PASS, imply everything we couldn't parse, or that
* we don't want to deal with, we just pass up the stack and let the
* kernel deal with it.
*/
__u32 action = XDP_PASS; /* Default action */
/* These keep track of the next header type and iterator pointer */
struct hdr_cursor nh;
int nh_type;
nh.pos = data;
struct ethhdr *eth;
/* Packet parsing in steps: Get each header one at a time, aborting if
* parsing fails. Each helper function does sanity checking (is the
* header type in the packet correct?), and bounds checking.
*/
nh_type = parse_ethhdr(&nh, data_end, ð);
if (nh_type == bpf_htons(ETH_P_IPV6)) {
struct ipv6hdr *ip6h;
struct icmp6hdr *icmp6h;
nh_type = parse_ip6hdr(&nh, data_end, &ip6h);
if (nh_type != IPPROTO_ICMPV6)
goto out;
nh_type = parse_icmp6hdr(&nh, data_end, &icmp6h);
if (nh_type != ICMPV6_ECHO_REQUEST)
goto out;
if (bpf_ntohs(icmp6h->icmp6_sequence) % 2 == 0)
action = XDP_DROP;
} else if (nh_type == bpf_htons(ETH_P_IP)) {
struct iphdr *iph;
struct icmphdr *icmph;
nh_type = parse_iphdr(&nh, data_end, &iph);
if (nh_type != IPPROTO_ICMP)
goto out;
nh_type = parse_icmphdr(&nh, data_end, &icmph);
if (nh_type != ICMP_ECHO)
goto out;
if (bpf_ntohs(icmph->un.echo.sequence) % 2 == 0)
action = XDP_DROP;
}
out:
return xdp_stats_record_action(ctx, action);
}
char _license[] SEC("license") = "GPL";