We have been using a Perl based BGP script to announce some prefixes — for black hole routing, or to ban IP addresses as a result of law enforcement requests — from a database to the network.

This project was the result of searching for a new BGP daemon that can be hooked into any need and that supports the L3 MPLS VPN Unicast address family.

We have used osrg/gobgp (GoBGP) as a native library for the iBGP connection into our network. GoBGP can be embedded directly as a Go library, so instead of talking to a separate daemon over gRPC we drive the BGP server in-process and feed it routes straight from our database.

The repository for the testing tool is here: github.com/denizaydin/bgpRouteServer

The convergence problem with VPNv4 updates

The current release of osrg/gobgp sends each VPNv4 prefix in a single UPDATE message. If you have a large number of routes, this increases the convergence time considerably.

I changed table/message.go to pack a single UPDATE for VPNv4 routes that share the same route distinguisher (RD) and next-hop. That fork lives at denizaydin/gobgp. Grouping prefixes that share an RD and next-hop into one UPDATE drastically cuts the number of messages on the wire and speeds up convergence when announcing many routes at once.

How the route server works

The tool (bgpRouteServer) is intentionally small — a single main.go that ties together the GoBGP library and a MySQL backend:

  • It opens a BGP session using the osrg/gobgp library.
  • It reads the prefixes to advertise from a MySQL database.
  • On a fixed interval it diffs the database against what is currently advertised, then adds new paths and withdraws removed ones.

The database connection and query are configurable through command-line flags. By default it runs:

1
SELECT prefix AS prefix FROM blackholeprefixes

and re-scans the table every 30 seconds. New rows are advertised with AddPath(); rows that disappear are withdrawn with DeletePath() using the IPv4 VPN route family.

BGP configuration

The BGP server is started in-process with the following settings:

SettingValue
Local AS65000
Router ID10.2.8.12
Neighbor10.2.51.7 (peer AS 65000, iBGP)
Address familiesipv4-unicast, l3vpn-ipv4-unicast
Listen port-1 (do not listen on TCP/179)

Setting the listen port to -1 keeps GoBGP from binding to TCP/179, so the process only initiates the session to the configured neighbor — handy when running it next to other BGP software on the same host.

Route encoding

Each advertised route is built as a labeled VPNv4 path:

FieldValue
Prefix length/32
MPLS label100
Route Distinguisher1:1
Route Targetextended community 1:1 (two-octet AS format)
Next hop10.2.8.12

This script is just for testing purposes. In the production setup each prefix in the database carries its own next-hop, route-target and RD, so the route server pulls those values per row instead of using the fixed 1:1 / 10.2.8.12 defaults shown above. The end result: routes are read from the database and advertised straight into the backbone over a single iBGP session.


The content of this post was created by the author; AI was used for editing and restructuring.