Skip to main content

OmniUPF Configuration Guide

Table of Contents

  1. Overview
  2. Operating Modes
  3. XDP Attachment Modes
  4. Configuration Parameters
  5. Configuration File
  6. Hypervisor Compatibility
  7. NIC Compatibility
  8. Configuration Examples
  9. 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

ModeAttach PointPerformanceUse CaseNIC Requirements
GenericNetwork stack (kernel)~1-2 MppsTesting, development, compatibilityAny NIC
NativeNetwork driver (kernel)~5-10 MppsProduction (bare metal, VM with SR-IOV)XDP-capable driver
OffloadNIC hardware (SmartNIC)~10-40 MppsHigh-throughput productionSmartNIC 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

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

ParameterDescriptionTypeDefault
xdp_interfacesNetwork interfaces for N3/N6/N9 traffic (comma-separated, or "auto" for all non-loopback)String"auto"
n3_addressIPv4 address for N3 interface (GTP-U from RAN)IP"127.0.0.1"
n9_addressIPv4 address for N9 interface (UPF-to-UPF for ULCL)IPSame 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

ParameterDescriptionTypeDefault
pfcp_addressLocal address for PFCP server (N4/Sxb/Sxc interface)IP String"127.0.0.1"
pfcp_portPFCP portInteger8805
node_idLocal Node ID for PFCP protocolIP String"127.0.0.1"
heartbeat_interval_msPFCP heartbeat interval (milliseconds)Integer5000
heartbeat_timeout_msPFCP heartbeat timeout (milliseconds)Integer5000
heartbeat_retriesNumber of heartbeat retries before declaring peer deadInteger3
association_setup_timeoutTimeout waiting for a PFCP Association Setup Response when the UPF initiates an association (milliseconds)Integer5000
pfcp_remote_nodesList 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

ParameterDescriptionTypeDefault
api_portLocal port for REST API server (Phoenix)Integer8080
log_levelLogging level (:debug, :info, :warning, :error)Atom:info

Example (in runtime.exs):

api_port = 8080
log_level = :debug

GTP Path Management

ParameterDescriptionTypeDefault
gtpu_portGTP-U portInteger2152
gtp_echo_intervalDefault echo interval in secondsInteger10
gtp_echo_retriesMax missed echoes before path failureInteger3
gtp_peersList of GTP peers for Echo Request keepalivesList[]

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

ParameterDescriptionTypeDefault
max_sessionsMaximum number of concurrent sessionsInteger1_000_000
far_map_sizeSize of FAR eBPF mapInteger131_070
qer_map_sizeSize of QER eBPF mapInteger65_535
urr_map_sizeSize of URR eBPF mapInteger65_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.

ParameterDescriptionTypeDefault
buffer_portUDP port for buffered packets from eBPFInteger22152
buffer_max_totalMaximum packets buffered across all FARs (global cap)Integer10_000
buffer_max_per_farMaximum packets buffered per FARInteger100
buffer_ttl_msTime a buffered packet is held before it is dropped (milliseconds)Integer30_000
buffer_cleanup_interval_msInterval at which expired buffered packets are swept (milliseconds)Integer5_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

ParameterDescriptionTypeDefault
feature_ueipEnable UE IP allocation by OmniUPFBooleanfalse
ueip_poolIP pool for UE IP allocation (requires feature_ueip)CIDR String"10.60.0.0/24"
feature_ftupEnable F-TEID allocation by OmniUPFBooleantrue
teid_pool_startTEID allocation range startInteger1
teid_pool_endTEID allocation range endInteger10_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.

ParameterDescriptionTypeDefault
route_manager_enabledEnable automatic UE route synchronizationBooleantrue
route_manager_typeRouting daemon type ("frr" or "static")String"frr"
route_manager_nexthopNext-hop address for injected UE routes (empty = directly connected)String""
route_manager_vtysh_pathPath to the FRR vtysh binary (used when route_manager_type is "frr")String"/usr/bin/vtysh"
route_manager_sync_interval_msFull reconciliation interval between tracked routes and the routing daemon (milliseconds)Integer600_000
route_batch_interval_msDebounce window for batching incremental route add/remove operations (milliseconds)Integer1_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

ParameterDescriptionTypeDefault
xdp_interfacesComma-separated list of interfaces for XDP, or "auto" for all non-loopbackString"auto"
xdp_attach_modeXDP mode: "generic", "native", or "offload"String"generic"
ebpf_pin_pathBPF filesystem pin pathString"/sys/fs/bpf/upf_pipeline"
xdp_obj_pathPath to compiled eBPF objectString"/etc/omniupf/ipentrypoint_bpf.o"
ebpf_backendDataplane 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=on or amd_iommu=on in 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: native or offload (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 PatternInner Packet SizeGTP-U TotalThroughput at 10 MppsTypical Use Case
VoIP calls (N3)65-150 bytes101-186 bytes0.8-1.5 GbpsAMR-WB voice, G.711
Light web (N3)400-600 bytes436-636 bytes3.5-5.1 GbpsHTTP/HTTPS, messaging
Modern mobile (N3)1200 bytes1236 bytes9.9 GbpsTypical 2024 traffic mix
Video streaming (N3)1400-1450 bytes1436-1486 bytes11.5-11.9 GbpsHD/4K video chunks
Maximum MTU (N3)1500 bytes1536 bytes12.3 GbpsLarge TCP downloads

On N6 interface (native IP, no GTP-U):

Traffic PatternPacket SizeThroughput at 10 MppsTypical Use Case
VoIP packets65-150 bytes0.5-1.2 GbpsVoice RTP streams
Light web400-600 bytes3.2-4.8 GbpsHTTP requests
Modern mobile1200 bytes9.6 GbpsTypical 2024 traffic
Video streaming1400-1450 bytes11.2-11.6 GbpsVideo downloads
Maximum MTU1500 bytes12.0 GbpsLarge 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 CapacityN3 Throughput (GTP-U)N6 Throughput (Native IP)Realistic Deployment
1 Mpps~1.0 Gbps~1.0 GbpsSmall cell site, IoT gateway
5 Mpps~4.9 Gbps~4.8 GbpsMedium cell site, enterprise
10 Mpps~9.9 Gbps~9.6 GbpsLarge cell site, small city
20 Mpps~19.7 Gbps~19.2 GbpsMetro area, medium city
40 Mpps~39.4 Gbps~38.4 GbpsLarge 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

ModelDriverXDP SupportModePerformance
Intel X710i40eYesNative~10 Mpps
Intel XL710i40eYesNative~10 Mpps
Intel E810iceYesNative~15 Mpps
Intel 82599ESixgbeYesNative~8 Mpps
Intel I350igbLimitedGeneric~1 Mpps
Intel E1000e1000NoGeneric only~1 Mpps

Mellanox/NVIDIA NICs

ModelDriverXDP SupportModePerformance
Mellanox ConnectX-5mlx5YesNative~12 Mpps
Mellanox ConnectX-6mlx5YesNative~20 Mpps
Mellanox BlueFieldmlx5YesNative + Offload~40 Mpps
Mellanox ConnectX-4mlx4LimitedGeneric~2 Mpps

Broadcom NICs

ModelDriverXDP SupportModePerformance
Broadcom BCM57xxxbnxt_enYesNative~8 Mpps
Broadcom NetXtreme IIbnx2xNoGeneric only~1 Mpps

Other Vendors

ModelDriverXDP SupportModePerformance
Netronome Agilio CXnfpYesOffload~30 Mpps
Amazon ENAenaYesNative~5 Mpps
Solarflare SFC9xxxsfcYesNative~8 Mpps
VirtIOvirtio_netLimitedGeneric~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

With 1200-byte average packet size (modern mobile traffic):

Use CaseRecommended NICModeMpps CapacityThroughput (N3)Deployment Scenario
Testing/DevelopmentAny NIC (VirtIO, E1000)Generic1-2 Mpps1-2 GbpsLab testing, PoC
Small Cell SiteIntel X710, Mellanox CX-5Native5-10 Mpps5-10 GbpsRural cell, enterprise
Medium Cell/MetroIntel E810, Mellanox CX-6Native10-20 Mpps10-20 GbpsUrban cell, small city
Large MetroMellanox CX-6, Intel E810 (dual)Native20-40 Mpps20-40 GbpsMetro area, medium city
Regional HubMellanox BlueField, Netronome AgilioOffload40+ Mpps40+ GbpsRegional aggregation
Proxmox VM (Bridge)VirtIOGeneric1-2 Mpps1-2 GbpsTesting only
Proxmox VM (SR-IOV)Intel X710/E810 VF, Mellanox CX-5 VFNative5-10 Mpps5-10 GbpsProduction 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