OmniUPF Configuration Guide
Table of Contents
- Overview
- Operating Modes
- XDP Attachment Modes
- Configuration Parameters
- Configuration File
- Hypervisor Compatibility
- NIC Compatibility
- Configuration Examples
- Map Sizing and Capacity Planning
Overview
OmniUPF is a versatile user plane function that can operate in multiple modes to support both 4G (EPC) and 5G core networks. The control plane is implemented in Elixir/OTP, and configuration is managed through an Elixir configuration file (runtime.exs).
On package install, the configuration file is placed at /etc/omniupf/runtime.exs and preserved across upgrades. The UPF must be restarted after configuration changes.
Operating Modes
OmniUPF is a unified platform that can simultaneously operate as:
Mode Configuration
The operating mode is determined by the control plane (SMF, PGW-C, or SGW-C) that establishes PFCP associations with OmniUPF. No specific OmniUPF configuration is required to switch between modes.
Simultaneous Operation:
- OmniUPF can accept PFCP associations from multiple control planes concurrently
- A single OmniUPF instance can act as UPF, PGW-U, and SGW-U at the same time
- Sessions from different control planes are isolated and managed independently
XDP Attachment Modes
OmniUPF uses XDP (eXpress Data Path) for high-performance packet processing. Three attachment modes are supported.
For detailed XDP setup instructions, especially for Proxmox and other hypervisors, see the XDP Modes Guide.
Mode Comparison
| Mode | Attach Point | Performance | Use Case | NIC Requirements |
|---|---|---|---|---|
| Generic | Network stack (kernel) | ~1-2 Mpps | Testing, development, compatibility | Any NIC |
| Native | Network driver (kernel) | ~5-10 Mpps | Production (bare metal, VM with SR-IOV) | XDP-capable driver |
| Offload | NIC hardware (SmartNIC) | ~10-40 Mpps | High-throughput production | SmartNIC with XDP offload |
Generic Mode (Default)
Description: XDP program runs in the kernel network stack
Advantages:
- Works with any network interface
- No special driver or hardware requirements
- Ideal for testing and development
- Compatible with all hypervisors and virtualization platforms
Disadvantages:
- Lower performance (~1-2 Mpps per core)
- Packets already passed through driver before XDP processing
Configuration (in runtime.exs):
xdp_attach_mode = "generic"
Best for:
- Virtual machines without SR-IOV
- Testing and validation environments
- NICs without XDP driver support
- Hypervisors like Proxmox, VMware, VirtualBox
Native Mode (Recommended)
Description: XDP program runs at the network driver level
Advantages:
- High performance (~5-10 Mpps per core)
- Packets processed before entering network stack
- Significantly lower latency than generic mode
- Works on bare metal and SR-IOV VMs
Disadvantages:
- Requires network driver with XDP support
- Not all NICs/drivers support native XDP
Configuration (in runtime.exs):
xdp_attach_mode = "native"
Best for:
- Production deployments on bare metal
- VMs with SR-IOV passthrough
- NICs with XDP-capable drivers (Intel, Mellanox, etc.)
Requirements:
- XDP-capable network driver (see NIC Compatibility)
- Linux kernel 5.15+ with XDP support enabled
Offload Mode (Maximum Performance)
Description: XDP program runs directly on SmartNIC hardware
Advantages:
- Maximum performance (~10-40 Mpps)
- Zero CPU overhead for packet processing
- Sub-microsecond latency
- Frees CPU for control plane processing
Disadvantages:
- Requires expensive SmartNIC hardware
- Limited SmartNIC availability
- Complex setup and configuration
Configuration (in runtime.exs):
xdp_attach_mode = "offload"
Best for:
- Ultra-high-throughput production deployments
- Edge computing with strict latency requirements
- Environments where CPU resources are limited
Requirements:
- SmartNIC with XDP offload support (Netronome Agilio CX, Mellanox BlueField)
- Specialized firmware and drivers
Configuration Parameters
Network Interfaces
| Parameter | Description | Type | Default |
|---|---|---|---|
xdp_interfaces | Network interfaces for N3/N6/N9 traffic (comma-separated, or "auto" for all non-loopback) | String | "auto" |
n3_address | IPv4 address for N3 interface (GTP-U from RAN) | IP | "127.0.0.1" |
n9_address | IPv4 address for N9 interface (UPF-to-UPF for ULCL) | IP | Same as n3_address |
Example (in runtime.exs):
xdp_interfaces = "eth0,eth1"
n3_address = "10.100.50.233"
n9_address = "10.100.50.234"
PFCP Configuration
| Parameter | Description | Type | Default |
|---|---|---|---|
pfcp_address | Local address for PFCP server (N4/Sxb/Sxc interface) | IP String | "127.0.0.1" |
pfcp_port | PFCP port | Integer | 8805 |
node_id | Local Node ID for PFCP protocol | IP String | "127.0.0.1" |
heartbeat_interval_ms | PFCP heartbeat interval (milliseconds) | Integer | 5000 |
heartbeat_timeout_ms | PFCP heartbeat timeout (milliseconds) | Integer | 5000 |
heartbeat_retries | Number of heartbeat retries before declaring peer dead | Integer | 3 |
association_setup_timeout | Timeout waiting for a PFCP Association Setup Response when the UPF initiates an association (milliseconds) | Integer | 5000 |
pfcp_remote_nodes | List of control-plane IP address strings the UPF actively sets up associations with on startup (UPF-initiated). Empty means the UPF only accepts associations initiated by the control plane. | List of String | [] |
Example (in runtime.exs):
pfcp_address = "10.100.50.241"
pfcp_port = 8805
node_id = "10.100.50.241"
heartbeat_interval_ms = 10_000
heartbeat_retries = 5
association_setup_timeout = 5_000
pfcp_remote_nodes = [] # or e.g. ["10.100.50.20", "10.100.50.22"]
API and Monitoring
| Parameter | Description | Type | Default |
|---|---|---|---|
api_port | Local port for REST API server (Phoenix) | Integer | 8080 |
log_level | Logging level (:debug, :info, :warning, :error) | Atom | :info |
Example (in runtime.exs):
api_port = 8080
log_level = :debug
GTP Path Management
| Parameter | Description | Type | Default |
|---|---|---|---|
gtpu_port | GTP-U port | Integer | 2152 |
gtp_echo_interval | Default echo interval in seconds | Integer | 10 |
gtp_echo_retries | Max missed echoes before path failure | Integer | 3 |
gtp_peers | List of GTP peers for Echo Request keepalives | List | [] |
Example (in runtime.exs):
gtp_echo_interval = 15
gtp_echo_retries = 3
gtp_peers = [
%{address: parse_ip.("10.100.50.50"), echo: true, echo_interval: 10},
%{address: parse_ip.("10.100.50.60"), echo: false},
]
eBPF Map Capacity
| Parameter | Description | Type | Default |
|---|---|---|---|
max_sessions | Maximum number of concurrent sessions | Integer | 1_000_000 |
far_map_size | Size of FAR eBPF map | Integer | 131_070 |
qer_map_size | Size of QER eBPF map | Integer | 65_535 |
urr_map_size | Size of URR eBPF map | Integer | 65_535 |
Example (in runtime.exs):
max_sessions = 100_000
far_map_size = 131_070
qer_map_size = 65_535
urr_map_size = 131_070
Buffer Configuration
Downlink packets are buffered while a UE is idle, then flushed when the UE is paged. These parameters bound how much is held and for how long.
| Parameter | Description | Type | Default |
|---|---|---|---|
buffer_port | UDP port for buffered packets from eBPF | Integer | 22152 |
buffer_max_total | Maximum packets buffered across all FARs (global cap) | Integer | 10_000 |
buffer_max_per_far | Maximum packets buffered per FAR | Integer | 100 |
buffer_ttl_ms | Time a buffered packet is held before it is dropped (milliseconds) | Integer | 30_000 |
buffer_cleanup_interval_ms | Interval at which expired buffered packets are swept (milliseconds) | Integer | 5_000 |
Example (in runtime.exs):
buffer_port = 22152
buffer_max_total = 10_000
buffer_max_per_far = 100
buffer_ttl_ms = 30_000
buffer_cleanup_interval_ms = 5_000
Drops caused by these limits are counted by upf_buffer_packets_dropped_total (labels global_limit, far_limit, expired). See the Metrics Reference.
Feature Flags
| Parameter | Description | Type | Default |
|---|---|---|---|
feature_ueip | Enable UE IP allocation by OmniUPF | Boolean | false |
ueip_pool | IP pool for UE IP allocation (requires feature_ueip) | CIDR String | "10.60.0.0/24" |
feature_ftup | Enable F-TEID allocation by OmniUPF | Boolean | true |
teid_pool_start | TEID allocation range start | Integer | 1 |
teid_pool_end | TEID allocation range end | Integer | 10_000_000 |
Example (UE IP allocation) (in runtime.exs):
feature_ueip = true
ueip_pool = "10.45.0.0/16"
Example (F-TEID allocation) (in runtime.exs):
feature_ftup = true
teid_pool_start = 1
teid_pool_end = 1_000_000
Route Manager Configuration
For UE route synchronization with FRR (Free Range Routing) daemon. See Route Management Guide for details.
| Parameter | Description | Type | Default |
|---|---|---|---|
route_manager_enabled | Enable automatic UE route synchronization | Boolean | true |
route_manager_type | Routing daemon type ("frr" or "static") | String | "frr" |
route_manager_nexthop | Next-hop address for injected UE routes (empty = directly connected) | String | "" |
route_manager_vtysh_path | Path to the FRR vtysh binary (used when route_manager_type is "frr") | String | "/usr/bin/vtysh" |
route_manager_sync_interval_ms | Full reconciliation interval between tracked routes and the routing daemon (milliseconds) | Integer | 600_000 |
route_batch_interval_ms | Debounce window for batching incremental route add/remove operations (milliseconds) | Integer | 1_000 |
Example (in runtime.exs):
route_manager_enabled = true
route_manager_type = "frr"
route_manager_nexthop = ""
route_manager_vtysh_path = "/usr/bin/vtysh"
route_manager_sync_interval_ms = 600_000
route_batch_interval_ms = 1_000
When to Enable:
- Multi-UPF deployments requiring route advertisement
- Integration with OSPF or BGP routing protocols
- Requires FRRouting daemon installed and configured
eBPF / XDP Configuration
| Parameter | Description | Type | Default |
|---|---|---|---|
xdp_interfaces | Comma-separated list of interfaces for XDP, or "auto" for all non-loopback | String | "auto" |
xdp_attach_mode | XDP mode: "generic", "native", or "offload" | String | "generic" |
ebpf_pin_path | BPF filesystem pin path | String | "/sys/fs/bpf/upf_pipeline" |
xdp_obj_path | Path to compiled eBPF object | String | "/etc/omniupf/ipentrypoint_bpf.o" |
ebpf_backend | Dataplane map backend: :nif (direct NIF, default), :port (external port process), or :mock (in-memory, for tests without eBPF) | Atom | :nif |
Example (in runtime.exs):
xdp_interfaces = "auto" # or "eth0,eth1" for specific interfaces
xdp_attach_mode = "native"
ebpf_pin_path = "/sys/fs/bpf/upf_pipeline"
xdp_obj_path = "/etc/omniupf/ipentrypoint_bpf.o"
ebpf_backend = :nif
Configuration File
Elixir Configuration File (runtime.exs)
File: /etc/omniupf/runtime.exs
The configuration file uses Elixir syntax with plain variable assignments for readability. Variables are applied to the application configuration at the bottom of the file via config :upf_ex, ....
import Config
parse_ip = fn str ->
{:ok, addr} = :inet.parse_address(String.to_charlist(str))
addr
end
# =============================================================================
# PFCP (N4/Sx) Configuration
# =============================================================================
pfcp_address = "10.100.50.241" # IP address to listen for PFCP messages
pfcp_port = 8805 # PFCP port (standard: 8805)
node_id = "10.100.50.241" # Node ID advertised in Association Setup
# =============================================================================
# GTP-U Data Plane Configuration
# =============================================================================
n3_address = "10.100.50.233" # N3 interface IP (GTP-U toward RAN)
n9_address = n3_address # N9 interface IP (defaults to N3)
gtpu_port = 2152 # GTP-U port (standard: 2152)
buffer_port = 22152 # Buffer listener port
# =============================================================================
# eBPF / XDP Configuration
# =============================================================================
xdp_interfaces = "auto" # "auto" for all non-loopback, or comma-separated list
xdp_attach_mode = "native" # XDP mode: "generic", "native", or "offload"
ebpf_pin_path = "/sys/fs/bpf/upf_pipeline"
xdp_obj_path = "/etc/omniupf/ipentrypoint_bpf.o"
# =============================================================================
# Session & Resource Pool Configuration
# =============================================================================
max_sessions = 100_000
teid_pool_start = 1
teid_pool_end = 10_000_000
far_map_size = 131_070
qer_map_size = 65_535
urr_map_size = 65_535
# =============================================================================
# Feature Flags
# =============================================================================
feature_ueip = true
feature_ftup = true
ueip_pool = "10.45.0.0/16"
# =============================================================================
# Route Management
# =============================================================================
route_manager_enabled = true
route_manager_type = "frr"
# =============================================================================
# Heartbeat Configuration
# =============================================================================
heartbeat_interval_ms = 10_000
heartbeat_timeout_ms = 5_000
heartbeat_retries = 5
# =============================================================================
# GTP-U Peer Echo Monitoring
# =============================================================================
gtp_echo_interval = 10
gtp_echo_retries = 3
gtp_peers = [
%{address: parse_ip.("10.100.50.50"), echo: true, echo_interval: 10},
]
# =============================================================================
# HTTP API and Logging
# =============================================================================
api_port = 8080
log_level = :info
# =============================================================================
# Apply Configuration (do not edit below this line)
# =============================================================================
config :upf_ex,
pfcp_address: parse_ip.(pfcp_address),
pfcp_port: pfcp_port,
n3_address: parse_ip.(n3_address),
n9_address: parse_ip.(n9_address),
node_id: parse_ip.(node_id),
api_port: api_port,
ebpf_pin_path: ebpf_pin_path,
xdp_obj_path: xdp_obj_path,
interface_names: String.split(xdp_interfaces, ","),
xdp_attach_mode: xdp_attach_mode,
feature_ueip: feature_ueip,
feature_ftup: feature_ftup,
ueip_pool: ueip_pool,
teid_pool_start: teid_pool_start,
teid_pool_end: teid_pool_end,
far_map_size: far_map_size,
qer_map_size: qer_map_size,
urr_map_size: urr_map_size,
max_sessions: max_sessions,
route_manager_enabled: route_manager_enabled,
route_manager_type: route_manager_type,
buffer_port: buffer_port,
gtpu_port: gtpu_port,
heartbeat_interval_ms: heartbeat_interval_ms,
heartbeat_timeout_ms: heartbeat_timeout_ms,
heartbeat_retries: heartbeat_retries,
gtp_echo_interval: gtp_echo_interval,
gtp_echo_retries: gtp_echo_retries,
gtp_peers: gtp_peers
config :logger, level: log_level
Managing the Service
# Start the UPF
sudo systemctl start omniupf
# Stop the UPF
sudo systemctl stop omniupf
# Restart after configuration changes
sudo systemctl restart omniupf
# Check status
sudo systemctl status omniupf
# View logs
sudo journalctl -u omniupf -f
# Or use the release binary directly
sudo /opt/omniupf/bin/upf_ex start
sudo /opt/omniupf/bin/upf_ex stop
sudo /opt/omniupf/bin/upf_ex daemon # start as background daemon
Hypervisor Compatibility
Overview
OmniUPF is compatible with all major hypervisors and virtualization platforms. The XDP attach mode and network configuration depend on the hypervisor's networking capabilities.
For step-by-step instructions on enabling native XDP on Proxmox and other hypervisors, see the XDP Modes Guide.
Proxmox VE
Supported Configurations:
1. Bridge Mode (Generic XDP)
Use case: Standard VM networking
Configuration:
- Network Device: VirtIO or E1000
- XDP Mode:
generic - Performance: ~1-2 Mpps
Proxmox VM Settings:
Network Device: net0
Model: VirtIO (paravirtualized)
Bridge: vmbr0
OmniUPF Config (in runtime.exs):
xdp_interfaces = "eth0"
xdp_attach_mode = "generic"
2. SR-IOV Passthrough (Native XDP)
Use case: High-performance production
Configuration:
- Network Device: SR-IOV Virtual Function
- XDP Mode:
native - Performance: ~5-10 Mpps
Requirements:
- Physical NIC with SR-IOV support (Intel X710, Mellanox ConnectX-5)
- SR-IOV enabled in BIOS
- IOMMU enabled (
intel_iommu=onoramd_iommu=onin GRUB)
Enable SR-IOV on Proxmox:
# Edit GRUB configuration
nano /etc/default/grub
# Add to GRUB_CMDLINE_LINUX_DEFAULT:
intel_iommu=on iommu=pt
# Update GRUB and reboot
update-grub
reboot
# Enable VFs on NIC (example: 4 virtual functions on eth0)
echo 4 > /sys/class/net/eth0/device/sriov_numvfs
# Make persistent
echo "echo 4 > /sys/class/net/eth0/device/sriov_numvfs" >> /etc/rc.local
chmod +x /etc/rc.local
Proxmox VM Settings:
Hardware -> Add -> PCI Device
Select: SR-IOV Virtual Function
All Functions: No
Primary GPU: No
PCI-Express: Yes (optional)
OmniUPF Config (in runtime.exs):
xdp_interfaces = "ens1f0" # SR-IOV VF name
xdp_attach_mode = "native"
3. PCI Passthrough (Native XDP)
Use case: Dedicated NIC for single VM
Configuration:
- Entire physical NIC passed to VM
- XDP Mode:
nativeoroffload(if SmartNIC) - Performance: ~5-40 Mpps (depends on NIC)
Proxmox VM Settings:
Hardware -> Add -> PCI Device
Select: Physical NIC (e.g., 0000:01:00.0)
All Functions: Yes
Primary GPU: No
PCI-Express: Yes
OmniUPF Config (in runtime.exs):
xdp_interfaces = "ens1f0"
xdp_attach_mode = "native" # or "offload" for SmartNIC
KVM/QEMU
Bridge Mode:
virt-install \
--name omniupf \
--network bridge=br0,model=virtio \
--disk path=/var/lib/libvirt/images/omniupf.qcow2 \
...
SR-IOV Passthrough:
<interface type='hostdev' managed='yes'>
<source>
<address type='pci' domain='0x0000' bus='0x01' slot='0x10' function='0x1'/>
</source>
</interface>
VMware ESXi
Standard vSwitch (Generic XDP):
- Network Adapter: VMXNET3
- XDP Mode:
generic
SR-IOV (Native XDP):
- Enable SR-IOV in ESXi host settings
- Add SR-IOV network adapter to VM
- XDP Mode:
native
Microsoft Hyper-V
Virtual Switch (Generic XDP):
- Network Adapter: Synthetic
- XDP Mode:
generic
SR-IOV (Native XDP):
- Enable SR-IOV in Hyper-V Manager
- Configure SR-IOV on virtual network adapter
- XDP Mode:
native
VirtualBox
NAT/Bridged Mode (Generic XDP only):
- Network Adapter: VirtIO-Net or Intel PRO/1000
- XDP Mode:
generic - Note: VirtualBox does not support SR-IOV
NIC Compatibility
Understanding Mpps vs Throughput
Packets per second (Mpps) and throughput (Gbps) are not directly equivalent - the relationship depends entirely on packet size. Mobile network traffic varies dramatically in packet size, from tiny VoIP packets to large video streaming frames.
Packet Size Impact on Throughput
In mobile networks, the UPF processes GTP-U encapsulated packets on the N3 interface and native IP packets on the N6 interface.
GTP-U Encapsulation Overhead (N3 Interface):
- Outer IPv4 header: 20 bytes
- Outer UDP header: 8 bytes
- GTP-U header: 8 bytes
- Total GTP-U overhead: 36 bytes
Minimum GTP-U Packet (N3):
- Inner IP header: 20 bytes (IPv4)
- Inner UDP header: 8 bytes
- Minimum payload: 1 byte
- Inner packet total: 29 bytes
- Plus GTP-U overhead: 36 bytes
- Total packet size: 65 bytes
Throughput at 1 Mpps with minimum GTP-U packets:
65 bytes x 1,000,000 pps x 8 bits/byte = 520 Mbps
Maximum GTP-U Packet (N3 with 1500 MTU):
- Inner IP MTU: 1500 bytes (full inner IP packet)
- Plus GTP-U overhead: 36 bytes
- Total packet size: 1536 bytes
Throughput at 1 Mpps with maximum GTP-U packets:
1536 bytes x 1,000,000 pps x 8 bits/byte = 12,288 Mbps ~ 12.3 Gbps
Native IP Packets (N6 Interface):
On N6 (towards Internet), packets are native IP without GTP-U:
Minimum N6 packet:
- IP header: 20 bytes
- UDP header: 8 bytes
- Minimum payload: 1 byte
- Total: 29 bytes
Throughput at 1 Mpps with minimum N6 packets:
29 bytes x 1,000,000 pps x 8 bits/byte = 232 Mbps
Maximum N6 packet (1500 MTU):
- IP MTU: 1500 bytes
- Total: 1500 bytes
Throughput at 1 Mpps with maximum N6 packets:
1500 bytes x 1,000,000 pps x 8 bits/byte = 12,000 Mbps = 12 Gbps
Real-World Performance Examples
Intel X710 NIC (10 Mpps capacity on N3 interface with GTP-U):
| Traffic Pattern | Inner Packet Size | GTP-U Total | Throughput at 10 Mpps | Typical Use Case |
|---|---|---|---|---|
| VoIP calls (N3) | 65-150 bytes | 101-186 bytes | 0.8-1.5 Gbps | AMR-WB voice, G.711 |
| Light web (N3) | 400-600 bytes | 436-636 bytes | 3.5-5.1 Gbps | HTTP/HTTPS, messaging |
| Modern mobile (N3) | 1200 bytes | 1236 bytes | 9.9 Gbps | Typical 2024 traffic mix |
| Video streaming (N3) | 1400-1450 bytes | 1436-1486 bytes | 11.5-11.9 Gbps | HD/4K video chunks |
| Maximum MTU (N3) | 1500 bytes | 1536 bytes | 12.3 Gbps | Large TCP downloads |
On N6 interface (native IP, no GTP-U):
| Traffic Pattern | Packet Size | Throughput at 10 Mpps | Typical Use Case |
|---|---|---|---|
| VoIP packets | 65-150 bytes | 0.5-1.2 Gbps | Voice RTP streams |
| Light web | 400-600 bytes | 3.2-4.8 Gbps | HTTP requests |
| Modern mobile | 1200 bytes | 9.6 Gbps | Typical 2024 traffic |
| Video streaming | 1400-1450 bytes | 11.2-11.6 Gbps | Video downloads |
| Maximum MTU | 1500 bytes | 12.0 Gbps | Large file transfers |
At 10 Mpps with modern mobile traffic (1200-byte average), expect ~10 Gbps throughput on both N3 and N6 interfaces.
Practical Capacity Planning:
With 1200-byte average packet size (typical for modern mobile networks with video streaming):
| NIC Mpps Capacity | N3 Throughput (GTP-U) | N6 Throughput (Native IP) | Realistic Deployment |
|---|---|---|---|
| 1 Mpps | ~1.0 Gbps | ~1.0 Gbps | Small cell site, IoT gateway |
| 5 Mpps | ~4.9 Gbps | ~4.8 Gbps | Medium cell site, enterprise |
| 10 Mpps | ~9.9 Gbps | ~9.6 Gbps | Large cell site, small city |
| 20 Mpps | ~19.7 Gbps | ~19.2 Gbps | Metro area, medium city |
| 40 Mpps | ~39.4 Gbps | ~38.4 Gbps | Large metro, regional hub |
XDP-Capable Network Drivers
OmniUPF requires network drivers with XDP support for native and offload modes. Generic mode works with any NIC.
Intel NICs
| Model | Driver | XDP Support | Mode | Performance |
|---|---|---|---|---|
| Intel X710 | i40e | Yes | Native | ~10 Mpps |
| Intel XL710 | i40e | Yes | Native | ~10 Mpps |
| Intel E810 | ice | Yes | Native | ~15 Mpps |
| Intel 82599ES | ixgbe | Yes | Native | ~8 Mpps |
| Intel I350 | igb | Limited | Generic | ~1 Mpps |
| Intel E1000 | e1000 | No | Generic only | ~1 Mpps |
Mellanox/NVIDIA NICs
| Model | Driver | XDP Support | Mode | Performance |
|---|---|---|---|---|
| Mellanox ConnectX-5 | mlx5 | Yes | Native | ~12 Mpps |
| Mellanox ConnectX-6 | mlx5 | Yes | Native | ~20 Mpps |
| Mellanox BlueField | mlx5 | Yes | Native + Offload | ~40 Mpps |
| Mellanox ConnectX-4 | mlx4 | Limited | Generic | ~2 Mpps |
Broadcom NICs
| Model | Driver | XDP Support | Mode | Performance |
|---|---|---|---|---|
| Broadcom BCM57xxx | bnxt_en | Yes | Native | ~8 Mpps |
| Broadcom NetXtreme II | bnx2x | No | Generic only | ~1 Mpps |
Other Vendors
| Model | Driver | XDP Support | Mode | Performance |
|---|---|---|---|---|
| Netronome Agilio CX | nfp | Yes | Offload | ~30 Mpps |
| Amazon ENA | ena | Yes | Native | ~5 Mpps |
| Solarflare SFC9xxx | sfc | Yes | Native | ~8 Mpps |
| VirtIO | virtio_net | Limited | Generic | ~2 Mpps |
Checking NIC XDP Support
Check if driver supports XDP:
# Find NIC driver
ethtool -i eth0 | grep driver
# Check XDP support in driver
modinfo <driver_name> | grep -i xdp
# Example for Intel i40e
modinfo i40e | grep -i xdp
Verify XDP program attachment:
# Check if XDP program is attached
ip link show eth0 | grep -i xdp
# Example output (XDP attached):
# 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdp qdisc mq
Recommended NICs by Use Case
With 1200-byte average packet size (modern mobile traffic):
| Use Case | Recommended NIC | Mode | Mpps Capacity | Throughput (N3) | Deployment Scenario |
|---|---|---|---|---|---|
| Testing/Development | Any NIC (VirtIO, E1000) | Generic | 1-2 Mpps | 1-2 Gbps | Lab testing, PoC |
| Small Cell Site | Intel X710, Mellanox CX-5 | Native | 5-10 Mpps | 5-10 Gbps | Rural cell, enterprise |
| Medium Cell/Metro | Intel E810, Mellanox CX-6 | Native | 10-20 Mpps | 10-20 Gbps | Urban cell, small city |
| Large Metro | Mellanox CX-6, Intel E810 (dual) | Native | 20-40 Mpps | 20-40 Gbps | Metro area, medium city |
| Regional Hub | Mellanox BlueField, Netronome Agilio | Offload | 40+ Mpps | 40+ Gbps | Regional aggregation |
| Proxmox VM (Bridge) | VirtIO | Generic | 1-2 Mpps | 1-2 Gbps | Testing only |
| Proxmox VM (SR-IOV) | Intel X710/E810 VF, Mellanox CX-5 VF | Native | 5-10 Mpps | 5-10 Gbps | Production VM |
Additional Resources
Official XDP Documentation:
NIC Compatibility Lists:
Configuration Examples
Example 1: Development Environment (Generic Mode)
Scenario: Testing OmniUPF on laptop or VM without SR-IOV
# Development config (/etc/omniupf/runtime.exs)
xdp_interfaces = "eth0"
xdp_attach_mode = "generic"
api_port = 8080
pfcp_address = "127.0.0.1"
pfcp_port = 8805
node_id = "127.0.0.1"
n3_address = "127.0.0.1"
log_level = :debug
max_sessions = 1_000
Example 2: Production Bare Metal (Native Mode)
Scenario: Production UPF on bare metal server with Intel X710 NIC
# Production bare metal config (/etc/omniupf/runtime.exs)
xdp_interfaces = "ens1f0,ens1f1" # N3 on ens1f0, N6 on ens1f1
xdp_attach_mode = "native"
api_port = 8080
pfcp_address = "10.100.50.241"
pfcp_port = 8805
node_id = "10.100.50.241"
n3_address = "10.100.50.233"
n9_address = "10.100.50.234"
log_level = :info
max_sessions = 500_000
gtp_echo_interval = 30
gtp_peers = [
%{address: parse_ip.("10.100.50.10"), echo: true, echo_interval: 30},
%{address: parse_ip.("10.100.50.11"), echo: true, echo_interval: 30},
]
heartbeat_interval_ms = 10_000
feature_ueip = true
ueip_pool = "10.45.0.0/16"
Example 3: Proxmox VM with SR-IOV (Native Mode)
Scenario: Production UPF on Proxmox VM with SR-IOV passthrough
# Proxmox SR-IOV config (/etc/omniupf/runtime.exs)
xdp_interfaces = "ens1f0" # SR-IOV VF
xdp_attach_mode = "native"
api_port = 8080
pfcp_address = "192.168.100.10"
pfcp_port = 8805
node_id = "192.168.100.10"
n3_address = "192.168.100.10"
log_level = :info
max_sessions = 100_000
gtp_echo_interval = 15
gtp_peers = [
%{address: parse_ip.("192.168.100.50"), echo: true},
]
Example 4: PGW-U Mode (4G EPC)
Scenario: OmniUPF acting as PGW-U in 4G EPC network
# PGW-U configuration (/etc/omniupf/runtime.exs)
xdp_interfaces = "eth0"
xdp_attach_mode = "native"
api_port = 8080
pfcp_address = "10.200.1.10"
pfcp_port = 8805
node_id = "10.200.1.10"
n3_address = "10.200.1.10" # S5/S8 interface (GTP-U)
log_level = :info
max_sessions = 200_000
gtp_echo_interval = 20
gtp_peers = [
%{address: parse_ip.("10.200.1.50"), echo: true, echo_interval: 20},
]
heartbeat_interval_ms = 5_000
Example 5: Multi-Mode (UPF + PGW-U Simultaneously)
Scenario: OmniUPF serving both 5G and 4G networks concurrently
# Multi-mode configuration (/etc/omniupf/runtime.exs)
xdp_interfaces = "eth0,eth1"
xdp_attach_mode = "native"
api_port = 8080
pfcp_address = "10.50.1.100"
pfcp_port = 8805
node_id = "10.50.1.100"
n3_address = "10.50.1.100"
n9_address = "10.50.1.101"
log_level = :info
max_sessions = 300_000
gtp_echo_interval = 15
gtp_peers = [
%{address: parse_ip.("10.50.2.10"), echo: true, echo_interval: 15},
%{address: parse_ip.("10.50.2.20"), echo: true, echo_interval: 15},
]
heartbeat_interval_ms = 10_000
feature_ueip = true
ueip_pool = "10.60.0.0/16"
Example 6: SmartNIC Offload Mode
Scenario: Ultra-high-throughput deployment with Netronome Agilio CX SmartNIC
# SmartNIC offload configuration (/etc/omniupf/runtime.exs)
xdp_interfaces = "enp1s0np0" # SmartNIC interface
xdp_attach_mode = "offload"
api_port = 8080
pfcp_address = "10.10.1.50"
pfcp_port = 8805
node_id = "10.10.1.50"
n3_address = "10.10.1.50"
log_level = :warning
max_sessions = 1_000_000
far_map_size = 2_000_000
qer_map_size = 1_000_000
gtp_echo_interval = 30
gtp_peers = [
%{address: parse_ip.("10.10.2.10"), echo: true},
%{address: parse_ip.("10.10.2.20"), echo: true},
%{address: parse_ip.("10.10.2.30"), echo: true},
]
heartbeat_interval_ms = 15_000
Map Sizing and Capacity Planning
Setting Map Sizes
Set max_sessions and configure map sizes for your deployment:
max_sessions = 100_000
far_map_size = 131_070
qer_map_size = 65_535
urr_map_size = 131_070
Memory usage: ~91 MB for 100K sessions
Capacity Estimation
Calculate maximum sessions:
Max Sessions = min(
pdr_map_size / 2,
far_map_size / 2,
qer_map_size
)
Example:
- PDR map: 200,000
- FAR map: 200,000
- QER map: 100,000
Max Sessions = min(100,000, 100,000, 100,000) = 100,000
Memory Requirements
Per session memory usage:
- PDR: 2 x 212 B = 424 B
- FAR: 2 x 20 B = 40 B
- QER: 1 x 36 B = 36 B
- URR: 2 x 20 B = 40 B
- Total: ~540 B per session
For 100K sessions: ~52 MB kernel memory
Recommendation: Ensure locked memory limit allows 2x estimated usage:
# Check current limit
ulimit -l
# Set unlimited (required for eBPF)
ulimit -l unlimited
Related Documentation
- Architecture Guide - eBPF/XDP technical details and performance optimization
- Rules Management Guide - PDR, FAR, QER, URR configuration
- Monitoring Guide - Statistics, capacity monitoring, and alerting
- Metrics Reference - Complete Prometheus metrics reference
- Web UI Guide - Control panel operations
- Operations Guide - UPF architecture and deployment overview
- Walled Garden Guide - Out-of-credit redirect, captive portal, and whitelist configuration