execute_process(COMMAND ${CLANG} --version OUTPUT_VARIABLE CLANG_VERSION_RAW)
string(REGEX MATCH "[0-9]+[.][0-9]+[.][0-9]+" CLANG_VERSION ${CLANG_VERSION_RAW})
message(STATUS "Found CLANG: ${CLANG} (found version \"${CLANG_VERSION}\")")
-if (CLANG_VERSION VERSION_LESS 3.6.0)
- message(FATAL_ERROR "requires clang version >= 3.6.0, ${CLANG_VERSION} found")
+if (CLANG_VERSION VERSION_LESS 3.5.0)
+ message(FATAL_ERROR "requires clang version >= 3.5.0, ${CLANG_VERSION} found")
endif()
set(CMAKE_C_FLAGS "-Wall")
## Motivation
BPF guarantees that the programs loaded into the kernel cannot crash, and
-cannot run forever, but yet BPF is general purpose enough to perform many
-arbitrary types of computation. Currently, it is possible to write a program in
+cannot run forever, but yet BPF is general purpose enough to perform many
+arbitrary types of computation. Currently, it is possible to write a program in
C that will compile into a valid BPF program, yet it is vastly easier to
write a C program that will compile into invalid BPF (C is like that). The user
-won't know until trying to run the program whether it was valid or not.
+won't know until trying to run the program whether it was valid or not.
With a BPF-specific frontend, one should be able to write in a language and
receive feedback from the compiler on the validity as it pertains to a BPF
The features of this toolkit include:
* End-to-end BPF workflow in a shared library
* The B language - a C-like language for BPF backends
- * Integration with llvm-bpf backend for JIT
+ * Integration with llvm-bpf backend for JIT
* Dynamic (un)loading of JITed programs
* Support for BPF kernel hooks: socket filters, tc classifiers,
tc actions, and kprobes
* CONFIG_BPF_EVENTS=y [optional, for kprobes]
* LLVM 3.7 or newer, compiled with BPF support (currently experimental)
* Clang 3.5 or newer (this requirement is orthoganal to the LLVM requirement,
- and the versions do not necessarily need to match)
+ and the versions do not necessarily need to match)
* cmake, gcc-4.9, flex, bison, xxd, libstdc++-static, libmnl-devel
+## Getting started
+
+Included in the scripts/ directory of this project is a VM kickstart script that
+captures the above requirements inside a Fedora VM. Before running the script,
+ensure that virt-install is available on the system.
+
+`./build_bpf_demo.sh -n bpf-demo -k bpf_demo.ks.erb`
+
+After setting up the initial VM, log in (the default password is 'iovisor')
+and determine the DHCP IP. SSH to this IP as root.
+
+To set up a kernel with the right options, run `bpf-kernel-setup`.
+
+```
+[root@bpf-demo ~]# bpf-kernel-setup
+Cloning into 'net-next'...
+```
+After pulling the net-next branch, the kernel config menu should pop up. Ensure
+that the below settings are proper.
+```
+General setup --->
+ [*] Enable bpf() system call
+Networking support --->
+ Networking options --->
+ QoS and/or fair queueing --->
+ <M> BPF-based classifier
+ <M> BPF based action
+ [*] enable BPF Just In Time compiler
+```
+Once the .config is saved, the build will proceed and install the resulting
+kernel. This kernel has updated userspace headers (e.g. the bpf() syscall) which
+install into /usr/local/include...proper packaging for this will be
+distro-dependent.
+
+Next, run `bpf-llvm-setup` to pull and compile LLVM with BPF support enabled.
+```
+[root@bpf-demo ~]# bpf-llvm-setup
+Cloning into 'llvm'...
+```
+The resulting libraries will be installed into /opt/local/llvm.
+
+Next, reboot into the new kernel, either manually or by using the kexec helper.
+```
+[root@bpf-demo ~]# kexec-4.1.0-rc1+
+Connection to 192.168.122.247 closed by remote host.
+Connection to 192.168.122.247 closed.
+```
+
+Reconnect and run the final step, building and testing bcc.
+```
+[root@bpf-demo ~]# bcc-setup
+Cloning into 'bcc'...
+...
+Linking CXX shared library libbpfprog.so
+[100%] Built target bpfprog
+...
+Running tests...
+Test project /root/bcc/build
+ Start 1: py_test1
+1/4 Test #1: py_test1 ......................... Passed 0.24 sec
+ Start 2: py_test2
+2/4 Test #2: py_test2 ......................... Passed 0.53 sec
+ Start 3: py_trace1
+3/4 Test #3: py_trace1 ........................ Passed 0.09 sec
+ Start 4: py_trace2
+4/4 Test #4: py_trace2 ........................ Passed 1.06 sec
+
+100% tests passed, 0 tests failed out of 4
+```
+
+
## Release notes
* 0.1
--- /dev/null
+# Minimal Kickstart file
+install
+text
+reboot
+lang en_US.UTF-8
+
+# repo to install the OS
+url --url=<%= @mirror %>/Everything/x86_64/os/
+
+keyboard us
+network --bootproto dhcp
+rootpw <%= @password %>
+authconfig --enableshadow --passalgo=sha512 --enablefingerprint
+firewall --enabled --ssh
+selinux --enforcing
+timezone --utc America/Los_Angeles
+#firstboot --disable
+bootloader --location=mbr --append="console=tty0 console=ttyS0,115200 rd_NO_PLYMOUTH crashkernel=auto"
+zerombr
+clearpart --all --initlabel
+autopart --type=lvm
+repo --name=everything --baseurl=<%= @mirror %>/Everything/x86_64/os/
+
+#Just core packages
+%packages --nobase
+@core
+ntp
+@c-development
+@development-tools
+@rpm-development-tools
+ncurses-devel
+vim
+bc
+kexec-tools
+cmake
+clang
+libmnl-devel
+libstdc++-static
+python-netaddr
+%end
+
+%post --log=/root/anaconda-post.log
+echo Kickstart post
+
+chkconfig NetworkManager off
+chkconfig network on
+
+chkconfig ntpd on
+
+yum -y clean metadata
+yum -y update
+
+hostname <%= @name %>.<%= @domain %>
+echo "<%= @name %>.<%= @domain %>" > /etc/hostname
+
+cat > /usr/local/bin/bpf-kernel-setup <<'DELIM__'
+#!/bin/bash
+set -e -x
+numcpu=$(grep -c ^processor /proc/cpuinfo)
+
+git clone https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
+cd net-next/
+
+cp /boot/config-$(uname -r) ./
+cp ./config-$(uname -r) .config
+
+make -j$numcpu mrproper
+make -j$numcpu nconfig
+make -j$numcpu bzImage
+make -j$numcpu modules
+sudo make modules_install
+sudo make install
+sudo make INSTALL_HDR_PATH=/usr/local headers_install
+
+release=$(<include/config/kernel.release)
+echo "kexec -l /boot/vmlinuz-$release --initrd=/boot/initramfs-$release.img --reuse-cmdline; reboot" > /usr/local/bin/kexec-$release
+chmod +x /usr/local/bin/kexec-$release
+ln -fs kexec-$release /usr/local/bin/kexec-latest
+
+DELIM__
+chmod +x /usr/local/bin/bpf-kernel-setup
+
+cat > /usr/local/bin/bpf-llvm-setup <<'DELIM__'
+#!/bin/bash
+set -e -x
+numcpu=$(grep -c ^processor /proc/cpuinfo)
+
+git clone https://github.com/llvm-mirror/llvm.git
+mkdir llvm/build/
+cd llvm/build/
+
+cmake .. \
+ -DBUILD_SHARED_LIBS=OFF \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DLLVM_ENABLE_TERMINFO=OFF \
+ -DLLVM_TARGETS_TO_BUILD="ARM;CppBackend;X86;BPF" \
+ -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=BPF \
+ -DCMAKE_INSTALL_PREFIX=/opt/local/llvm
+
+make -j$numcpu
+sudo make install
+grep -q llvm $HOME/.bashrc || echo 'PATH=/opt/local/llvm/bin:$PATH' >> $HOME/.bashrc
+
+DELIM__
+chmod +x /usr/local/bin/bpf-llvm-setup
+
+cat > /usr/local/bin/bcc-setup <<'DELIM__'
+#!/bin/bash
+set -e -x
+numcpu=$(grep -c ^processor /proc/cpuinfo)
+
+repo=ssh://git@github.com/plumgrid/bcc.git
+git ls-remote $repo 2>&1 > /dev/null
+if [[ $? -ne 0 ]]; then
+ repo=https://<%= @github_access_token %>@github.com/plumgrid/bcc.git
+fi
+git clone $repo
+mkdir bcc/build/
+cd bcc/build/
+cmake ..
+make -j$numcpu
+make test
+DELIM__
+chmod +x /usr/local/bin/bcc-setup
+
+%end
--- /dev/null
+#!/bin/bash
+
+#set -x
+set -e
+
+function usage() {
+ cat <<DELIM__
+usage: $(basename $0) [options]
+
+Options:
+ -b, --bridge BRNAME Which linux bridge to attach to
+ -c, --cpu NUM Number of CPUs to reserve to the instance (default 4)
+ -g, --github_token X HTTP Github oauth token (for buildbots)
+ -k, --kickstart KS Path to kickstart file to use (required)
+ -m, --mirror URL URL at which to reach netinstallable packages
+ -M, --mem NUM Number of MB to reserve to the instance (default 4094)
+ -n, --name NAME Name of the instance (required)
+ -p, --password PASS Password to set in the VM
+ -s, --size NUM Size in GB to reserve for the virtual HDD (default 40GB)
+DELIM__
+}
+
+TEMP=$(getopt -o b:c:k:m:M:n:p:s: --long bridge:,cpu:,kickstart:,mirror:,mem:,name:,password:size: -- "$@")
+if [[ $? -ne 0 ]]; then
+ usage
+ exit 1
+fi
+
+eval set -- "$TEMP"
+
+while true; do
+ case "$1" in
+ -b|--bridge) BRIDGE="$2"; shift 2 ;;
+ -c|--cpu) CPU="$2"; shift 2 ;;
+ -k|--kickstart) KICKSTART="$2"; shift 2 ;;
+ -n|--name) NAME="$2"; shift 2 ;;
+ -m|--mirror) MIRROR="$2"; shift 2 ;;
+ -M|--mem) MEM="$2"; shift 2 ;;
+ -p|--password) PASSWORD="$2"; shift 2 ;;
+ -s|--size) SIZE="$2"; shift 2 ;;
+ --) shift; break ;;
+ *) usage; exit 1
+ ;;
+ esac
+done
+[[ ! -f "$KICKSTART" ]] && { usage; exit 1; }
+[[ -z "$NAME" ]] && { usage; exit 1; }
+
+PASSWORD=${PASSWORD:-"iovisor"}
+BRIDGE=${BRIDGE:-virbr0}
+MIRROR=${MIRROR:-http://mirror.pnl.gov/fedora/linux/releases/21}
+MEM=${MEM:-4094}
+CPU=${CPU:-4}
+SIZE=${SIZE:-40}
+
+if [[ "$(id -u)" != "0" ]]; then
+ sudo="sudo"
+fi
+
+if ! which virt-install &> /dev/null; then
+ echo "Error: virt-install is not installed"
+ exit 1
+fi
+
+libvirt_dir=/var/lib/libvirt/images
+img_name=$NAME
+tmpdir=$(mktemp -d /tmp/virt-install_XXXXX)
+tmp_ks_file=$tmpdir/$img_name.ks
+
+function cleanup() {
+ set +e
+ read -p "brk: "
+ [[ -d "$tmpdir" ]] && rm -fr "$tmpdir"
+ local destroy_kvm=n
+ [[ -f "/etc/libvirt/qemu/$img_name.xml" ]] && read -p "Destroy libvirt VM (y/n)? " destroy_kvm
+ if [[ "$destroy_kvm" != n* ]]; then
+ virsh destroy $img_name
+ virsh undefine $img_name
+ virsh vol-delete $img_name.img --pool default
+ $sudo rm -f $libvirt_dir/$img_name.img
+ fi
+}
+trap cleanup EXIT
+
+ruby <<DELIM__
+require 'erb'
+@password="$PASSWORD"
+@name="$NAME"
+@domain="example.com"
+@github_access_token="$GITHUB_ACCESS_TOKEN"
+@mirror="$MIRROR"
+File.open('$tmp_ks_file', 'w') do |f|
+ f.puts ERB.new(File.open('$KICKSTART', 'rb').read, nil, '-').result()
+end
+DELIM__
+
+tree=$MIRROR/Server/x86_64/os/
+virt-install --connect=qemu:///system \
+ --network=bridge:$BRIDGE \
+ --initrd-inject=$tmp_ks_file \
+ --controller type=scsi,model=virtio-scsi \
+ --extra-args="ks=file:/$(basename $tmp_ks_file) console=tty0 console=ttyS0,115200" \
+ --name=$img_name \
+ --disk $libvirt_dir/$img_name.img,cache=none,format=qcow2,size=$SIZE,bus=scsi \
+ --ram $MEM \
+ --vcpus=$CPU \
+ --check-cpu \
+ --accelerate \
+ --hvm \
+ --location=$tree \
+ --nographics
+
+echo "SUCCESS"
+exit 0
self.stats = self.prog.table("stats", Key, Leaf)
self.prog.attach_kprobe("sys_write", "sys_wr", 0, -1)
self.prog.attach_kprobe("sys_read", "sys_rd", 0, -1)
- self.prog.attach_kprobe("htab_map_get_next_key", "sys_bpf")
+ self.prog.attach_kprobe("htab_map_get_next_key", "sys_bpf", 0, -1)
def test_trace1(self):
with open("/dev/null", "a") as f:
class Counters(Structure):
_fields_ = [("stat1", c_ulong)]
-tracing = "/sys/kernel/debug/tracing"
class TestTracingEvent(TestCase):
def setUp(self):
self.prog = BPF("trace2", "trace2.b", "kprobe.b",
sudo ip link add $ns.in type veth peer name $ns.out
sudo ip link set $ns.in netns $ns
sudo ip netns exec $ns ip link set $ns.in name eth0
+ sudo ip netns exec $ns tc qdisc add dev eth0 root prio
sudo ip netns exec $ns ip addr add dev eth0 172.16.1.2/24
sudo ip netns exec $ns ip link set eth0 up
sudo ip addr add dev $ns.out 172.16.1.1/24