Updated README, example virt-install script
authorBrenden Blanco <bblanco@plumgrid.com>
Sun, 3 May 2015 17:43:07 +0000 (10:43 -0700)
committerBrenden Blanco <bblanco@plumgrid.com>
Sun, 3 May 2015 17:44:01 +0000 (10:44 -0700)
* Add Getting Started section in README.md
* Add a virt-install script which creates a BPF-capable Fedora 21 VM
* Fix a test that was failing on F21

Signed-off-by: Brenden Blanco <bblanco@plumgrid.com>
.gitignore
CMakeLists.txt
README.md
scripts/bpf_demo.ks.erb [new file with mode: 0644]
scripts/build_bpf_demo.sh [new file with mode: 0755]
tests/jit/trace1.py
tests/jit/trace2.py
tests/wrapper.sh.in

index 3819313..d2d414b 100644 (file)
@@ -1,2 +1,3 @@
 *.swp
 *.swo
+*.pyc
index 2bb6369..7fe3146 100644 (file)
@@ -20,8 +20,8 @@ endif()
 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")
index 3e11869..166b84d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -10,11 +10,11 @@ features which are mostly available in Linux 4.1 and above.
 ## 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
@@ -24,7 +24,7 @@ programs while still harnessing its full flexibility.
 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
@@ -45,9 +45,80 @@ To get started using this toolchain, one needs:
   * 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
diff --git a/scripts/bpf_demo.ks.erb b/scripts/bpf_demo.ks.erb
new file mode 100644 (file)
index 0000000..fc49dc7
--- /dev/null
@@ -0,0 +1,126 @@
+# 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
diff --git a/scripts/build_bpf_demo.sh b/scripts/build_bpf_demo.sh
new file mode 100755 (executable)
index 0000000..86173bb
--- /dev/null
@@ -0,0 +1,114 @@
+#!/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
index 6d6dcc2..b6bb367 100755 (executable)
@@ -22,7 +22,7 @@ class TestKprobe(TestCase):
         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:
index 014a5ec..d83f6d6 100755 (executable)
@@ -10,7 +10,6 @@ class Ptr(Structure):
 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",
index 38f9cb6..16baf4b 100755 (executable)
@@ -25,6 +25,7 @@ function ns_run() {
   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