Wednesday, April 04, 2007

kernel + PF_RING rpm

This is an update to my original post regarding PF_RING and how to build it. In this post, I'll be walking through just the steps of building the PF_RING kernel patch, and then building kernel RPMS with the added patch. This will simplify the process if you wish to use PF_RING on many sensors. Obviously, compiling on every machine is a waste of time and really not scalable. This post will duplicate some of the information from the original.




My work is on RedHat Enterprise 4, so if you are using a different distro, your mileage may vary, however, it shouldn't be drastically different.

UPDATE: Here's a Debian Sarge oriented howto:
http://bjou.homeunix.net/blog/2006/12/advanced-packet-capturing-howto-pf_ring-napi-and-extended-libpcap-on-debian-sarge/

There are 2 Fedora Core (4 and 5) instruction pages at:

http://wiki.ntop.org/mediawiki/index.php/Installing_PF_RING_and_nProbe_on_Fedora_Core_4_%28FC4%29

and

http://wiki.ntop.org/mediawiki/index.php/Installing_on_Fedora_Core_5_%28FC5%29

that these are based upon, and (hopefully) expand upon. Thanks to the authors of those.

Before beginning, make sure that your system is fully up to date with patches. These instructions presume that you have at least 2+ GBs of free disk space, primarily in /usr/src.

1. Software packages needed (in addition to a minimal install on RHEL):

glibc-kernheaders
autoconf
automake
bison
flex
cvs
gcc
gcc-c++
libtool
tcl (note this version is compiled without threading, so good for Sguil)
tcl-devel
tclx
rpm-build
redhat-rpm-config
openssl-devel
pcre-devel
ncurses-devel

On a registered RHEL, you'd run the command:

up2date -f install [package_name]

to download package_name and required dependencies, and install them.

* Note: not all of these are necessary for just PF_RING, however, are needed for other things like Snort, Sguil, barnyard, www.metre.net/sancp.html">SANCP, etc.

2. Remove software:

At a bare minimum, the following software packages need to be removed:
libpcap
ppp *
rp-pppoe *
wvdial *

The command to do this is:

rpm -e

* relies on libpcap. If needed, will need to be recompiled with the new libpcap that we'll compile and install later.

3. Install the kernel src.rpm of the latest kernel (on RHEL, kernel-2.6.9-42.0.10.EL.src.rpm at the time of this writing).

For RHEL 4, the file will be located ftp.redhat.com. For example, to get the latest kernel for RHEL as of today, you'd run the command:

wget ftp://ftp.redhat.com:/pub/redhat/linux/updates/enterprise/4XX/en/os/SRPMS/kernel-2.6.9-42.0.10.EL.src.rpm

where XX is the type of RHEL 4 you're running: Desktop (uhh, desktop), WS (workstation), ES (enterprise server), or AS (advanced server). If you don't know, run the command:

[root@hostname ~]# cat /etc/redhat-release
Red Hat Enterprise Linux WS release 4 (Nahant Update 4)

In this case, this machine was a workstation, so use WS.

Now install the kernel with the command:

rpm -ivh kernel-2.6.9-42.0.10.EL.src.rpm

This will place the vanilla 2.6.9 kernel src, RedHat's patches, spec file, etc. into /usr/src/redhat/{SOURCES,SPECS}.

4. Prep the kernel for the PF_RING patches.

Now we need to prep the kernel. First, change to the appropiate directory:

cd /usr/src/redhat/SPECS

Then run the command:

rpmbuild -bp --target $(arch) kernel-2.6.spec

If this works, you should see something similar to the following:

Building target platforms: i686
Building for target i686
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.7797
+ umask 022
+ cd /usr/src/redhat/BUILD
+ LANG=C
+ export LANG
+ unset DISPLAY
+ cd /usr/src/redhat/BUILD
+ rm -rf kernel-2.6.9
+ /bin/mkdir -p kernel-2.6.9
+ cd kernel-2.6.9
+ /usr/bin/bzip2 -dc /usr/src/redhat/SOURCES/linux-2.6.9.tar.bz2
+ tar -xf -
+ STATUS=0
+ '[' 0 -ne 0 ']'
++ /usr/bin/id -u
+ '[' 0 = 0 ']'
+ /bin/chown -Rhf root .
++ /usr/bin/id -u
+ '[' 0 = 0 ']'
+ /bin/chgrp -Rhf root .
+ /bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ cd linux-2.6.9
+ echo 'Patch #3 (patch-2.6.9-ac11.bz2):'
Patch #3 (patch-2.6.9-ac11.bz2):
+ /usr/bin/bzip2 -d
+ patch -p1 -s
[snip]
removed `./net/xfrm/xfrm_state.c.orig'
removed `./net/socket.c.orig'
removed `./net/netlink/af_netlink.c.orig'
removed `./net/ipv6/ip6_output.c.orig'
removed `./net/ipv6/addrconf.c.orig'
removed `./net/ipv6/netfilter/ip6_tables.c.orig'
removed `./net/bluetooth/af_bluetooth.c.orig'
removed `./net/8021q/vlan.c.orig'
removed `./net/sched/sch_api.c.orig'
+ find . -name '*~' -exec rm -fv '{}' ';'
+ exit 0

This applies all of the various patches (nearly 1000) to the vanilla kernel tree that RedHat applies to it's kernels.

Now we need to create a symlink to that patched kernel source to /usr/src with the command:

ln -s /usr/src/redhat/BUILD/kernel-2.6.X/linux-2.6.X /usr/src/linux

where X is the subversion. In this case, for RHEL 4, X = 9.

5. Download and build the PF_RING patch for your kernel.

Now we need to get the PF_RING patches downloaded and built for our kernel. PF_RING is currently only available via CVS. To do this, run the following:

cd /usr/src
CVSROOT=:pserver:anonymous@cvs.ntop.org:/export/home/ntop;export CVSROOT
mkdir pf_ring && cd pf_ring
cvs login

which should produce the following output:

Logging in to :pserver:anonymous@cvs.ntop.org:2401/export/home/ntop
CVS password:

At the prompt, type "ntop" (no quotes), and hit Enter. (Note: ntop will not appear on the screen.) Next type the following:

cvs checkout PF_RING

which, if it works, should produce something simliar to the following:

cvs checkout: Updating PF_RING
U PF_RING/README
U PF_RING/mkpatch.sh
cvs checkout: Updating PF_RING/kernel
U PF_RING/kernel/README
cvs checkout: Updating PF_RING/kernel/include
cvs checkout: Updating PF_RING/kernel/include/linux
U PF_RING/kernel/include/linux/ring.h
cvs checkout: Updating PF_RING/kernel/include/net
U PF_RING/kernel/include/net/PATCH-to-sock.h
cvs checkout: Updating PF_RING/kernel/net
U PF_RING/kernel/net/PATCH-to-Config.in
U PF_RING/kernel/net/PATCH-to-netsyms.c
cvs checkout: Updating PF_RING/kernel/net/core
U PF_RING/kernel/net/core/PATCH-1-to-dev.c
U PF_RING/kernel/net/core/PATCH-2-to-dev.c
U PF_RING/kernel/net/core/PATCH-3-to-dev.c
cvs checkout: Updating PF_RING/kernel/net/ring
U PF_RING/kernel/net/ring/Config.in
U PF_RING/kernel/net/ring/Kconfig
U PF_RING/kernel/net/ring/Makefile
U PF_RING/kernel/net/ring/Makefile-2.4.X
U PF_RING/kernel/net/ring/Makefile-2.6.X
U PF_RING/kernel/net/ring/ring_packet.c
cvs checkout: Updating PF_RING/userland
cvs checkout: Updating PF_RING/userland/libpcap-0.9.4-ring
U PF_RING/userland/libpcap-0.9.4-ring/README
U PF_RING/userland/libpcap-0.9.4-ring/pcap-int.h
U PF_RING/userland/libpcap-0.9.4-ring/pcap-linux.c
cvs checkout: Updating PF_RING/userland/libpfring
U PF_RING/userland/libpfring/Makefile
U PF_RING/userland/libpfring/pfcount.c
U PF_RING/userland/libpfring/pfring.c
U PF_RING/userland/libpfring/pfring.h
cvs checkout: Updating PF_RING/userland/pcount
U PF_RING/userland/pcount/Makefile
U PF_RING/userland/pcount/pcount.c

The current version of PF_RING comes with a script that creates a patch specific to your kernel. Now we'll get things in order to run that script with the following commands:

cd /usr/src/pf_ring/PF_RING

mkdir workspace
cd workspace
cd /usr/src/redhat/BUILD
/kernel-2.6.X/linux-2.6.X
tar -czf
/usr/src/pf_ring/PF_RING/linux-2.6.X.tar.gz linux-2.6.X
cd /usr/src/pf_ring/PF_RING

where X = 9 for RHEL4 (broken record).

Now edit the file mkpatch.sh, and adjust the following variables to match your environment:

SUBLEVEL=${SUBLEVEL:-18.1}

EXTRAVERSION=${EXTRAVERSION:--i686-smp-$PATCH}


For example, on RHEL 4, you'd change to the variables to:

SUBLEVEL=${SUBLEVEL:-9}

EXTRAVERSION=${EXTRAVERSION:--42.0.10.ELsmp-$PATCH}


Save your changes, and run the script:

sh ./mkpatch.sh

If all goes well, the output should look similar to the following:

Creating patch for Linux kernel linux-2.6.9 ...
Edit this file (mkpatch.sh) for a different kernel version
Kernel build area is /usr/src/pf_ring/PF_RING/workspace
rm: cannot remove `/usr/src/pf_ring/PF_RING/workspace/ring3': No such file or directory
Creating link to /usr/src/pf_ring/PF_RING in /usr/src/pf_ring/PF_RING/workspace called ring3
Found linux-2.6.9.tar.gz in source directory /usr/src/pf_ring/PF_RING/workspace
Untarring Linux sources (read-only tree) in /usr/src/pf_ring/PF_RING/workspace/linux-2.6.9
Cloning Linux sources (read-write tree) in /usr/src/pf_ring/PF_RING/workspace
Patching Linux sources ...
1. Install additional file include/linux/ring.h with definitions
for packet ring.
done
2. Install the ring sources under the kernel tree.
Installing kernel ring sources in
linux-2.6.9-42.0.3.ELsmp-ring3/net/ring ... done
3. Patch net/core/dev.c ...
Patch #1 (define ring_handler)
Patch #2 (modify function netif_rx and netif_receive_skb)
Patch #3 (modify dev_queue_xmit, found in PATCH-3-to-dev.c)
... done
4. Patching file net/Makefile ... done
5. Copy net/ring/Kconfig to linux-2.6.9-42.0.3.ELsmp-ring3/net/ring/Kconfig done
6. Patching file net/Kconfig ... done
diff --unified --recursive --new-file linux-2.6.9 linux-2.6.9-42.0.3.ELsmp-ring3 > linux-2.6.9-42.0.3.ELsmp-ring3.patch
Making Linux patch file. This could take some time, please wait ... done
Your patch file is now in /usr/src/pf_ring/PF_RING/workspace/linux-2.6.9-42.0.3.ELsmp-ring3.patch.gz

6. Apply the patch and build the kernel.

To setup the patch to be applied during the kernel RPM build, do the following:

gunzip
/usr/src/pf_ring/PF_RING/workspace/linux-2.6.*patch.gz
cp /usr/src/pf_ring/PF_RING/workspace/linux-2.6.*patch /usr/src/redhat/SOURCES
cd /usr/src/redhat/SPECS

In the /usr/src/redhat/SPECS directory, there should be a kernel-2.6.spec file, apply the following patch to that file (adjust as you desire, but this works for me):


--- kernel-2.6.spec 2007-04-04 23:42:58.000000000 +0100
+++ kernel-2.6.spec.new 2007-04-04 18:18:37.000000000 +0100
@@ -22,7 +22,7 @@
# that the kernel isn't the stock distribution kernel, for example by
# adding some text to the end of the version number.
#
-%define release 42.0.10.EL
+%define release 42.0.10.EL.ring3
%define sublevel 9
%define kversion 2.6.%{sublevel}
%define rpmversion 2.6.%{sublevel}
@@ -699,6 +699,7 @@
Patch1333: linux-2.6.9-net-sctp-shutdown.patch
Patch1334: linux-2.6.9-net-sctp-receive-buffer.patch
Patch1335: linux-2.6.9-net-sctp.patch
+Patch1336: linux-2.6.9-42.0.10.ELsmp-ring3.patch

# NIC driver updates
Patch1350: linux-2.6.9-net-b44-4g4g.patch
@@ -2376,6 +2377,8 @@
%patch1334 -p1
# various sctp fixes
%patch1335 -p1
+# ring3
+%patch1336 -p1

# NIC driver fixes.
# Fix problems with b44 & 4g/4g



Exit and save the spec file. Change the directory:

cd /usr/src/redhat/SOURCES

and edit the following files:

kernel-2.6.9-i686.config
kernel-2.6.9-i686-hugemem.config
kernel-2.6.9-i686-smp.config

to include the following:

CONFIG_RING=m

similar to the following:

CONFIG_UNIX=y
CONFIG_NET_KEY=m
CONFIG_RING=m
CONFIG_INET=y
CONFIG_INET_TUNNEL=m

Run the following to compile the kernel, and build the RPMs:

rpmbuild -ba --target i686 /usr/src/redhat/SPECS/kernel-2.6.spec

If all goes well, you'll have RPMs in /usr/src/redhat/RPMS/i686 similar to:

kernel-2.6.9-42.0.10.EL.ring3.i686.rpm
kernel-debuginfo-2.6.9-42.0.10.EL.ring3.i686.rpm
kernel-devel-2.6.9-42.0.10.EL.ring3.i686.rpm
kernel-hugemem-2.6.9-42.0.10.EL.ring3.i686.rpm
kernel-hugemem-devel-2.6.9-42.0.10.EL.ring3.i686.rpm
kernel-smp-2.6.9-42.0.10.EL.ring3.i686.rpm
kernel-smp-devel-2.6.9-42.0.10.EL.ring3.i686.rpm

Install these RPMs as per usual, and reboot.

Enjoy.