Skip to content

Commit b5dbd06

Browse files
authored
Merge pull request aya-rs#72 from vadorovsky/xdp-docs-update
examples/{tc,xdp}*: Use network-types crate instead of aya-tool bindings
2 parents fdc71fe + cbc37cd commit b5dbd06

File tree

90 files changed

+338
-957
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+338
-957
lines changed

docs/book/start/dropping-packets.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ we're going to extend it to allow the dropping of traffic.
55

66
!!! example "Source Code"
77

8-
Full code for the example in this chapter is available [here](https://github.com/aya-rs/book/tree/main/examples/myapp-03)
8+
Full code for the example in this chapter is available [here](https://github.com/aya-rs/book/tree/main/examples/xdp-drop)
99

1010
## Design
1111

@@ -31,8 +31,8 @@ keep this logic in a function called `block_ip`.
3131

3232
Here's what the code looks like now:
3333

34-
```rust linenums="1" title="myapp-ebpf/src/main.rs"
35-
--8<-- "examples/myapp-03/myapp-ebpf/src/main.rs"
34+
```rust linenums="1" title="xdp-drop-ebpf/src/main.rs"
35+
--8<-- "examples/xdp-drop/xdp-drop-ebpf/src/main.rs"
3636
```
3737

3838
1. Create our map
@@ -60,8 +60,8 @@ traffic originating from `1.1.1.1` in this example.
6060

6161
Here's how the userspace code looks:
6262

63-
```rust linenums="1" title="myapp/src/main.rs"
64-
--8<-- "examples/myapp-03/myapp/src/main.rs"
63+
```rust linenums="1" title="xdp-drop/src/main.rs"
64+
--8<-- "examples/xdp-drop/xdp-drop/src/main.rs"
6565
```
6666

6767
1. Get a reference to the map
@@ -71,13 +71,13 @@ Here's how the userspace code looks:
7171

7272
```console
7373
$ RUST_LOG=info cargo xtask run
74-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 1.1.1.1, ACTION 1
75-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 192.168.1.21, ACTION 2
76-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 192.168.1.21, ACTION 2
77-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 18.168.253.132, ACTION 2
78-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 1.1.1.1, ACTION 1
79-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 18.168.253.132, ACTION 2
80-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 18.168.253.132, ACTION 2
81-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 1.1.1.1, ACTION 1
82-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 140.82.121.6, ACTION 2
74+
[2022-10-04T12:46:05Z INFO xdp_drop] SRC: 1.1.1.1, ACTION: 1
75+
[2022-10-04T12:46:05Z INFO xdp_drop] SRC: 192.168.1.21, ACTION: 2
76+
[2022-10-04T12:46:05Z INFO xdp_drop] SRC: 192.168.1.21, ACTION: 2
77+
[2022-10-04T12:46:05Z INFO xdp_drop] SRC: 18.168.253.132, ACTION: 2
78+
[2022-10-04T12:46:05Z INFO xdp_drop] SRC: 1.1.1.1, ACTION: 1
79+
[2022-10-04T12:46:05Z INFO xdp_drop] SRC: 18.168.253.132, ACTION: 2
80+
[2022-10-04T12:46:05Z INFO xdp_drop] SRC: 18.168.253.132, ACTION: 2
81+
[2022-10-04T12:46:05Z INFO xdp_drop] SRC: 1.1.1.1, ACTION: 1
82+
[2022-10-04T12:46:05Z INFO xdp_drop] SRC: 140.82.121.6, ACTION: 2
8383
```

docs/book/start/hello-xdp.md

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
!!! example "Source Code"
44

5-
Full code for the example in this chapter is availble [here](https://github.com/aya-rs/book/tree/main/examples/myapp-01)
5+
Full code for the example in this chapter is available [here](https://github.com/aya-rs/book/tree/main/examples/xdp-hello)
66

77
## Example Project
88

@@ -16,10 +16,10 @@ XDP (eXpress Data Path) programs permit our eBPF program to make decisions about
1616

1717
We must first write the eBPF component of our program.
1818
This is a minimal generated XDP program that permits all traffic.
19-
The logic for this program is located in `myapp-ebpf/src/main.rs` and currently looks like this:
19+
The logic for this program is located in `xdp-hello-ebpf/src/main.rs` and currently looks like this:
2020

21-
```rust linenums="1" title="myapp-ebpf/src/main.rs"
22-
--8<-- "examples/myapp-01/myapp-ebpf/src/main.rs"
21+
```rust linenums="1" title="xdp-hello-ebpf/src/main.rs"
22+
--8<-- "examples/xdp-hello/xdp-hello-ebpf/src/main.rs"
2323
```
2424

2525
1. `#![no_std]` is required since we cannot use the standard library.
@@ -37,9 +37,9 @@ Now we can compile this using `cargo xtask build-ebpf`.
3737
Let's take a look at the compiled eBPF program:
3838

3939
```console
40-
$ llvm-objdump -S target/bpfel-unknown-none/debug/myapp
40+
$ llvm-objdump -S target/bpfel-unknown-none/debug/xdp-hello
4141

42-
target/bpfel-unknown-none/debug/myapp: file format elf64-bpf
42+
target/bpfel-unknown-none/debug/xdp-hello: file format elf64-bpf
4343

4444
Disassembly of section .text:
4545

@@ -74,9 +74,9 @@ Disassembly of section .text:
7474
0000000000000090 <LBB2_3>:
7575
18: 95 00 00 00 00 00 00 00 exit
7676

77-
Disassembly of section xdp/myapp:
77+
Disassembly of section xdp/xdp_hello:
7878

79-
0000000000000000 <myapp>:
79+
0000000000000000 <xdp_hello>:
8080
0: bf 16 00 00 00 00 00 00 r6 = r1
8181
1: b7 07 00 00 00 00 00 00 r7 = 0
8282
2: 63 7a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r7
@@ -93,7 +93,7 @@ Disassembly of section xdp/myapp:
9393
```
9494

9595
The output was trimmed for brevity.
96-
We can see an `xdp/myapp` section here.
96+
We can see an `xdp/xdp_hello` section here.
9797
And in `<LBB0_2>`, `r0 = 2` sets register `0` to `2`, which is the value of the `XDP_PASS` action.
9898
`exit` ends the program.
9999

@@ -102,14 +102,14 @@ Simple!
102102
## User-space Component
103103

104104
Now our eBPF program is complete and compiled, we need a user-space program to load it and attach it to a trace point.
105-
Fortunately, we have a generated program ready in `myapp/src/main.rs` which is going to do that for us.
105+
Fortunately, we have a generated program ready in `xdp-hello/src/main.rs` which is going to do that for us.
106106

107107
### Starting Out
108108

109109
Let's look at the details of our generated user-space application:
110110

111-
```rust linenums="1" title="myapp/src/main.rs"
112-
--8<-- "examples/myapp-01/myapp/src/main.rs"
111+
```rust linenums="1" title="xdp-hello/src/main.rs"
112+
--8<-- "examples/xdp-hello/xdp-hello/src/main.rs"
113113
```
114114

115115
1. `tokio` is the async library we're using, which provides our [Ctrl-C handler](https://docs.rs/tokio/latest/tokio/signal/fn.ctrl_c.html). It will come in useful later as we expand the functionality of the initial program:
@@ -130,10 +130,10 @@ $ cargo xtask run -- -h
130130
:
131131
Finished dev [optimized] target(s) in 0.90s
132132
Finished dev [unoptimized + debuginfo] target(s) in 0.60s
133-
myapp
133+
xdp-hello
134134

135135
USAGE:
136-
myapp [OPTIONS]
136+
xdp-hello [OPTIONS]
137137

138138
OPTIONS:
139139
-h, --help Print help information
@@ -148,13 +148,12 @@ OPTIONS:
148148

149149
```console
150150
$ RUST_LOG=info cargo xtask run
151-
17:51:57 [INFO] myapp: [myapp/src/main.rs:48] Waiting for Ctrl-C...
152-
17:51:57 [INFO] myapp: [src/main.rs:20] received a packet
153-
17:51:57 [INFO] myapp: [src/main.rs:20] received a packet
154-
17:51:57 [INFO] myapp: [src/main.rs:20] received a packet
155-
:
156-
17:51:58 [INFO] myapp: [src/main.rs:20] received a packet
157-
^C17:51:58 [INFO] myapp: [myapp/src/main.rs:50] Exiting...
151+
[2022-12-21T18:03:09Z INFO xdp_hello] Waiting for Ctrl-C...
152+
[2022-12-21T18:03:11Z INFO xdp_hello] received a packet
153+
[2022-12-21T18:03:11Z INFO xdp_hello] received a packet
154+
[2022-12-21T18:03:11Z INFO xdp_hello] received a packet
155+
[2022-12-21T18:03:11Z INFO xdp_hello] received a packet
156+
^C[2022-12-21T18:03:11Z INFO xdp_hello] Exiting...
158157
```
159158

160159
So everytime a packet was received on the interface, a log was printed!
@@ -169,13 +168,13 @@ So everytime a packet was received on the interface, a log was printed!
169168
The program runs until CTRL+C is pressed and then exits.
170169
On exit, Aya takes care of detaching the program for us.
171170

172-
If you issue the `sudo bpftool prog list` command when `myapp` is running you can verify that it is loaded:
171+
If you issue the `sudo bpftool prog list` command when `xdp_hello` is running you can verify that it is loaded:
173172

174173
```console
175-
958: xdp name myapp tag 0137ce4fce70b467 gpl
174+
958: xdp name xdp_hello tag 0137ce4fce70b467 gpl
176175
loaded_at 2022-06-23T13:55:28-0400 uid 0
177176
xlated 2016B jited 1138B memlock 4096B map_ids 275,274,273
178-
pids myapp(131677)
177+
pids xdp-hello(131677)
179178
```
180179

181-
Running the command again once `myapp` has exited will show that the program is no longer running.
180+
Running the command again once `xdp_hello` has exited will show that the program is no longer running.

docs/book/start/logging-packets.md

Lines changed: 31 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Let's expand this program to log the traffic that is being permitted in the user
66

77
!!! example "Source Code"
88

9-
Full code for the example in this chapter is availble [here](https://github.com/aya-rs/book/tree/main/examples/myapp-02)
9+
Full code for the example in this chapter is available [here](https://github.com/aya-rs/book/tree/main/examples/xdp-log)
1010

1111
## Getting Data to User-Space
1212

@@ -17,8 +17,8 @@ To get data from kernel-space to user-space we use an eBPF map. There are numero
1717
While we could go all out and extract data all the way up to L7, we'll constrain our firewall to L3, and to make things easier, IPv4 only.
1818
The data structure that we'll need to send information to user-space will need to hold an IPv4 address and an action for Permit/Deny, we'll encode both as a `u32`.
1919

20-
```rust linenums="1" title="myapp-common/src/lib.rs"
21-
--8<-- "examples/myapp-02/myapp-common/src/lib.rs"
20+
```rust linenums="1" title="xdp-log-common/src/lib.rs"
21+
--8<-- "examples/xdp-log/xdp-log-common/src/lib.rs"
2222
```
2323

2424
1. We implement the `aya::Pod` trait for our struct since it is Plain Old Data as can be safely converted to a byte-slice and back.
@@ -87,73 +87,50 @@ The data structure that we'll need to send information to user-space will need t
8787

8888
## Writing Data
8989

90-
### Generating Bindings To vmlinux.h
90+
### Using Kernel Network Types
9191

92-
To get useful data to add to our maps, we first need some useful data structures to populate with data from the `XdpContext`.
92+
To get useful data to add to our maps, we first need some useful data structures
93+
to populate with data from the `XdpContext`.
9394
We want to log the Source IP Address of incoming traffic, so we'll need to:
9495

9596
1. Read the Ethernet Header to determine if this is an IPv4 Packet
9697
1. Read the Source IP Address from the IPv4 Header
9798

98-
The two structs in the kernel for this are `ethhdr` from `uapi/linux/if_ether.h` and `iphdr` from `uapi/linux/ip.h`.
99-
If I were to use bindgen to generate Rust bindings for those headers, I'd be tied to the kernel version of the system that I'm developing on.
100-
This is where `aya-tool` comes in to play. It can easily generate bindings for using the BTF information in `/sys/kernel/btf/vmlinux`.
99+
The two structs in the kernel for this are `ethhdr` from `uapi/linux/if_ether.h`
100+
and `iphdr` from `uapi/linux/ip.h`. Rust equivalents of those structures (`EthHdr`
101+
and `Ipv4Hdr`) are provided by the [network-types crate](https://crates.io/crates/network-types).
101102

102-
First, we must make sure that `bindgen` is installed.
103-
```sh
104-
cargo install bindgen-cli
105-
```
106-
107-
Once the bindings are generated and checked in to our repository they shouldn't need to be regenerated again unless we need to add a new struct.
108-
109-
Lets use `xtask` to automate this so we can easily reproduce this file in future.
110-
111-
We'll add the following code
112-
113-
=== "xtask/src/codegen.rs"
114-
115-
```rust linenums="1"
116-
--8<-- "examples/myapp-02/xtask/src/codegen.rs"
117-
```
103+
Let's add it to our eBPF crate by adding a dependency on `network-types` in our
104+
`xdp-log-ebpf/Cargo.toml`:
118105

119-
=== "xtask/Cargo.toml"
106+
=== "xdp-log-ebpf/Cargo.toml"
120107

121108
```toml linenums="1"
122-
--8<-- "examples/myapp-02/xtask/Cargo.toml"
109+
--8<-- "examples/xdp-log/xdp-log-ebpf/Cargo.toml"
123110
```
124111

125-
=== "xtask/src/main.rs"
126-
127-
```rust linenums="1"
128-
--8<-- "examples/myapp-02/xtask/src/main.rs"
129-
```
130-
131-
Once we've generated our file using `cargo xtask codegen` from the root of the project.
132-
We can access these by including `mod bindings` from our eBPF code.
133-
134112
### Getting Packet Data From The Context And Into the Map
135113

136114
The `XdpContext` contains two fields, `data` and `data_end`.
137-
`data` is a pointer to the start of the data in kernel memory and `data_end`, a pointer to the end of the data in kernel memory. In order to access this data and ensure that the eBPF verifier is happy, we'll introduce a helper function called `ptr_at`. This function will ensure that before we access any data, we check that it's contained between `data` and `data_end`. It is marked as `unsafe` because when calling the function, you must ensure that there is a valid `T` at that location or there will be undefined behaviour.
115+
`data` is a pointer to the start of the data in kernel memory and `data_end`, a
116+
pointer to the end of the data in kernel memory. In order to access this data
117+
and ensure that the eBPF verifier is happy, we'll introduce a helper function
118+
called `ptr_at`. This function will ensure that before we access any data, we
119+
check that it's contained between `data` and `data_end`. It is marked as `unsafe`
120+
because when calling the function, you must ensure that there is a valid `T` at
121+
that location or there will be undefined behaviour.
138122

139123
With our helper function in place, we can:
140124

141125
1. Read the Ethertype field to check if we have an IPv4 packet.
142126
1. Read the IPv4 Source Address from the IP header
143127

144-
To do this efficiently we'll add a dependency on `memoffset = "0.6"` in our `myapp-ebpf/Cargo.toml`
145-
146-
!!! tip "Reading Fields Using `offset_of!`"
147-
148-
As there is limited stack space, it's more memory efficient to use the `offset_of!` macro to read
149-
a single field from a struct, rather than reading the whole struct and accessing the field by name.
150-
151128
Once we have our IPv4 source address, we can create a `PacketLog` struct and output this to our `PerfEventArray`
152129

153130
The resulting code looks like this:
154131

155-
```rust linenums="1" title="myapp-ebpf/src/main.rs"
156-
--8<-- "examples/myapp-02/myapp-ebpf/src/main.rs"
132+
```rust linenums="1" title="xdp-log-ebpf/src/main.rs"
133+
--8<-- "examples/xdp-log/xdp-log-ebpf/src/main.rs"
157134
```
158135

159136
1. Create our map
@@ -168,16 +145,16 @@ Don't forget to rebuild your eBPF program!
168145
In order to read from the `AsyncPerfEventArray`, we have to call `AsyncPerfEventArray::open()` for each online CPU, then we have to poll the file descriptor for events.
169146
While this is do-able using `PerfEventArray` and `mio` or `epoll`, the code is much less easy to follow. Instead, we'll use `tokio`, which was added to our template for us.
170147

171-
We'll need to add a dependency on `bytes = "1"` to `myapp/Cargo.toml` since this will make it easier
148+
We'll need to add a dependency on `bytes = "1"` to `xdp-log/Cargo.toml` since this will make it easier
172149
to deal with the chunks of bytes yielded by the `AsyncPerfEventArray`.
173150

174151
Here's the code:
175152

176-
```rust linenums="1" title="myapp/src/main.rs"
177-
--8<-- "examples/myapp-02/myapp/src/main.rs"
153+
```rust linenums="1" title="xdp-log/src/main.rs"
154+
--8<-- "examples/xdp-log/xdp-log/src/main.rs"
178155
```
179156

180-
1. Name was not defined in `myapp-ebpf/src/main.rs`, so use `xdp` instead of `myapp`
157+
1. Name was not defined in `xdp-log-ebpf/src/main.rs`, so use `xdp`
181158
2. Define our map
182159
3. Call `open()` for each online CPU
183160
4. Spawn a `tokio::task`
@@ -192,11 +169,9 @@ As before, the interface can be overwritten by providing the interface name as a
192169

193170
```console
194171
$ RUST_LOG=info cargo xtask run
195-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 192.168.1.205, ACTION 2
196-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 192.168.1.21, ACTION 2
197-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 192.168.1.21, ACTION 2
198-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 18.168.253.132, ACTION 2
199-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 18.168.253.132, ACTION 2
200-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 18.168.253.132, ACTION 2
201-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 140.82.121.6, ACTION 2
172+
[2022-12-22T11:32:21Z INFO xdp_log] SRC IP: 172.52.22.104, SRC PORT: 443
173+
[2022-12-22T11:32:21Z INFO xdp_log] SRC IP: 172.52.22.104, SRC PORT: 443
174+
[2022-12-22T11:32:21Z INFO xdp_log] SRC IP: 172.52.22.104, SRC PORT: 443
175+
[2022-12-22T11:32:21Z INFO xdp_log] SRC IP: 172.52.22.104, SRC PORT: 443
176+
[2022-12-22T11:32:21Z INFO xdp_log] SRC IP: 234.130.159.162, SRC PORT: 443
202177
```

examples/myapp-01/.vim/coc-settings.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

examples/myapp-01/.vscode/settings.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

examples/myapp-01/Cargo.toml

Lines changed: 0 additions & 2 deletions
This file was deleted.

examples/myapp-02/.vim/coc-settings.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

examples/myapp-02/.vscode/settings.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

examples/myapp-02/Cargo.toml

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)