Using BGP for Network Device Configuration Distribution: A Proof of Concept

In the world of network automation and configuration management, we’re constantly seeking elegant solutions for distributing configuration changes across our infrastructure. While there are many established tools and protocols for this purpose, I recently explored an unconventional approach: using BGP (Border Gateway Protocol) as a transport mechanism for device configurations. In this post, I’ll share my proof of concept that demonstrates how BGP can be repurposed for configuration distribution.

The Idea

BGP is traditionally used for exchanging routing information between autonomous systems. However, its extensible nature, particularly its ability to carry custom attributes, makes it an interesting candidate for distributing other types of data. The key advantages of using BGP for configuration distribution include:

  • Built-in peer authentication and session management
  • Reliable transport mechanism
  • Existing network infrastructure support
  • Natural support for hierarchical distribution
%%{init: {'theme': 'dark', 'themeVariables': { 'lineColor': '#ffffff', 'textColor': '#ffffff', 'mainBkg': '#2b2b2b', 'nodeBkg': '#2b2b2b', 'nodeTextColor': '#ffffff', 'noteBkgColor': '#1f1f1f', 'noteTextColor': '#ffffff', 'messageFontColor': '#ffffff', 'labelTextColor': '#ffffff', 'actorTextColor': '#ffffff', 'signalTextColor': '#ffffff'}}}%%
sequenceDiagram
    participant Publisher as BGP Publisher (AS 65003)
    participant BGP as BGP Network
    participant Receiver as BGP Receiver (AS 65002)
    
    Note over Publisher: Create DeviceConfig
    Note over Publisher: JSON encode config
    
    Publisher->>+BGP: StartBGP (172.20.0.2:179)
    Publisher->>+BGP: AddPeer (172.20.0.3)
    
    Receiver->>+BGP: StartBGP (172.20.0.3)
    Receiver->>+BGP: AddPeer (172.20.0.2)
    
    Note over Publisher,Receiver: BGP Session Established
    
    Publisher->>BGP: Create BGP Update
    Note over Publisher: Add attributes:
    Note over Publisher: - NLRI (192.168.1.0/24)
    Note over Publisher: - Origin (IGP)
    Note over Publisher: - NextHop (172.20.0.2)
    Note over Publisher: - Custom Attr Type 99
    
    BGP->>Receiver: BGP Update Message
    
    activate Receiver
    Note over Receiver: Process BGP Update
    Note over Receiver: Extract Custom Attribute
    Note over Receiver: JSON decode config
    Note over Receiver: Process Device Config
    deactivate Receiver
    
    Note over Receiver: Configuration Ready:
    Note over Receiver: - Device ID
    Note over Receiver: - Interface
    Note over Receiver: - IP Address
    Note over Receiver: - Netmask

The Proof of Concept

I created a simple proof of concept using GoBGP, a pure Go implementation of BGP. The system consists of two components:

  1. A configuration publisher (BGP speaker)
  2. A configuration receiver (BGP client)

The Configuration Model

First, I defined a simple configuration structure that represents interface configuration data:

type DeviceConfig struct {
    DeviceID string `json:"device_id"`
    Config   struct {
        Interface string `json:"interface"`
        IPAddress string `json:"ip_address"`
        Netmask   string `json:"netmask"`
    } `json:"config"`
}

This structure allows us to specify basic interface configuration parameters, but it could be extended to include any type of device configuration.

The Server

The server runs a BGP speaker that:

  • Establishes a BGP session with ASN 65003
  • Connects to a peer (the receiver) in ASN 65002
  • Encodes configuration data as JSON
  • Embeds the configuration in a custom BGP attribute (type 99)
  • Announces the configuration using a BGP UPDATE message

The clever part here is how we embed the configuration data. We use BGP’s extensible attribute system by creating a custom attribute (type 99) that carries our JSON-encoded configuration data:

a1, _ := apb.New(&api.UnknownAttribute{
    Flags: uint32(bgp.BGP_ATTR_FLAG_OPTIONAL | bgp.BGP_ATTR_FLAG_TRANSITIVE),
    Type:  99,
    Value: configBytes,
})

The Client

The client component:

  • Runs a BGP speaker in ASN 65002
  • Establishes a peering session with the publisher
  • Watches for BGP updates
  • Extracts and decodes configuration data from custom attributes
  • Processes the received configuration

The client uses GoBGP’s event watching system to monitor for updates:

s.WatchEvent(context.Background(), &api.WatchEventRequest{
    Table: &api.WatchEventRequest_Table{
        Filters: []*api.WatchEventRequest_Table_Filter{
            {
                Type: api.WatchEventRequest_Table_Filter_BEST,
            },
        },
    },
}, func(r *api.WatchEventResponse) {
    // Process updates...
})

The Result

We can run the server and client in docker containers and see the configuration being distributed:

docker compose up

[+] Running 2/0
 ✔ Container bgpfig-bgp-server-1  Created                                                                                                          0.0s
 ✔ Container bgpfig-bgp-client-1  Created                                                                                                          0.0s
Attaching to bgp-client-1, bgp-server-1
bgp-server-1  | time="2024-12-12T13:40:45Z" level=info msg="Add a peer configuration" Key=172.20.0.3 Topic=Peer
bgp-server-1  | 2024/12/12 13:40:45 Sending path update with attributes: [[type.googleapis.com/apipb.OriginAttribute]:{} [type.googleapis.com/apipb.NextHopAttribute]:{next_hop:"172.20.0.2"} [type.googleapis.com/apipb.UnknownAttribute]:{flags:192 type:99 value:"{\"device_id\":\"router1\",\"config\":{\"interface\":\"GigabitEthernet0/1\",\"ip_address\":\"192.168.1.1\",\"netmask\":\"255.255.255.0\"}}"}]
bgp-server-1  | BGP speaker is running...
bgp-client-1  | time="2024-12-12T13:40:45Z" level=info msg="Add a peer configuration" Key=172.20.0.2 Topic=Peer
bgp-server-1  | time="2024-12-12T13:40:54Z" level=info msg="Peer Up" Key=172.20.0.3 State=BGP_FSM_OPENCONFIRM Topic=Peer
bgp-client-1  | time="2024-12-12T13:40:54Z" level=info msg="Peer Up" Key=172.20.0.2 State=BGP_FSM_OPENCONFIRM Topic=Peer
bgp-client-1  | Received path: nlri:{[type.googleapis.com/apipb.IPAddressPrefix]:{prefix_len:24 prefix:"192.168.1.0"}} pattrs:{[type.googleapis.com/apipb.OriginAttribute]:{}} pattrs:{[type.googleapis.com/apipb.AsPathAttribute]:{segments:{type:AS_SEQUENCE numbers:65003}}} pattrs:{[type.googleapis.com/apipb.NextHopAttribute]:{next_hop:"172.20.0.2"}} pattrs:{[type.googleapis.com/apipb.UnknownAttribute]:{flags:192 type:99 value:"{\"device_id\":\"router1\",\"config\":{\"interface\":\"GigabitEthernet0/1\",\"ip_address\":\"192.168.1.1\",\"netmask\":\"255.255.255.0\"}}"}} age:{seconds:1734010854} validation:{} family:{afi:AFI_IP safi:SAFI_UNICAST} source_asn:65003 source_id:"172.20.0.2" neighbor_ip:"172.20.0.2" local_identifier:1
bgp-client-1  | Attribute 0: TypeUrl=type.googleapis.com/apipb.OriginAttribute
bgp-client-1  | Attribute 1: TypeUrl=type.googleapis.com/apipb.AsPathAttribute
bgp-client-1  | Attribute 2: TypeUrl=type.googleapis.com/apipb.NextHopAttribute
bgp-client-1  | Attribute 3: TypeUrl=type.googleapis.com/apipb.UnknownAttribute

We can see the server and client establish a BGP session and the configuration being distributed.

Why This Approach is Interesting

This proof of concept demonstrates several interesting possibilities:

  1. Declarative State Distribution: BGP naturally handles the distribution of state information across a network. By extending this to configuration data, we can leverage BGP’s built-in distribution mechanisms.

  2. Infrastructure Reuse: Many networks already run BGP. Using it for configuration distribution means we don’t need to deploy additional infrastructure.

  3. Scalability: BGP is designed to scale across large networks, making it potentially suitable for configuration distribution in large environments.

  4. Real-time Updates: BGP’s update mechanism provides near real-time distribution of changes across the network.

Considerations and Limitations

While this proof of concept is interesting, there are several considerations for real-world use:

  1. Security: In a production environment, you’d want to ensure proper authentication and encryption of the configuration data.

  2. Version Control: The proof of concept doesn’t include version control for configurations, which would be essential in practice.

  3. Validation: You’d want to add validation of configuration data before applying it to devices.

  4. Size Limitations: BGP updates have size limitations that might affect larger configuration payloads.

Future Possibilities

This proof of concept could be extended in several ways:

  1. Adding validation and verification of configurations
  2. Implementing configuration versioning
  3. Adding support for different types of configuration data
  4. Building in rollback capabilities
  5. Adding authentication and encryption for configuration data

Conclusion

While this is just a proof of concept, it demonstrates an interesting possibility for network configuration management. By repurposing BGP’s extensible attribute system, we can create a distributed configuration management system that leverages existing network infrastructure.

The code demonstrates that it’s relatively straightforward to implement this approach, and while it might not be suitable for all use cases, it provides food for thought about alternative approaches to network configuration management.

Remember, sometimes the most interesting solutions come from looking at existing tools in new ways. This experiment with BGP shows that protocols can often be used for purposes beyond their original design, leading to innovative solutions for complex problems.

Source Code