libbgp is a C11 library for working with BGP-4 packets and small BGP control
plane building blocks. It provides public C APIs for packet parsing and
encoding, path attributes, incremental stream framing, IPv4 and IPv6 RIBs,
route filters, an event bus, output handlers, and a BGP finite state machine
(FSM).
The project is intended for applications that need to embed BGP protocol handling, inspect or generate BGP messages, maintain a local route table, or build simple peering tools. It is not a complete router daemon by itself: it does not provide a production multi-peer process, configuration language, policy engine, kernel FIB programming, persistence, or an operational CLI. The examples show how to connect the library to TCP sockets, but long-running process management remains the application's responsibility.
Public headers live under include/libbgp/. Applications can include the
umbrella header:
#include <libbgp/libbgp.h>- BGP message parsing and encoding for OPEN, UPDATE, KEEPALIVE, and NOTIFICATION packets.
- Incremental stream framing with
libbgp_sink, including fragmented packet reassembly and queued packet delivery. - OPEN capability support for four-octet ASN and MP-BGP capability objects, with unknown capability preservation.
- UPDATE support for classic IPv4 withdrawn routes and IPv4 NLRI.
- Path attribute support for ORIGIN, AS_PATH, NEXT_HOP, MED, LOCAL_PREF, ATOMIC_AGGREGATE, AGGREGATOR, COMMUNITY, AS4_PATH, AS4_AGGREGATOR, MP_REACH_NLRI for IPv6 unicast, MP_UNREACH_NLRI for IPv6 unicast, and unknown optional attributes.
- Four-octet ASN helpers for AS_PATH/AS4_PATH and AGGREGATOR/AS4_AGGREGATOR downgrade and restore workflows.
- IPv4 and IPv6 prefix helpers for wire-format parse/write, comparison, and prefix containment.
- IPv4 and IPv6 RIB storage with insert, local insert, withdraw, discard, route count, longest-prefix lookup, scoped lookup, and best-path selection.
- Route filtering for IPv4 and IPv6 prefixes, AS path contains/origin matches, community matches, negative matches, and ordered permit/deny rules.
- Event bus for session, route, collision, and custom events.
- FSM support for BGP session state transitions, OPEN/KEEPALIVE negotiation, hold/keepalive timers, soft/hard reset, collision handling, route import into RIBs, route advertisement from RIB/event sources, inbound/outbound filters, next-hop checks and rewrites, and optional IPv6 unicast MP-BGP.
- Output handling through either POSIX file descriptors or caller-provided send/receive callbacks.
- Custom global allocator hooks and a configurable logging API.
- Optional
THREADSAFE=1build that enables pthread-backed locks in stateful handles such as RIBs, sinks, filters, event buses, output handlers, logging, and the FSM.
libbgphas FSM/session components, but it is still a library, not a complete BGP speaker daemon.- IPv4 unicast is supported through classic UPDATE NLRI. MP-BGP IPv4 capability negotiation exists in the FSM, but public UPDATE storage is still classic IPv4 NLRI.
- IPv6 unicast is supported through MP_REACH_NLRI and MP_UNREACH_NLRI attributes and the IPv6 RIB/FSM paths. Other AFI/SAFI combinations are not implemented as typed attributes and are preserved as unknown attributes where applicable.
- RIB lookup APIs return borrowed internal route pointers. They remain valid
only until the next mutating operation on the same RIB or until destroy.
In
THREADSAFE=1builds, callers still need external synchronization if they keep borrowed route pointers while another thread may mutate the RIB. - The thread-safe build protects library handle internals; it does not make an application-level BGP design automatically race-free.
libbgp uses the root Makefile. There is no CMake or Meson build file in
the current tree.
Requirements:
- C11 compiler, such as GCC or Clang
make- POSIX socket APIs for the bundled examples
- Doxygen, optional, for API documentation generation
On Debian-based systems:
sudo apt install gcc make doxygenBuild static and shared libraries:
makeThe default build writes:
build/threadsafe-0/libbgp.abuild/threadsafe-0/libbgp.so- compatibility copies at
build/libbgp.aandbuild/libbgp.so
The installed library name is bgp, so installed consumers typically link with
-lbgp and include headers from -I<PREFIX>/include.
Build the pthread-backed variant:
make THREADSAFE=1Add compiler or linker flags with CFLAGS_EXTRA and LDFLAGS_EXTRA:
make CFLAGS_EXTRA="-O2 -g"Install headers and libraries:
sudo make installUse PREFIX and DESTDIR for staged installs:
make PREFIX=/usr DESTDIR="$PWD/pkg" installClean generated build outputs:
make cleanRun all unit tests:
make testCompile-check every public header:
make headersBuild examples:
make examplesRun the benchmark binary:
make bench
build/threadsafe-0/bench/benchRun the full project verification target:
make verifymake verify performs a clean build, builds libraries, compile-checks public
headers, runs normal tests, runs THREADSAFE=1 tests, runs address/undefined
behavior sanitizer tests through CFLAGS_EXTRA/LDFLAGS_EXTRA, builds
examples, and checks exported symbols. make release-check is an alias for the
same verification flow.
There is no dedicated coverage or fuzz target in the current Makefile.
Examples are under examples/ and build with:
make examplesThe binaries are written to build/threadsafe-$(THREADSAFE)/examples/.
Current examples:
sink_fragmented_stream.c: feeds a KEEPALIVE packet tolibbgp_sinkin fragments, then pops the completed packet.open_capabilities.c: builds an OPEN with four-octet ASN and IPv6 unicast MP-BGP capabilities, encodes it, then parses the capabilities back.ipv6_mp_update.c: constructs an IPv6 unicast MP_REACH_NLRI UPDATE and parses the encoded packet.out_handler_callback.c: sends an encoded packet through caller-provided output callbacks instead of a file descriptor.event_bus_publish_subscribe.c: subscribes event handlers, publishes route events, and unsubscribes one handler.custom_allocator.c: installs allocator hooks, exercises libbgp allocation, and restores the default allocator.route_withdraw.c: encodes an IPv4 withdraw UPDATE and applies the withdraw to an IPv4 RIB.packet_roundtrip.c: parses a complete BGP KEEPALIVE packet, writes it back to wire format, and checks that the bytes round-trip.update_builder.c: constructs an IPv4 UPDATE with ORIGIN, AS_PATH, NEXT_HOP, and NLRI, encodes it, then parses the encoded packet.rib_filter_walkthrough.c: builds a small IPv4 RIB, performs longest-prefix lookup, and applies a prefix filter decision to the selected route.peer_and_print.c: accepts one TCP peer, parses incoming bytes withlibbgp_sink, feeds packets tolibbgp_fsm, and prints packet type names.route_server.c: accepts one TCP peer using a shared IPv4 RIB and event bus, then prints session and route events produced by the FSM.
Both examples default to TCP port 1179 so they can run without root:
build/threadsafe-0/examples/peer_and_print --port 1179
build/threadsafe-0/examples/route_server --port 1179Use --help on either binary for options. To listen on the standard BGP port,
pass --port 179 and run with the privileges required by your system.
Parse a complete BGP packet:
#include <libbgp/libbgp.h>
int parse_packet(const uint8_t *buf, size_t len)
{
libbgp_packet_t pkt;
size_t consumed = 0;
libbgp_err_t err;
libbgp_packet_init(&pkt);
err = libbgp_packet_parse(&pkt, buf, len, &consumed);
if (err != LIBBGP_OK) {
libbgp_packet_destroy(&pkt);
return -1;
}
/* Inspect pkt.type and pkt.data here. */
libbgp_packet_destroy(&pkt);
return 0;
}Use a stream sink when reading from TCP:
libbgp_sink_t sink;
libbgp_sink_init(&sink);
libbgp_sink_feed(&sink, bytes, byte_count);
while (libbgp_sink_packet_count(&sink) > 0) {
libbgp_packet_t pkt;
libbgp_packet_init(&pkt);
if (libbgp_sink_pop(&sink, &pkt) == LIBBGP_OK) {
/* Pass pkt to libbgp_fsm_on_packet() or inspect it directly. */
}
libbgp_packet_destroy(&pkt);
}
libbgp_sink_destroy(&sink);API documentation can be generated with Doxygen from the repository root:
doxygenDoxyfile writes generated documentation under docs/, including HTML output
under docs/html.
The C11 API preserves the core protocol behavior of the legacy C++ library, including MP-BGP IPv4/IPv6 route-family gating, IPv6 global plus link-local nexthop handling, FSM collision controls, soft/hard reset behavior, negotiated hold-time access, and state-change notifications.
Some legacy C++ convenience APIs are intentionally represented differently in C. Textual prefix construction is handled by the prefix parse APIs, parser details are returned through parse/write result codes, and UPDATE mutation remains available through public message/path-attribute structs plus lower-level helper functions instead of one wrapper per C++ mutator.
The legacy BgpFsm::run(buffer, size) auto-tick wrapper is split into explicit
sink parsing, libbgp_fsm_on_packet(), and libbgp_fsm_tick() calls. The C API
therefore does not need a no_autotick switch. Sink/output failures are returned
as errors instead of exposing the legacy BROKEN state. Logging remains the
standalone C logging API rather than per-object logger injection.
libbgp_fsm_init(fsm, NULL) uses the legacy 120 second hold timer and 40 second
keepalive defaults. When callers pass their own struct libbgp_fsm_config, the
C API uses the field values exactly as provided; it does not merge zero-valued
fields with legacy defaults. A zero-initialized custom config therefore keeps
hold_time and keepalive_time at 0 unless the caller passes NULL or fills
those fields explicitly.
MIT