Skip to content

Week 10 — Kernel Testing Tools

Goal

Learn the tools used to validate kernel changes: kselftest, kunit, static analysis (sparse, smatch, coccinelle), and the fuzzer syzkaller. These tools find real bugs and are expected in patch submissions.

Why This Matters

The netdev maintainers expect that patches have been tested. "I compiled it and it boots" is necessary but not sufficient. Running the networking selftests and static analysis before submitting a patch shows you're serious and saves reviewer time.


kselftest — Kernel Self Tests

The kernel ships with a test suite in tools/testing/selftests/. The networking tests live in tools/testing/selftests/net/.

Running Network Selftests

cd ~/linux

# Build the networking selftests
make -C tools/testing/selftests/net

# Run them (as root, in the guest)
make -C tools/testing/selftests TARGETS=net run_tests

You can also run individual tests:

cd tools/testing/selftests/net
./run_tests.sh          # Run all
./fcnal-test.sh         # Run a specific test script

What to expect: Some tests will pass, some may skip (missing dependencies), some may fail on your config. Skips are fine — focus on passes and unexpected failures.

Running a Subset

Many test scripts accept arguments:

# Run only TCP tests
./fcnal-test.sh -t tcp

# Some tests need specific setup (namespaces, veth pairs)
# Read the test header comments for requirements

Writing a kselftest

If you contribute a networking feature, you're expected to include tests. A basic test:

#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Test: verify that TCP connects work over loopback

source lib.sh  # kselftest helper library

# Setup
setup_ns ns1   # Create a network namespace

# Test
ip netns exec $ns1 bash -c '
    # Start a listener
    nc -l 12345 &
    sleep 0.5
    echo "hello" | nc localhost 12345
    wait
' && echo "PASS" || echo "FAIL"

# Cleanup
cleanup_ns $ns1

kunit — Unit Testing Framework

kunit is for testing small, isolated pieces of kernel code. It runs in-kernel (or in a UML build for fast iteration).

Running kunit

cd ~/linux

# Run all kunit tests using User Mode Linux (fast, no QEMU needed)
./tools/testing/kunit/kunit.py run

# Run only networking-related tests
./tools/testing/kunit/kunit.py run --kunitconfig=net/core/.kunitconfig

Expect: Output like:

[PASSED] net_test_example
[PASSED] skb_test_basic
...
Testing complete. Passed: 42, Failed: 0, Skipped: 3

Writing a kunit Test

// SPDX-License-Identifier: GPL-2.0
#include <kunit/test.h>
#include <linux/skbuff.h>

static void skb_alloc_test(struct kunit *test)
{
    struct sk_buff *skb;

    skb = alloc_skb(1024, GFP_KERNEL);
    KUNIT_ASSERT_NOT_NULL(test, skb);
    KUNIT_EXPECT_EQ(test, skb->len, 0);

    skb_put(skb, 100);
    KUNIT_EXPECT_EQ(test, skb->len, 100);

    kfree_skb(skb);
}

static struct kunit_case my_test_cases[] = {
    KUNIT_CASE(skb_alloc_test),
    {}
};

static struct kunit_suite my_test_suite = {
    .name = "my_net_tests",
    .test_cases = my_test_cases,
};

kunit_test_suite(my_test_suite);
MODULE_LICENSE("GPL");

Static Analysis

sparse — Kernel Semantic Checker

sparse checks for common C mistakes, especially around address spaces (user vs kernel pointers), locking, and endianness.

# Install
sudo apt install -y sparse

# Run during build
make C=1 net/ipv4/tcp.o        # Check a single file
make C=1 M=net/ipv4/           # Check a directory
make C=2 net/ipv4/tcp.o        # Force recheck even if .o is up to date

Common sparse warnings you'll see:

warning: incorrect type in assignment (different address spaces)
warning: symbol 'xxx' was not declared. Should it be static?
warning: context imbalance - unexpected unlock

smatch — Advanced Static Analyzer

smatch finds deeper bugs: null pointer dereferences, buffer overflows, logic errors.

# Install
cd ~
git clone https://github.com/error27/smatch.git
cd smatch
make
sudo make install

# Run
cd ~/linux
make CHECK="smatch -p=kernel" C=1 net/ipv4/tcp.o

Coccinelle — Semantic Patching

Coccinelle is a tool for finding and transforming C code patterns. The kernel ships with coccinelle scripts (semantic patches) that find common issues:

# Install
sudo apt install -y coccinelle

# Run all kernel coccinelle checks
make coccicheck MODE=report

# Run on a specific directory
make coccicheck MODE=report M=net/ipv4/

Why this matters for contributors: Coccinelle is often used for tree-wide cleanup patches. A common first contribution is running a coccinelle script, finding issues, and sending fixes.

checkpatch.pl — Style and Convention Checker

You already saw this in Week 7. Run it on every patch before sending:

# Check a patch file
./scripts/checkpatch.pl 0001-my-change.patch

# Check a file directly
./scripts/checkpatch.pl --file net/ipv4/tcp.c

# Check your staged changes
git diff --cached | ./scripts/checkpatch.pl --stdin

Treat checkpatch errors as blockers. Warnings are worth fixing too — reviewers will ask about them.

syzkaller — Kernel Fuzzer (Overview)

syzkaller is Google's kernel fuzzer. It automatically generates sequences of system calls and looks for crashes, hangs, and memory bugs. It has found thousands of networking bugs.

You won't run syzkaller this week — it requires significant setup (multiple VMs, a corpus, etc.). But you should know it exists because:

  1. It generates bug reports on https://syzkaller.appspot.com/
  2. These reports contain reproducers you can use to find and fix bugs
  3. Fixing syzkaller bugs is a legitimate contribution path
# Browse open networking bugs:
# https://syzkaller.appspot.com/upstream
# Filter by "net" subsystem

A syzkaller report typically includes: - A C reproducer program - The crash log - The guilty commit (if identified) - A stack trace

You can run the reproducer in your QEMU setup to reproduce the bug, then work on a fix.

Putting It All Together: Pre-Submission Checklist

Before sending any patch, run:

# 1. Build cleanly
make -j$(nproc)

# 2. Static analysis
make C=1 net/ipv4/your_changed_file.o

# 3. checkpatch
./scripts/checkpatch.pl your-patch.patch

# 4. Boot test in QEMU
# Boot, verify basic networking works

# 5. Run relevant selftests
make -C tools/testing/selftests TARGETS=net run_tests

# 6. If applicable, run kunit
./tools/testing/kunit/kunit.py run

Exercises

  1. Build and run the networking selftests in your QEMU guest. Note which pass, skip, and fail. Investigate one failure.
  2. Run make C=1 net/ipv4/tcp.o and make C=1 net/ipv4/tcp_input.o. Are there any sparse warnings? (In mainline, there usually aren't — the code is well-maintained.)
  3. Run make coccicheck MODE=report M=net/ (this takes a while). Read a few of the results. Do any look like real bugs?
  4. Go to https://syzkaller.appspot.com/upstream and find a networking bug report with a C reproducer. Download the reproducer and try to understand what it does.
  5. Run kunit with ./tools/testing/kunit/kunit.py run. How many tests pass? Explore net/core/.kunitconfig to see what's being tested.

What's Next

Next week: the git workflow and patch submission process. You'll learn git format-patch, git send-email, b4, and the netdev-specific conventions.