Skip to content

KarpelesLab/pktkit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pktkit

Go Reference Test Coverage Status Go Report Card

Zero-copy L2/L3 packet handling library for Go.

pktkit provides primitives for building virtual network topologies: devices, hubs, adapters, and tunnels that move Ethernet frames and IP packets without copying buffers on the hot path.

Features

Core

  • Zero-copy types: Frame and Packet are []byte aliases with typed header accessors — no wrapper allocation
  • Callback-based forwarding: synchronous func(T) error handler callbacks matching Send signatures, no channels
  • L2Device / L3Device interfaces: uniform API for all network devices
  • IPv4 and IPv6 support throughout the stack

Connectivity

  • L2Hub: MAC-learning switch with 5-minute aging — forwards unicast to learned ports, floods unknown/broadcast/multicast
  • L3Hub: routing hub with prefix-based unicast forwarding and broadcast/multicast delivery
  • ConnectL2 / ConnectL3: point-to-point wiring helpers (a.SetHandler(b.Send))
  • L2Connector / L3Connector: lifecycle-managed device attachment with cleanup callbacks
  • Serve: accept loop connecting incoming L2Devices to a connector, with automatic cleanup on disconnect

Bridging

  • L2Adapter: bridges an L3 device onto an L2 network with ARP (IPv4), NDP (IPv6), DHCP client, and gateway routing. Random MAC generated by default.
  • DHCPServer: L2 device serving DHCP leases with configurable IP pool, router, DNS, and lease time. Handles DISCOVER, OFFER, REQUEST, ACK, RELEASE, DECLINE, and INFORM.

Subpackages

  • slirp: userspace NAT stack implementing L3Device — routes virtual traffic to the real network via net.Dial, with namespace-isolated connection tracking for multi-tenant use (ConnectL3). Supports IPv4/IPv6 TCP, UDP, and ICMPv6.
  • vclient: virtual network client implementing L3Device — provides Dial, Listen, net.Conn, DNS resolution, and http.Client
  • vtcp: pure RFC-compliant TCP protocol engine (congestion control, SACK, timestamps, window scaling, SYN cookies)
  • nat: packet-level IPv4 NAT between two virtual L3 networks with ALGs (FTP, SIP, H.323, PPTP, TFTP, IRC), NAT64, defragmentation, namespace isolation, and UPnP
  • wg: WireGuard tunnel implementation with Noise IK handshake, per-peer L3 isolation, and adapter bridging peers to pktkit networks
  • ovpn: OpenVPN server with TLS key exchange, AES-CBC/GCM encryption, per-peer L3/L2 isolation, and username/password authentication
  • tuntap: OS-level TUN/TAP devices with IP address and route configuration (Linux and macOS)
  • qemu: QEMU userspace network socket protocol (both client and server/listener)

Usage

Point-to-point L3

import "github.com/KarpelesLab/pktkit"

tun1 := pktkit.NewPipeL3(netip.MustParsePrefix("10.0.0.1/24"))
tun2 := pktkit.NewPipeL3(netip.MustParsePrefix("10.0.0.2/24"))
pktkit.ConnectL3(tun1, tun2)

Virtual LAN with DHCP and NAT

hub := pktkit.NewL2Hub()

// DHCP server
dhcpSrv := pktkit.NewDHCPServer(pktkit.DHCPServerConfig{
    ServerIP:   netip.MustParseAddr("192.168.0.1"),
    SubnetMask: net.CIDRMask(24, 32),
    RangeStart: netip.MustParseAddr("192.168.0.10"),
    RangeEnd:   netip.MustParseAddr("192.168.0.100"),
    Router:     netip.MustParseAddr("192.168.0.1"),
    DNS:        []netip.Addr{netip.MustParseAddr("1.1.1.1")},
})
hub.Connect(dhcpSrv)

// NAT gateway (slirp routes to real internet)
stack := slirp.New()
stack.SetAddr(netip.MustParsePrefix("192.168.0.1/24"))
hub.Connect(pktkit.NewL2Adapter(stack, nil))

// Virtual client — gets IP via DHCP, can dial out
client := vclient.New()
adapter := pktkit.NewL2Adapter(client, nil)
hub.Connect(adapter)
adapter.StartDHCP()

// Use standard Go HTTP client over the virtual network
resp, _ := client.HTTPClient().Get("https://example.com")

WireGuard server with per-peer isolation

Each WireGuard peer gets a namespace-isolated NAT connection on a single slirp stack. Peers can share the same IP address without conflict.

stack := slirp.New()
stack.SetAddr(netip.MustParsePrefix("10.0.0.1/24"))

adapter, _ := wg.NewAdapter(wg.AdapterConfig{
    Connector: stack, // each peer gets isolated NAT via ConnectL3
})

udp, _ := net.ListenPacket("udp4", ":51820")
go adapter.Serve(udp)

// Add authorized peers
adapter.AddPeer(clientPublicKey)

QEMU VM networking

Connect QEMU VMs via the socket protocol. Each accepted connection can join a shared hub or get an isolated namespace.

ln, _ := qemu.Listen("unix", "/tmp/qemu.sock")

hub := pktkit.NewL2Hub()
// hub.Connect(pktkit.NewL2Adapter(stack, nil)) // add a NAT gateway

pktkit.Serve(ln, hub) // accept loop: each VM joins the hub

Performance

All data-plane hot paths are zero-allocation. Benchmarks on an i9-14900K (32 threads):

Core

Path ns/op Throughput Allocs
Frame accessors 0.63 2.4 TB/s 0
Packet IPv4 accessors 0.92 1.6 TB/s 0
Packet IPv6 accessors 0.67 2.2 TB/s 0
L2Hub unicast forward 50 30 GB/s 0
L2Hub forward (parallel) 2.3 656 GB/s 0
L3Hub route 9.2 163 GB/s 0
L2Adapter incoming (frame to packet) 33 46 GB/s 0
L2Adapter outgoing (packet to frame, pooled) 61 24 GB/s 0
Checksum (1500 B) 273 5.5 GB/s 0
SendBuf PeekUnsent 0.24 6.1 TB/s 0
ARP/NDP table lookup 37 - 0

NAT (1440 B payload)

Path ns/op Throughput Allocs
NAT outbound TCP 40 36 GB/s 0
NAT inbound TCP 41 35 GB/s 0
NAT outbound UDP 34 3.7 GB/s 0
NAT mapping lookup 12 - 0
Defrag (non-fragment fast path) 1.4 1.0 TB/s 0

WireGuard (1420 B payload)

Path ns/op Throughput Allocs
Encrypt (EncryptTo, zero-alloc) 555 2.6 GB/s 0
Encrypt + Decrypt (zero-alloc) 1131 1.3 GB/s 0
Encrypt (Encrypt, allocating) 2417 588 MB/s 1
Decrypt (ProcessPacket) 4135 343 MB/s 1
Handshake (full initiation + response) 578k - 481
Key generation 57 - 0
Replay filter 9.1 - 0
Peer lookup 13 - 0

OpenVPN GCM (1420 B payload)

Path ns/op Throughput Allocs
GCM encrypt 227 6.3 GB/s 1
GCM decrypt 202 7.0 GB/s 0
CBC encrypt 8307 171 MB/s 15
Replay window 9.2 - 0
PRF 1.2 (256 B) 3497 73 MB/s 25
Options parse 721 - 4

End-to-end VPN over UDP loopback (1400 B payload)

Both benchmarks use real UDP sockets on 127.0.0.1. Throughput is measured with a saturated pipeline (sender blasts, receiver counts); latency is per-packet synchronous send-wait.

Metric WireGuard (ChaCha20-Poly1305) OpenVPN (AES-256-GCM)
Throughput 299 MB/s (2.4 Gbps) 678 MB/s (5.4 Gbps)
Latency 23.9 us 20.0 us

OpenVPN GCM is faster end-to-end on x86 because AES-GCM uses AES-NI hardware acceleration, while ChaCha20-Poly1305 is a software cipher. On platforms without AES-NI (e.g. ARM without crypto extensions), WireGuard's ChaCha20 is typically faster.

Run benchmarks with go test -bench=. -benchmem ./....

License

MIT — see LICENSE.

About

Zero-copy L2/L3 packet handling library for Go — virtual switches, NAT, DHCP, ARP, NDP, and protocol ALGs

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages