OpenBSD Handbook

    Theme
    • Part I. Install & Configure
      • Introduction to OpenBSD
      • Installing OpenBSD
      • The X Window System
      • Networking on OpenBSD
      • System Configuration
      • OpenBSD Basics
      • Managing Software: Packages and Ports
    • Part II. Daily Operations
      • OpenBSD Desktop Environments
      • Multimedia
      • Printing
      • Linux Compatibility
      • Windows Compatibility
      • Games
    • Part III. System Administration
      • Virtualization
      • Storage and File Systems
      • Updating and Upgrading
      • Localization
      • The OpenBSD Boot Process
      • Security
    • Part IV. Networking & Daemons
      • Services
        • Database
          • MariaDB
          • PostgreSQL
          • Redis
          • memcached
        • Directory
          • YP (NIS)
          • LDAP
        • File
          • NFS
          • Samba
        • FTP Services
          • ftpd
          • ProFTPD
          • vsftpd
          • Pure-FTPd
          • TFTP
        • Mail
          • OpenSMTPD Mail Server
          • Dovecot IMAP and POP3 Server
          • Postfix
          • Exim
          • Rspamd
        • Name
          • Unbound DNS Resolver
          • NSD Authoritative DNS Server
          • BIND DNS Server
        • Networking
          • OpenBGPD
          • rad
          • DHCP on OpenBSD
          • slaacd
        • Web
          • Apache HTTP Server
          • nginx Web Server
          • OpenBSD httpd Web Server
          • relayd Reverse Proxy
        • Logging
          • syslogd
        • Monitoring
          • SNMP
        • Remote Access
          • Audit OpenSSH
          • OpenSSH Server
        • File Synchronization
          • rsync
        • Messaging
          • RabbitMQ Message Broker
        • Time
          • NTP Time Synchronization
        • Load Balancing
          • Build Redundant Load-Balanced Gateways
          • Load Balance Services with NAT or DSR
          • Build an HA HTTPS Load Balancer
      • PF
        • pfctl cheat sheet
        • PF Anchors
        • PF Filter Rules
        • PF Forwarding
        • PF Lists and Macros
        • PF Load Balancing
        • PF Logging
        • PF NAT
        • PF Options
        • PF Policies
        • PF Shortcuts
        • PF Tables
      • Advanced Networking
        • High Availability and State Replication
        • Multi-WAN and Policy-Based Routing
        • VPN and Cryptographic Tunneling
        • Classic and Lightweight Tunnels
        • IPv6 at Scale
        • QoS and Traffic Shaping
        • MPLS and Label Distribution
        • Network Services at Scale
        • Virtualization and Host Networking
        • Large-Scale L2 and L3 Design
        • Telemetry, Logging, and Flow Export
        • Hardening and Operational Safety
        • Reference Architectures
        • Troubleshooting Playbooks
      • Serial Communication
    • Part V. Miscellaneous
      • Virtualization Cheat Sheet
      • OpenBSD Cheatsheet
      • How-to Guides
        • Installation and First Boot
          • Complete the First 30 Minutes After Installation
          • Check Hardware Compatibility Before Installing
          • Bootstrap Wi-Fi Firmware Without Ethernet
          • Run OpenBSD as a Virtual Machine Guest
          • Install OpenBSD on a VPS or Cloud Server
          • Install OpenBSD with Full-Disk Encryption
          • Dual-Boot OpenBSD on a UEFI System
          • Automate OpenBSD Installation with Autoinstall and PXE
        • Desktops and Laptops
          • Set Up OpenBSD as a Laptop or Workstation
          • Configure Laptop Power Management
          • Troubleshoot Web Browsers on OpenBSD
          • Use Plan 9 Tools on OpenBSD
          • Build a Minimal Desktop with suckless Tools
          • Install Z shell (zsh)
        • Networking and Remote Access
          • Create an Administrator Account with doas and SSH Keys
          • Configure Secure Remote Access with OpenSSH
          • Use FIDO Security Keys with OpenSSH
          • Configure Wi-Fi Roaming and Wired Failover
          • Troubleshoot PF, NAT, and Routing
          • Route Multiple VLANs with PF
          • Configure a Road-Warrior WireGuard VPN
          • Route IPv6 Networks without NAT
          • Test OpenBGPD with Two Providers
          • Unlock an Internal Service with an SSH Key
          • Build a Simple Router and Firewall
        • Servers and Services
          • Set Up WordPress on OpenBSD
          • Build a Mail Server with OpenSMTPD, Dovecot, and Rspamd
        • Security, Maintenance and Recovery
          • Establish a Conservative Security Baseline
          • Recover Access and Reset the Root Password
          • Collect OpenBSD Diagnostic Evidence
          • Troubleshoot Package Installation and Update Failures
          • Schedule Recurring Maintenance
          • Monitor an OpenBSD System
          • Back Up and Restore an OpenBSD System
          • Configure softraid RAID1
          • Recover an OpenBSD System That Does Not Boot
        • Building, Automation and Virtual Machines
          • Manage OpenBSD with Ansible
          • Build Third-Party Software from Ports
          • Build OpenBSD from Source
          • Plan a Docker Workload Migration to OpenBSD
      • OpenBSD for Linux Users
      • OpenBSD for FreeBSD Users
      • OpenBSD for macOS Users
    • OpenBSD FAQ
    • OpenBSD Architectures
      • OpenBSD Package Search
        • Synopsis
        • Design Considerations
        • Configuration
          • 1) Enable MPLS on transit interfaces and bring up LDP (both PEs)
          • 2) Verify label distribution across the core
          • 3) L3 MPLS VPN (PE-CE) with mpe(4) and OpenBGPD
          • 4) L2 VPLS using mpw(4) pseudowires and bridge(4)
        • Verification
        • Troubleshooting
        • See Also

        MPLS and Label Distribution

        Synopsis #

        OpenBSD provides Multiprotocol Label Switching (MPLS) with the base Label Distribution Protocol daemon ldpd(8) . Enable MPLS on interfaces with ifconfig(8) and configure LDP in ldpd.conf(5) . For Layer-3 MPLS VPNs, use the Provider Edge interface mpe(4) with bgpd.conf(5) ; for Layer-2 VPLS pseudowires, use mpw(4) . Use LDP to distribute labels across an IGP domain and BGP to carry multi-tenant Layer-3 services across the MPLS core.

        Design Considerations #

        • Underlay and discovery. LDP neighbors form by link discovery on interfaces that carry IP connectivity and have MPLS enabled. Ensure the underlay (static/OSPF/IS-IS/BGP-IGP) provides reachability first; LDP does not replace the IGP.
        • Interface enablement. MPLS is enabled per interface (for example, ifconfig em0 mpls). You can disable it with -mpls. Adjust MTU to account for the 4-byte shim per label.
        • Label disposition. By default, directly connected routes use implicit-null; you may advertise explicit-null via explicit-null yes when needed (QoS/ECN preservation).
        • VRFs with rdomains. Use routing domains (VRF-like) to separate customer routing tables; connect a VRF to the MPLS core with an mpe(4) interface bound to that rdomain.
        • L2 services. For VPLS, build full-mesh pseudowires among PEs and bridge them with bridge(4) . Use protected domains to avoid loops.
        • Security and interop. LDP sessions use TCP and hello discovery; consider GTSM and MD5 where appropriate. OpenBSD’s ldpd provides knobs for both.

        Configuration #

        The examples assume a minimal two-PE core:

        • PE1 underlay: em0 ↔ Core, em1 ↔ Core
        • PE2 underlay: em0 ↔ Core, em1 ↔ Core

        IP reachability between PEs over the core exists (via your IGP or statics).

        1) Enable MPLS on transit interfaces and bring up LDP (both PEs) #

        Enable MPLS per interface and configure ldpd to speak LDP on the core links.

        doas ifconfig em0 mpls
          # Allow MPLS on core-facing interface
        doas ifconfig em1 mpls
          # Allow MPLS on the second core-facing interface
        

        Create a minimal /etc/ldpd.conf that runs LDP for IPv4 on the core interfaces:

        ## /etc/ldpd.conf — minimal LDP over IPv4 on two interfaces
        
        router-id 192.0.2.1         # PE1 example; set uniquely per PE
        
        address-family ipv4 {
            interface em0
            interface em1
            # optional: explicit-null yes
        }
        

        On the second PE, set router-id 192.0.2.2 and use the same interface list. ldpd discovers neighbors on enabled links; no neighbor IPs are required for link-local sessions.

        Validate the completed configuration and start LDP on each PE:

        doas ldpd -n -f /etc/ldpd.conf
          # Validate before starting the daemon
        doas rcctl enable ldpd
          # Start LDP on boot
        doas rcctl start ldpd
          # Launch with the completed configuration
        

        2) Verify label distribution across the core #

        Use ldpctl(8) and ifconfig(8) :

        ldpctl show neighbor
          # Expect each core link’s neighbor in Operational state
        ldpctl show lib
          # Label Information Base entries for connected and IGP-learned routes
        ifconfig em0 | egrep -i 'mpls|mtu'
          # Confirm MPLS is enabled and MTU is appropriate
        

        3) L3 MPLS VPN (PE-CE) with mpe(4) and OpenBGPD #

        Bind a customer VRF to MPLS with an mpe(4) interface inside a non-default rdomain, and signal VPN routes using bgpd(8) .

        PE1 (example customer VRF rdomain 10):

        doas ifconfig em2 rdomain 10
        doas ifconfig em2 inet 10.10.10.1/24
          # CE-facing interface in VRF (customer LAN)
        doas ifconfig mpe0 create
          # Create Provider Edge interface
        doas ifconfig mpe0 rdomain 10 mplslabel 2000
        doas ifconfig mpe0 inet 192.0.2.100/32 up
          # Attach mpe0 to VRF, assign per-VPN label, add a /32 per bgpd.conf(5) example
        
        doas rcctl enable bgpd
        doas rcctl start bgpd
        

        Minimal /etc/bgpd.conf excerpt on PE1 to define the VPN and enable VPN AFI/SAFI toward PE2:

        ## /etc/bgpd.conf — L3 VPN on mpe0, IBGP to remote PE
        
        AS 65000
        router-id 192.0.2.1
        
        vpn "cust10" on mpe0 {
            rd 65000:10
            import-target rt 65000:10
            export-target rt 65000:10
            network 10.10.10.0/24     # from VRF rdomain 10 via mpe0
        }
        
        neighbor 192.0.2.2 {
            remote-as 65000
            descr "PE2 core session"
            announce IPv4 vpn
        }
        

        The excerpt defines the VPN and neighbor capability. Add explicit, scoped import and export filters for the peer and permitted VPN prefixes; bgpd defaults to denying routes. It is not a complete routing policy.

        On PE2, mirror the setup: create a VRF (for example, rdomain 20), attach mpe0 (label 3000), announce its customer network in the vpn block, and enable announce IPv4 vpn toward PE1. The vpn block uses the mpe interface’s label and /32, and can be tied to a different rdomain than the one bgpd runs in.

        Verification (either PE):

        doas bgpctl show summary
          # Session to the remote PE should be Established
        doas bgpctl show rib VPNv4
          # VPN RIB should list customer prefixes with RT/RD and mpe0 as the outgoing iface
        route -T 10 -n show
          # Customer VRF (rdomain 10) shows remote VPN routes via mpe0
        

        4) L2 VPLS using mpw(4) pseudowires and bridge(4) #

        For Layer-2 multipoint service, create pseudowires to remote PEs and bridge them with the CE port. ldpd can signal VPLS and bind pseudowires to mpw(4).

        PE1:

        doas ifconfig mpw1 create up
          # Create a pseudowire interface (parameters will be set by ldpd)
        doas ifconfig bridge0 create
        doas ifconfig bridge0 add em2
          # CE-facing port into the bridge
        doas ifconfig bridge0 add mpw1
          # Add the pseudowire to the bridge
        

        /etc/ldpd.conf VPLS block on PE1:

        ## /etc/ldpd.conf — VPLS instance with one pseudowire (PE1)
        
        router-id 192.0.2.1
        
        l2vpn "cust-vpls" type vpls {
            bridge bridge0
            interface em2
            pseudowire mpw1 {
                pw-id 100
                neighbor-id 192.0.2.2    # LSR-ID of PE2
            }
        }
        

        On PE2, create mpw1, add it to a local bridge0, and use the same pw-id with neighbor-id 192.0.2.1. If needed, adjust MTU and control-word/flow-aware knobs (pwecw, -pwefat) on mpw(4).

        Verification (either PE):

        ldpctl show neighbor
          # VPLS-targeted neighbor should appear up
        ifconfig mpw1
          # Local/remote labels (if set) and operational status
        ifconfig bridge0
          # Member list (CE port + mpw1) and protected status if configured
        

        Note: For transport over GRE underlays, gre(4) can encapsulate MPLS; plan MTU accordingly.

        Verification #

        • Core LDP health: ldpctl show neighbor, ldpctl show lib.
        • Interface state: ifconfig <if> | grep -i mpls to confirm MPLS enablement and MTU.
        • L3VPN control plane: bgpctl show summary (Established), bgpctl show rib VPNv4 (routes, labels, mpe).
        • VRF dataplane: route -T <rdomain> -n show and traceroute between CE subnets to confirm forwarding through the MPLS core.

        Troubleshooting #

        • No LDP neighbors. Ensure MPLS is enabled on both ends of the link, the underlay IP is up, and the interface is listed in ldpd.conf. Check discovery/transport preferences and GTSM if using multi-hop.
        • Labels missing for connected routes. Review ldpctl show lib. Consider explicit-null yes for specific paths that require EXP/ECN handling.
        • L3VPN routes not present in VRF. Confirm mpe is in the correct rdomain with a /32 address and mplslabel, and that neighbors negotiate the VPN AFI/SAFI (announce IPv4 vpn).
        • Pseudowire down. Verify matching pw-id, correct neighbor-id (LSR-ID), and consistent MTU. Adjust control word (pwecw) or flow-aware transport (-pwefat) as needed on mpw(4).
        • MTU black holes. MPLS adds 4 bytes per label (two labels are common). Lower the payload MTU or raise the underlay MTU where possible; re-test with large pings.

        See Also #

        • Networking
        • OpenBGPD
        • Related: Reference Architectures
        • Related: High Availability and State Replication
        Report a bug
        • Synopsis
        • Design Considerations
        • Configuration
          • 1) Enable MPLS on transit interfaces and bring up LDP (both PEs)
          • 2) Verify label distribution across the core
          • 3) L3 MPLS VPN (PE-CE) with mpe(4) and OpenBGPD
          • 4) L2 VPLS using mpw(4) pseudowires and bridge(4)
        • Verification
        • Troubleshooting
        • See Also