Skip to content

Commit cb146f2

Browse files
committed
packet: move helpers which rewrite headers to a separate file
Move helpers which rewrite headers, such as vlan_tag_pop or swap_src_dst_ipv4 to a separate header file so that they can be reused. Signed-off-by: Anton Protopopov <a.s.protopopov@gmail.com>
1 parent 52c592e commit cb146f2

2 files changed

Lines changed: 142 additions & 113 deletions

File tree

common/rewrite_helpers.h

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* This file contains functions that are used in the packetXX XDP programs to
4+
* manipulate on packets data. The functions are marked as __always_inline, and
5+
* fully defined in this header file to be included in the BPF program.
6+
*/
7+
8+
#ifndef __REWRITE_HELPERS_H
9+
#define __REWRITE_HELPERS_H
10+
11+
#include <linux/bpf.h>
12+
#include <linux/ip.h>
13+
#include <linux/ipv6.h>
14+
#include <linux/if_ether.h>
15+
16+
#include "bpf_helpers.h"
17+
#include "bpf_endian.h"
18+
19+
/* Pops the outermost VLAN tag off the packet. Returns the popped VLAN ID on
20+
* success or negative errno on failure.
21+
*/
22+
static __always_inline int vlan_tag_pop(struct xdp_md *ctx, struct ethhdr *eth)
23+
{
24+
void *data_end = (void *)(long)ctx->data_end;
25+
struct ethhdr eth_cpy;
26+
struct vlan_hdr *vlh;
27+
__be16 h_proto;
28+
int vlid;
29+
30+
if (!proto_is_vlan(eth->h_proto))
31+
return -1;
32+
33+
/* Careful with the parenthesis here */
34+
vlh = (void *)(eth + 1);
35+
36+
/* Still need to do bounds checking */
37+
if (vlh + 1 > data_end)
38+
return -1;
39+
40+
/* Save vlan ID for returning, h_proto for updating Ethernet header */
41+
vlid = bpf_ntohs(vlh->h_vlan_TCI);
42+
h_proto = vlh->h_vlan_encapsulated_proto;
43+
44+
/* Make a copy of the outer Ethernet header before we cut it off */
45+
__builtin_memcpy(&eth_cpy, eth, sizeof(eth_cpy));
46+
47+
/* Actually adjust the head pointer */
48+
if (bpf_xdp_adjust_head(ctx, (int)sizeof(*vlh)))
49+
return -1;
50+
51+
/* Need to re-evaluate data *and* data_end and do new bounds checking
52+
* after adjusting head
53+
*/
54+
eth = (void *)(long)ctx->data;
55+
data_end = (void *)(long)ctx->data_end;
56+
if (eth + 1 > data_end)
57+
return -1;
58+
59+
/* Copy back the old Ethernet header and update the proto type */
60+
__builtin_memcpy(eth, &eth_cpy, sizeof(*eth));
61+
eth->h_proto = h_proto;
62+
63+
return vlid;
64+
}
65+
66+
/* Pushes a new VLAN tag after the Ethernet header. Returns 0 on success,
67+
* -1 on failure.
68+
*/
69+
static __always_inline int vlan_tag_push(struct xdp_md *ctx,
70+
struct ethhdr *eth, int vlid)
71+
{
72+
void *data_end = (void *)(long)ctx->data_end;
73+
struct ethhdr eth_cpy;
74+
struct vlan_hdr *vlh;
75+
76+
/* First copy the original Ethernet header */
77+
__builtin_memcpy(&eth_cpy, eth, sizeof(eth_cpy));
78+
79+
/* Then add space in front of the packet */
80+
if (bpf_xdp_adjust_head(ctx, 0 - (int)sizeof(*vlh)))
81+
return -1;
82+
83+
/* Need to re-evaluate data_end and data after head adjustment, and
84+
* bounds check, even though we know there is enough space (as we
85+
* increased it).
86+
*/
87+
data_end = (void *)(long)ctx->data_end;
88+
eth = (void *)(long)ctx->data;
89+
90+
if (eth + 1 > data_end)
91+
return -1;
92+
93+
/* Copy back the Ethernet header in the right place, populate the VLAN
94+
* tag with the ID and proto, and set the outer Ethernet header to VLAN
95+
* type. */
96+
__builtin_memcpy(eth, &eth_cpy, sizeof(*eth));
97+
98+
vlh = (void *)(eth +1);
99+
100+
if (vlh + 1 > data_end)
101+
return -1;
102+
103+
vlh->h_vlan_TCI = bpf_htons(vlid);
104+
vlh->h_vlan_encapsulated_proto = eth->h_proto;
105+
106+
eth->h_proto = bpf_htons(ETH_P_8021Q);
107+
return 0;
108+
}
109+
110+
/*
111+
* Swaps destination and source MAC addresses inside an Ethernet header
112+
*/
113+
static __always_inline void swap_src_dst_mac(struct ethhdr *eth)
114+
{
115+
__u8 h_tmp[ETH_ALEN];
116+
__builtin_memcpy(h_tmp, eth->h_source, ETH_ALEN);
117+
__builtin_memcpy(eth->h_source, eth->h_dest, ETH_ALEN);
118+
__builtin_memcpy(eth->h_dest, h_tmp, ETH_ALEN);
119+
}
120+
121+
/*
122+
* Swaps destination and source IPv6 addresses inside an IPv6 header
123+
*/
124+
static __always_inline void swap_src_dst_ipv6(struct ipv6hdr *ipv6)
125+
{
126+
struct in6_addr tmp = ipv6->saddr;
127+
ipv6->saddr = ipv6->daddr;
128+
ipv6->daddr = tmp;
129+
}
130+
131+
/*
132+
* Swaps destination and source IPv4 addresses inside an IPv4 header
133+
*/
134+
static __always_inline void swap_src_dst_ipv4(struct iphdr *iphdr)
135+
{
136+
__be32 tmp = iphdr->saddr;
137+
iphdr->saddr = iphdr->daddr;
138+
iphdr->daddr = tmp;
139+
}
140+
141+
#endif /* __REWRITE_HELPERS_H */

packet-solutions/xdp_prog_kern.c

Lines changed: 1 addition & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
// The parsing helper functions from the packet01 lesson have moved here
88
#include "../common/parsing_helpers.h"
9+
#include "../common/rewrite_helpers.h"
910

1011
/* Defines xdp_stats_map */
1112
#include "../common/xdp_stats_kern_user.h"
@@ -29,97 +30,6 @@ struct bpf_map_def SEC("maps") redirect_params = {
2930
.max_entries = 1,
3031
};
3132

32-
/* Pops the outermost VLAN tag off the packet. Returns the popped VLAN ID on
33-
* success or negative errno on failure.
34-
*/
35-
static __always_inline int vlan_tag_pop(struct xdp_md *ctx, struct ethhdr *eth)
36-
{
37-
void *data_end = (void *)(long)ctx->data_end;
38-
struct ethhdr eth_cpy;
39-
struct vlan_hdr *vlh;
40-
__be16 h_proto;
41-
int vlid;
42-
43-
if (!proto_is_vlan(eth->h_proto))
44-
return -1;
45-
46-
/* Careful with the parenthesis here */
47-
vlh = (void *)(eth + 1);
48-
49-
/* Still need to do bounds checking */
50-
if (vlh + 1 > data_end)
51-
return -1;
52-
53-
/* Save vlan ID for returning, h_proto for updating Ethernet header */
54-
vlid = bpf_ntohs(vlh->h_vlan_TCI);
55-
h_proto = vlh->h_vlan_encapsulated_proto;
56-
57-
/* Make a copy of the outer Ethernet header before we cut it off */
58-
__builtin_memcpy(&eth_cpy, eth, sizeof(eth_cpy));
59-
60-
/* Actually adjust the head pointer */
61-
if (bpf_xdp_adjust_head(ctx, (int)sizeof(*vlh)))
62-
return -1;
63-
64-
/* Need to re-evaluate data *and* data_end and do new bounds checking
65-
* after adjusting head
66-
*/
67-
eth = (void *)(long)ctx->data;
68-
data_end = (void *)(long)ctx->data_end;
69-
if (eth + 1 > data_end)
70-
return -1;
71-
72-
/* Copy back the old Ethernet header and update the proto type */
73-
__builtin_memcpy(eth, &eth_cpy, sizeof(*eth));
74-
eth->h_proto = h_proto;
75-
76-
return vlid;
77-
}
78-
79-
/* Pushes a new VLAN tag after the Ethernet header. Returns 0 on success,
80-
* -1 on failure.
81-
*/
82-
static __always_inline int vlan_tag_push(struct xdp_md *ctx,
83-
struct ethhdr *eth, int vlid)
84-
{
85-
void *data_end = (void *)(long)ctx->data_end;
86-
struct ethhdr eth_cpy;
87-
struct vlan_hdr *vlh;
88-
89-
/* First copy the original Ethernet header */
90-
__builtin_memcpy(&eth_cpy, eth, sizeof(eth_cpy));
91-
92-
/* Then add space in front of the packet */
93-
if (bpf_xdp_adjust_head(ctx, 0 - (int)sizeof(*vlh)))
94-
return -1;
95-
96-
/* Need to re-evaluate data_end and data after head adjustment, and
97-
* bounds check, even though we know there is enough space (as we
98-
* increased it).
99-
*/
100-
data_end = (void *)(long)ctx->data_end;
101-
eth = (void *)(long)ctx->data;
102-
103-
if (eth + 1 > data_end)
104-
return -1;
105-
106-
/* Copy back the Ethernet header in the right place, populate the VLAN
107-
* tag with the ID and proto, and set the outer Ethernet header to VLAN
108-
* type. */
109-
__builtin_memcpy(eth, &eth_cpy, sizeof(*eth));
110-
111-
vlh = (void *)(eth +1);
112-
113-
if (vlh + 1 > data_end)
114-
return -1;
115-
116-
vlh->h_vlan_TCI = bpf_htons(vlid);
117-
vlh->h_vlan_encapsulated_proto = eth->h_proto;
118-
119-
eth->h_proto = bpf_htons(ETH_P_8021Q);
120-
return 0;
121-
}
122-
12333
/* Solution to the assignments in lesson packet02: Will pop outermost VLAN tag
12434
* if it exists, otherwise push a new one with ID 1
12535
*/
@@ -147,28 +57,6 @@ int xdp_vlan_swap_func(struct xdp_md *ctx)
14757
return XDP_PASS;
14858
}
14959

150-
static __always_inline void swap_src_dst_mac(struct ethhdr *eth)
151-
{
152-
__u8 h_tmp[ETH_ALEN];
153-
memcpy(h_tmp, eth->h_source, ETH_ALEN);
154-
memcpy(eth->h_source, eth->h_dest, ETH_ALEN);
155-
memcpy(eth->h_dest, h_tmp, ETH_ALEN);
156-
}
157-
158-
static __always_inline void swap_src_dst_ipv6(struct ipv6hdr *ipv6)
159-
{
160-
struct in6_addr tmp = ipv6->saddr;
161-
ipv6->saddr = ipv6->daddr;
162-
ipv6->daddr = tmp;
163-
}
164-
165-
static __always_inline void swap_src_dst_ipv4(struct iphdr *iphdr)
166-
{
167-
__be32 tmp = iphdr->saddr;
168-
iphdr->saddr = iphdr->daddr;
169-
iphdr->daddr = tmp;
170-
}
171-
17260
static __always_inline __u16 csum16_add(__u16 csum, __u16 addend)
17361
{
17462
csum += addend;

0 commit comments

Comments
 (0)