forked from iovisor/bcc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add DEVMAP, CPUMAP, and redirect_map() to the reference guide
Also add a simple example for DEVMAP based on xdp_drop_count.py v2: Add an example for CPUMAP Signed-off-by: Gary Lin <[email protected]>
- Loading branch information
Showing
3 changed files
with
293 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
#!/usr/bin/env python | ||
# | ||
# xdp_redirect_cpu.py Redirect the incoming packet to the specific CPU | ||
# | ||
# Copyright (c) 2018 Gary Lin | ||
# Licensed under the Apache License, Version 2.0 (the "License") | ||
|
||
from bcc import BPF | ||
import time | ||
import sys | ||
from multiprocessing import cpu_count | ||
import ctypes as ct | ||
|
||
flags = 0 | ||
def usage(): | ||
print("Usage: {0} <in ifdev> <CPU id>".format(sys.argv[0])) | ||
print("e.g.: {0} eth0 2\n".format(sys.argv[0])) | ||
exit(1) | ||
|
||
if len(sys.argv) != 3: | ||
usage() | ||
|
||
in_if = sys.argv[1] | ||
cpu_id = int(sys.argv[2]) | ||
|
||
max_cpu = cpu_count() | ||
if (cpu_id > max_cpu): | ||
print("Invalid CPU id") | ||
exit(1) | ||
|
||
# load BPF program | ||
b = BPF(text = """ | ||
#define KBUILD_MODNAME "foo" | ||
#include <uapi/linux/bpf.h> | ||
#include <linux/in.h> | ||
#include <linux/if_ether.h> | ||
BPF_CPUMAP(cpumap, __MAX_CPU__); | ||
BPF_ARRAY(dest, uint32_t, 1); | ||
BPF_PERCPU_ARRAY(rxcnt, long, 1); | ||
int xdp_redirect_cpu(struct xdp_md *ctx) { | ||
void* data_end = (void*)(long)ctx->data_end; | ||
void* data = (void*)(long)ctx->data; | ||
struct ethhdr *eth = data; | ||
uint32_t key = 0; | ||
long *value; | ||
uint32_t *cpu; | ||
uint64_t nh_off; | ||
nh_off = sizeof(*eth); | ||
if (data + nh_off > data_end) | ||
return XDP_DROP; | ||
cpu = dest.lookup(&key); | ||
if (!cpu) | ||
return XDP_PASS; | ||
value = rxcnt.lookup(&key); | ||
if (value) | ||
*value += 1; | ||
return cpumap.redirect_map(*cpu, 0); | ||
} | ||
int xdp_dummy(struct xdp_md *ctx) { | ||
return XDP_PASS; | ||
} | ||
""", cflags=["-w", "-D__MAX_CPU__=%u" % max_cpu], debug=0) | ||
|
||
dest = b.get_table("dest"); | ||
dest[0] = ct.c_uint32(cpu_id) | ||
|
||
cpumap = b.get_table("cpumap"); | ||
cpumap[cpu_id] = ct.c_uint32(192) | ||
|
||
in_fn = b.load_func("xdp_redirect_cpu", BPF.XDP) | ||
b.attach_xdp(in_if, in_fn, flags) | ||
|
||
rxcnt = b.get_table("rxcnt") | ||
prev = 0 | ||
print("Printing redirected packets, hit CTRL+C to stop") | ||
while 1: | ||
try: | ||
val = rxcnt.sum(0).value | ||
if val: | ||
delta = val - prev | ||
prev = val | ||
print("{} pkt/s to CPU {}".format(delta, cpu_id)) | ||
time.sleep(1) | ||
except KeyboardInterrupt: | ||
print("Removing filter from device") | ||
break; | ||
|
||
b.remove_xdp(in_if, flags) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
#!/usr/bin/env python | ||
# | ||
# xdp_redirect_map.py Redirect the incoming packet to another interface | ||
# with the helper: bpf_redirect_map() | ||
# | ||
# Copyright (c) 2018 Gary Lin | ||
# Licensed under the Apache License, Version 2.0 (the "License") | ||
|
||
from bcc import BPF | ||
import pyroute2 | ||
import time | ||
import sys | ||
import ctypes as ct | ||
|
||
flags = 0 | ||
def usage(): | ||
print("Usage: {0} <in ifdev> <out ifdev>".format(sys.argv[0])) | ||
print("e.g.: {0} eth0 eth1\n".format(sys.argv[0])) | ||
exit(1) | ||
|
||
if len(sys.argv) != 3: | ||
usage() | ||
|
||
in_if = sys.argv[1] | ||
out_if = sys.argv[2] | ||
|
||
ip = pyroute2.IPRoute() | ||
out_idx = ip.link_lookup(ifname=out_if)[0] | ||
|
||
# load BPF program | ||
b = BPF(text = """ | ||
#define KBUILD_MODNAME "foo" | ||
#include <uapi/linux/bpf.h> | ||
#include <linux/in.h> | ||
#include <linux/if_ether.h> | ||
BPF_DEVMAP(tx_port, 1); | ||
BPF_PERCPU_ARRAY(rxcnt, long, 1); | ||
static inline void swap_src_dst_mac(void *data) | ||
{ | ||
unsigned short *p = data; | ||
unsigned short dst[3]; | ||
dst[0] = p[0]; | ||
dst[1] = p[1]; | ||
dst[2] = p[2]; | ||
p[0] = p[3]; | ||
p[1] = p[4]; | ||
p[2] = p[5]; | ||
p[3] = dst[0]; | ||
p[4] = dst[1]; | ||
p[5] = dst[2]; | ||
} | ||
int xdp_redirect_map(struct xdp_md *ctx) { | ||
void* data_end = (void*)(long)ctx->data_end; | ||
void* data = (void*)(long)ctx->data; | ||
struct ethhdr *eth = data; | ||
uint32_t key = 0; | ||
long *value; | ||
uint64_t nh_off; | ||
nh_off = sizeof(*eth); | ||
if (data + nh_off > data_end) | ||
return XDP_DROP; | ||
value = rxcnt.lookup(&key); | ||
if (value) | ||
*value += 1; | ||
swap_src_dst_mac(data); | ||
return tx_port.redirect_map(0, 0); | ||
} | ||
int xdp_dummy(struct xdp_md *ctx) { | ||
return XDP_PASS; | ||
} | ||
""", cflags=["-w"]) | ||
|
||
tx_port = b.get_table("tx_port") | ||
tx_port[0] = ct.c_int(out_idx) | ||
|
||
in_fn = b.load_func("xdp_redirect_map", BPF.XDP) | ||
out_fn = b.load_func("xdp_dummy", BPF.XDP) | ||
|
||
b.attach_xdp(in_if, in_fn, flags) | ||
b.attach_xdp(out_if, out_fn, flags) | ||
|
||
rxcnt = b.get_table("rxcnt") | ||
prev = 0 | ||
print("Printing redirected packets, hit CTRL+C to stop") | ||
while 1: | ||
try: | ||
val = rxcnt.sum(0).value | ||
if val: | ||
delta = val - prev | ||
prev = val | ||
print("{} pkt/s".format(delta)) | ||
time.sleep(1) | ||
except KeyboardInterrupt: | ||
print("Removing filter from device") | ||
break; | ||
|
||
b.remove_xdp(in_if, flags) | ||
b.remove_xdp(out_if, flags) |