1#!/usr/bin/env python 2# 3# xdp_redirect_cpu.py Redirect the incoming packet to the specific CPU 4# 5# Copyright (c) 2018 Gary Lin 6# Licensed under the Apache License, Version 2.0 (the "License") 7 8from bcc import BPF 9import time 10import sys 11from multiprocessing import cpu_count 12import ctypes as ct 13 14flags = 0 15def usage(): 16 print("Usage: {0} <in ifdev> <CPU id>".format(sys.argv[0])) 17 print("e.g.: {0} eth0 2\n".format(sys.argv[0])) 18 exit(1) 19 20if len(sys.argv) != 3: 21 usage() 22 23in_if = sys.argv[1] 24cpu_id = int(sys.argv[2]) 25 26max_cpu = cpu_count() 27if (cpu_id > max_cpu): 28 print("Invalid CPU id") 29 exit(1) 30 31# load BPF program 32b = BPF(text = """ 33#define KBUILD_MODNAME "foo" 34#include <uapi/linux/bpf.h> 35#include <linux/in.h> 36#include <linux/if_ether.h> 37 38BPF_CPUMAP(cpumap, __MAX_CPU__); 39BPF_ARRAY(dest, uint32_t, 1); 40BPF_PERCPU_ARRAY(rxcnt, long, 1); 41 42int xdp_redirect_cpu(struct xdp_md *ctx) { 43 void* data_end = (void*)(long)ctx->data_end; 44 void* data = (void*)(long)ctx->data; 45 struct ethhdr *eth = data; 46 uint32_t key = 0; 47 long *value; 48 uint32_t *cpu; 49 uint64_t nh_off; 50 51 nh_off = sizeof(*eth); 52 if (data + nh_off > data_end) 53 return XDP_DROP; 54 55 cpu = dest.lookup(&key); 56 if (!cpu) 57 return XDP_PASS; 58 59 value = rxcnt.lookup(&key); 60 if (value) 61 *value += 1; 62 63 return cpumap.redirect_map(*cpu, 0); 64} 65 66int xdp_dummy(struct xdp_md *ctx) { 67 return XDP_PASS; 68} 69""", cflags=["-w", "-D__MAX_CPU__=%u" % max_cpu], debug=0) 70 71dest = b.get_table("dest") 72dest[0] = ct.c_uint32(cpu_id) 73 74cpumap = b.get_table("cpumap") 75cpumap[cpu_id] = ct.c_uint32(192) 76 77in_fn = b.load_func("xdp_redirect_cpu", BPF.XDP) 78b.attach_xdp(in_if, in_fn, flags) 79 80rxcnt = b.get_table("rxcnt") 81prev = 0 82print("Printing redirected packets, hit CTRL+C to stop") 83while 1: 84 try: 85 val = rxcnt.sum(0).value 86 if val: 87 delta = val - prev 88 prev = val 89 print("{} pkt/s to CPU {}".format(delta, cpu_id)) 90 time.sleep(1) 91 except KeyboardInterrupt: 92 print("Removing filter from device") 93 break 94 95b.remove_xdp(in_if, flags) 96