# XDP firewall
contributed by < `chiacyu` >
## What is XDP?
XDP(Express Data Path)是一種基於 ebpf (Extended Berkeley Packet Filter) 的高速資料傳輸技術,可提供高效率的封包處理服務。
### What is ebpf
#### ebpf 簡介
ebpf (Extended Berkeley Packet Filter) 則是運行於 Linux 核心內部的虛擬機器(virtual machine)使用者可自行撰寫 ebpf 程式並透過相關 API 載入。不同 `program type` 則提供不同的功能,有些可用於系統功能的量測與紀錄系統呼叫的次數等等。

### 載入 ebpf program

編譯過後的 `bpf program` 需要透過一些工具來將程式載入,可以使用 [bpf system call](https://man7.org/linux/man-pages/man2/bpf.2.html)外, 也可以用`int bpf(int cmd, union bpf_attr *attr, unsigned int size);` 透過傳入的參數來定義後續的行為,可以看到 [`union bpf_attr *attr`](https://elixir.bootlin.com/linux/v4.9/source/include/uapi/linux/bpf.h#L110) 的內容
```c
union bpf_attr {
struct { /* anonymous struct used by BPF_MAP_CREATE command */
__u32 map_type; /* one of enum bpf_map_type */
__u32 key_size; /* size of key in bytes */
__u32 value_size; /* size of value in bytes */
__u32 max_entries; /* max number of entries in a map */
__u32 map_flags; /* prealloc or not */
};
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
__u32 map_fd;
__aligned_u64 key;
union {
__aligned_u64 value;
__aligned_u64 next_key;
};
__u64 flags;
};
struct { /* anonymous struct used by BPF_PROG_LOAD command */
__u32 prog_type; /* one of enum bpf_prog_type */
__u32 insn_cnt;
__aligned_u64 insns;
__aligned_u64 license;
__u32 log_level; /* verbosity level of verifier */
__u32 log_size; /* size of user buffer */
__aligned_u64 log_buf; /* user supplied buffer */
__u32 kern_version; /* checked when prog_type=kprobe */
};
...
...
```
其中透過 `prog_type` 可以將 ebpf program 分成幾種類型,每一種則對應到不同的事件,當該事件發生時已載入的 `ebpf program` 也會被啟動。更詳細的 `program type` 可以參考
```c
enum bpf_prog_type {
BPF_PROG_TYPE_UNSPEC,
BPF_PROG_TYPE_SOCKET_FILTER,
BPF_PROG_TYPE_KPROBE,
BPF_PROG_TYPE_SCHED_CLS,
BPF_PROG_TYPE_SCHED_ACT,
BPF_PROG_TYPE_TRACEPOINT,
BPF_PROG_TYPE_XDP,
BPF_PROG_TYPE_PERF_EVENT,
BPF_PROG_TYPE_CGROUP_SKB,
BPF_PROG_TYPE_CGROUP_SOCK,
BPF_PROG_TYPE_LWT_IN,
...
...
...
```
除了撰寫客製化的 bpf program 之外也可以使用 [`bcc`](https://github.com/iovisor/bcc) 提供的許多現成的工具

### ebpf 觸發方式
從 [bcc/tools/](https://github.com/iovisor/bcc/tree/master/tools) 可以看到許多現成的工具可以使用,首先需要針對作業系統的版本安裝所需的套件。 先將 bcc 專案複製到本機端並進入 `tools` 資料夾執行 `sudo python opensnoop.py` 可以看到
```c
chiacyu@chiacyu-Alpha-15-B5EEK:~/Desktop/bcc/tools$ sudo python opensnoop.py
[sudo] password for chiacyu:
PID COMM FD ERR PATH
581 systemd-oomd 7 0 /proc/meminfo
581 systemd-oomd 7 0 /proc/meminfo
581 systemd-oomd 7 0 /proc/meminfo
666 iio-sensor-prox 9 0 /dev/iio:device2
666 iio-sensor-prox 9 0 /dev/iio:device4
667 irqbalance 6 0 /proc/interrupts
667 irqbalance 6 0 /proc/stat
667 irqbalance 6 0 /proc/irq/106/smp_affinity
667 irqbalance 6 0 /proc/irq/99/smp_affinity
...
...
...
```
`opensnoop.py` 這個檔案內容可以看到 `syscall__trace_entry_open` 就是將程式對 `open` 這個 系統呼叫做 `hook` ,當 `open` 被呼叫時 `bpf program` 就會被啟動。
```c
# initialize BPF
b = BPF(text=bpf_text)
if not is_support_kfunc:
b.attach_kprobe(event=fnname_open, fn_name="syscall__trace_entry_open")
b.attach_kretprobe(event=fnname_open, fn_name="trace_return")
b.attach_kprobe(event=fnname_openat, fn_name="syscall__trace_entry_openat")
b.attach_kretprobe(event=fnname_openat, fn_name="trace_return")
...
...
...
```
### 撰寫XDP program
撰寫 `XDP program` 可以參考 [xdp-tutorial](https://github.com/xdp-project/xdp-tutorial/tree/master/basic01-xdp-pass) 的內容。
```c
SEC("xdp")
int xdp_prog_simple(struct xdp_md *ctx)
{
return XDP_PASS;
}
```
接著透過 [`llvm-objdump`](https://llvm.org/docs/CommandGuide/llvm-objdump.html) 可以看到內容為
```c
chiacyu@server:~/Desktop/xdp-tutorial/basic01-xdp-pass$ llvm-objdump -S xdp_pass_kern.o
xdp_pass_kern.o: file format elf64-bpf
Disassembly of section xdp:
0000000000000000 <xdp_prog_simple>:
; return XDP_PASS;
0: b7 00 00 00 02 00 00 00 r0 = 2
1: 95 00 00 00 00 00 00 00 exit
```
其中 section xdp 透過 `SEC` 巨集來定義,可以看到 `0000000000000000` 的 section 出現先前定義的程式 xdp_prog_simple,而 `SEC` 的實做可以詳見 [/tools/lib/bpf/bpf_helpers.h](https://elixir.bootlin.com/linux/latest/source/tools/lib/bpf/bpf_helpers.h#L32)
### XDP-firewall 的運作原理
看到