Getting Started
Community Guidelines
- Be respectful
- Don't be a dick
- Be a part of the solution, not the problem
Prerequisites
- Go 1.24+
- Protocol Buffers compiler (
protobuf-compiler) - golangci-lint
- Docker & Docker Compose (for local testing)
Prefer a sandboxed VM?
If you'd rather not install Go, VPP, FRR, or Docker on your host directly, see Development VM (QEMU/KVM) — make dev-vm provisions a Debian 12 VM with the full toolchain pre-installed.
Clone and Build
git clone https://github.com/veesix-networks/osvbng.git
cd osvbng
make build
This produces bin/osvbngd and bin/osvbngcli.
Running Locally
make build
cd docker/dev
./dev.sh start
This builds the Docker image, creates the network topology, and starts osvbng.
Development VM (QEMU/KVM)
For QEMU image work, dataplane changes, or to keep your host clean of VPP/FRR/kernel-module tweaks, make dev-vm provisions a Debian 12 VM via libvirt with the full toolchain (Go, VPP, FRR, Docker, containerlab, packer) pre-installed and your SSH key authorised. The Docker smoke test in docker/dev/ runs unchanged inside the VM.
Host prerequisites (Debian / Ubuntu / Pop!_OS)
sudo apt install -y \
virtinst \
libvirt-daemon-system \
cloud-image-utils \
qemu-utils \
whiptail \
rsync
sudo usermod -aG libvirt $USER
newgrp libvirt # or log out and back in
You also need an SSH public key in ~/.ssh/. If you don't have one: ssh-keygen.
Don't run make dev-vm with sudo
The script issues its own sudo calls where needed and resolves your SSH key via $HOME. Running the whole thing with sudo makes it search /root/.ssh/ and fail with No SSH public keys found.
Create the VM
make dev-vm
Downloads the Debian 12 cloud image (~400 MB, cached), creates a 30 GB qcow2 disk, defines a 6 GB / 4 vCPU domain named osvbng-dev, then SSHes in and runs the provisioner. First run takes ~10 minutes; subsequent recreates are faster. Override defaults via env: VM_MEMORY=8192 make dev-vm.
Sync your code
make dev-vm-sync
Rsyncs the working tree into /home/dev/osvbng/ in the VM (excludes .git/, bin/, output/, *.qcow2).
Reprovision after versions.env changes
make dev-vm-provision
Re-runs the provisioner with the current versions.env so VPP / FRR / Go versions match the project pin.
Connecting to the VM
The VM gets a libvirt-DHCP lease on the default network (typically 192.168.122.0/24); the IP can change on recreate. Look it up:
virsh -c qemu:///system domifaddr osvbng-dev | awk '/ipv4/ {split($4,a,"/"); print a[1]}'
Add a host alias once and update the IP after each recreate:
# ~/.ssh/config
Host osvbng-dev
HostName 192.168.122.X
User dev
StrictHostKeyChecking accept-new
UserKnownHostsFile /dev/null
LogLevel ERROR
Then: ssh osvbng-dev.
Reaching osvbng services from your host browser
When you run the in-VM Docker smoke test (docker/dev/dev.sh start), osvbng listens on a Docker bridge inside the VM (172.30.0.2:8080/9090/50050), so it isn't directly reachable from the host. Forward the ports over SSH:
ssh -L 8080:172.30.0.2:8080 \
-L 9090:172.30.0.2:9090 \
-L 50050:172.30.0.2:50050 \
osvbng-dev
Leave that session open and open http://localhost:8080/api/docs on the host. Grafana is already published to the VM's eth0:3000, so it's reachable directly at http://<vm-ip>:3000 (admin/admin).
VM lifecycle
virsh start osvbng-dev
virsh shutdown osvbng-dev
virsh destroy osvbng-dev # force stop
virsh undefine osvbng-dev --remove-all-storage # delete entirely
Development
Branch Naming
Use prefixed branch names:
| Prefix | Purpose |
|---|---|
feat/ |
New features |
fix/ |
Bug fixes |
perf/ |
Performance improvements |
ci/ |
CI/CD changes |
refactor/ |
Code restructuring |
docs/ |
Documentation |
test/ |
Test changes |
Code Style
Before submitting
Always run linting before opening a PR.
make lint # check for issues
make fmt # auto-fix formatting
Running Tests
make test # run unit tests
make test-report # run tests with JUnit XML report in build/reports/
Unit tests (make test) validate individual packages in isolation - parsers, allocators, config handling, protocol logic. They run fast, require no infrastructure, and are the first gate in CI.
Integration tests (tests/) use containerlab and robot framework to spin up a full osvbng instance with BNGBlaster subscribers, verifying end-to-end functionality across all supported features. They require Docker and take longer to run.
CI runs unit tests first. Integration tests will not run until unit tests pass. Both must pass before a PR can be merged.
Future: Hardware and QEMU testing
We plan to build physical and QEMU-based test infrastructure for throughput and subscriber scaling validation on minor and major releases.
Profiling
For performance work, set OSVBNG_PROFILE=1 in the container environment to enable pprof endpoints and runtime profiling (block rate + mutex fraction):
# CPU profile (capture during load test)
curl -o cpu.prof http://<bng-ip>:8080/debug/pprof/profile?seconds=30
# Block profile (where goroutines are blocked - mutexes, channels, syscalls)
curl -o block.prof http://<bng-ip>:8080/debug/pprof/block
# Mutex contention (which mutexes are contended and for how long)
curl -o mutex.prof http://<bng-ip>:8080/debug/pprof/mutex
# Goroutine dump (what all goroutines are doing right now)
curl -o goroutine.txt "http://<bng-ip>:8080/debug/pprof/goroutine?debug=2"
# Execution trace (goroutine scheduling, blocking, syscalls over time)
curl -o trace.out "http://<bng-ip>:8080/debug/pprof/trace?seconds=5"
Analyze with:
go tool pprof -top cpu.prof # CPU hot functions
go tool pprof -top -cum block.prof # where goroutines spend time blocked
go tool pprof -top -cum mutex.prof # mutex contention ranking
go tool trace trace.out # visual goroutine timeline
New Features
Before you start coding
Open an issue first to discuss your idea with the core developers. This helps ensure your contribution aligns with the project direction and avoids wasted effort.
Submitting Changes
- Fork the repo
- Create a branch (
git checkout -b <type>/my-change) - Make your changes
- Run
make lintandmake test - Commit using Conventional Commits format and push
- Open a PR against
main- the PR title must follow Conventional Commits format (PRs are squash-merged)
Documentation
Any contribution that adds, modifies, or removes behaviour must include corresponding documentation updates.
Questions?
Join the Discord, open a discussion, or file an issue.