diff --git a/examples/basic_l3dsr/dscp/Dockerfile b/examples/basic_l3dsr/dscp/Dockerfile new file mode 100644 index 0000000..ec8eed3 --- /dev/null +++ b/examples/basic_l3dsr/dscp/Dockerfile @@ -0,0 +1,5 @@ + +FROM ubuntu:22.04 + +RUN apt update \ + && apt install -y libc6-dev-i386 clang libbpf-dev iproute2 diff --git a/examples/basic_l3dsr/dscp/spec.yaml b/examples/basic_l3dsr/dscp/spec.yaml new file mode 100644 index 0000000..92296fa --- /dev/null +++ b/examples/basic_l3dsr/dscp/spec.yaml @@ -0,0 +1,76 @@ +preinit: + - cmds: + - cmd: docker build -t xdptmp . + +nodes: + - name: R1 + image: xdptmp + interfaces: + - { name: net1, type: direct, args: CLOS#net1 } + sysctls: + - sysctl: net.ipv4.ip_forward=1 + - sysctl: net.ipv4.conf.all.rp_filter=0 + - sysctl: net.ipv4.conf.default.rp_filter=0 + + - name: C1 + image: slankdev/mikanectl + docker_run_extra_args: --entrypoint bash + interfaces: + - { name: net0, type: direct, args: CLOS#net0 } + sysctls: + - sysctl: net.ipv4.ip_forward=1 + - sysctl: net.ipv4.conf.all.rp_filter=0 + - sysctl: net.ipv4.conf.default.rp_filter=0 + + - name: C2 + image: slankdev/mikanectl + docker_run_extra_args: --entrypoint bash + interfaces: + - { name: net2, type: direct, args: CLOS#net2 } + sysctls: + - sysctl: net.ipv4.ip_forward=1 + - sysctl: net.ipv4.conf.all.rp_filter=0 + - sysctl: net.ipv4.conf.default.rp_filter=0 + + - name: CLOS + image: nicolaka/netshoot + interfaces: + - { name: net0, type: direct, args: C1#net0 } + - { name: net1, type: direct, args: R1#net1 } + - { name: net2, type: direct, args: C2#net2 } + sysctls: + - sysctl: net.ipv4.ip_forward=1 + - sysctl: net.ipv4.conf.all.rp_filter=0 + - sysctl: net.ipv4.conf.default.rp_filter=0 + +postinit: + cmds: + - cmd: docker cp xdp.c R1:/root/xdp.c + - cmd: docker exec R1 clang -O2 -Wall -target bpf -c /root/xdp.c + - cmd: docker exec R1 ip link set net1 xdpgeneric obj xdp.o sec xdp-lb + +node_configs: + - name: R1 + cmds: + - cmd: ip addr add 142.0.0.1/32 dev lo + - cmd: ip addr add 10.0.1.1/24 dev net1 + - cmd: ip route add default via 10.0.1.2 + - name: C1 + cmds: + - cmd: ip addr add 10.0.0.1/24 dev net0 + - cmd: ip route add default via 10.0.0.2 + - name: C2 + cmds: + - cmd: nohup mikanectl ifconfig-http -p 80 & + - cmd: ip addr add 10.0.2.1/24 dev net2 + - cmd: ip route add default via 10.0.2.2 + - cmd: ip route add local 142.0.0.1/32 dev lo + - cmd: tc qdisc add dev net2 clsact + - cmd: tc filter add dev net2 ingress u32 match ip dsfield 0xa 0x1e action nat ingress 10.0.2.1 142.0.0.1 + + - name: CLOS + cmds: + - cmd: ip addr add 10.0.0.2/24 dev net0 + - cmd: ip addr add 10.0.1.2/24 dev net1 + - cmd: ip addr add 10.0.2.2/24 dev net2 + - cmd: ip route add 142.0.0.1/32 dev net1 diff --git a/examples/basic_l3dsr/dscp/xdp.c b/examples/basic_l3dsr/dscp/xdp.c new file mode 100644 index 0000000..05398d8 --- /dev/null +++ b/examples/basic_l3dsr/dscp/xdp.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifndef DSCP +#define DSCP 10 +#endif + +static __always_inline __u16 csum_fold_helper(__u64 csum) { + int i; +#pragma unroll + for (i = 0; i < 4; i ++) { + if (csum >> 16) + csum = (csum & 0xffff) + (csum >> 16); + } + return ~csum; +} + +static __always_inline void ipv4_csum(void *data_start, int data_size, __u64 *csum) { + *csum = bpf_csum_diff(0, 0, data_start, data_size, *csum); + *csum = csum_fold_helper(*csum); +} + +static __always_inline int process_ipv4(struct xdp_md* ctx, + __u64 data, __u64 data_end) { + __u8 src_mac[ETH_ALEN]; + struct ethhdr *eth; + struct iphdr *iph; + + __u32 dst_addr = 0xa000201; + __u64 csum = 0; + + eth = (struct ethhdr*)(data); + + if ((__u64)(eth + 1) > data_end) + return XDP_DROP; + + iph = (struct iphdr*)(data + sizeof(struct ethhdr)); + + if ((__u64)(iph + 1) > data_end) + return XDP_DROP; + + if (iph->daddr == bpf_htonl(0x8e000001)) { + iph->tos = DSCP; + iph->daddr = bpf_htonl(dst_addr); + iph->check = 0; + ipv4_csum(iph, sizeof(struct iphdr), &csum); + iph->check = csum; + + __builtin_memcpy(src_mac, eth->h_source, ETH_ALEN); + __builtin_memcpy(eth->h_source, eth->h_dest, ETH_ALEN); + __builtin_memcpy(eth->h_dest, src_mac, ETH_ALEN); + + return XDP_TX; + } + return XDP_PASS; +} + +static __always_inline int process_eth(struct xdp_md* ctx) { + __u64 data = ctx->data; + __u64 data_end = ctx->data_end; + struct ethhdr *eth; + + eth = (struct ethhdr*)data; + + if ((__u64)(eth + 1) > data_end) + return XDP_DROP; + + if (eth->h_proto == bpf_htons(ETH_P_IP)) { + return process_ipv4(ctx, data, data_end); + } + return XDP_PASS; +} + +SEC("xdp-lb") +int entry(struct xdp_md *ctx) { + int ret = process_eth(ctx); + return ret; +} + +char __license[] SEC("license") = "GPL";