Quick Start
Installation
To get started with bgpipe
, you need to install it on your system, ie. where you want it to proxy or terminate BGP sessions. bgpipe
is a single binary that can be run on any machine with a compatible operating system (preferably Linux). It does not require any additional libraries or dependencies, making it easy to deploy - just copy the binary to your target machine.
You can download pre-built binaries from the GitHub Releases page:
wget https://github.com/bgpfix/bgpipe/releases/latest/download/bgpipe-linux-amd64
chmod +x bgpipe-linux-amd64
sudo mv -f bgpipe-linux-amd64 /usr/local/bin/bgpipe # note (1)
- Make sure that the target directory is in your
$PATH
, or simply rename the binary tobgpipe
and keep executing it from the current directory.
Alternatively, you can compile from source. You need to have Go installed first. Then, you can run:
- Make sure to put the resultant
bgpipe
binary in your$PATH
. Go installs executables in the directory named by the$GOBIN
environment variable, which defaults to$GOPATH/bin
, or$HOME/go/bin
if the$GOPATH
variable is not set.
Running bgpipe
When you run bgpipe
without any arguments, it will print the help message, for example:
Usage: bgpipe [OPTIONS] [--] STAGE1 [OPTIONS] [ARGUMENTS] [--] STAGE2...
Options:
-v, --version print detailed version info and quit
-n, --explain print the pipeline as configured and quit
-l, --log string log level (debug/info/warn/error/disabled) (default "info")
--pprof string bind pprof to given listen address
-e, --events strings log given events ("all" means all events) (default [PARSE,ESTABLISHED,EOR])
-k, --kill strings kill session on any of these events
-i, --stdin read JSON from stdin
-o, --stdout write JSON to stdout
-I, --stdin-wait like --stdin but wait for EVENT_ESTABLISHED
-O, --stdout-wait like --stdout but wait for EVENT_EOR
-2, --short-asn use 2-byte ASN numbers
--caps string use given BGP capabilities (JSON format)
Supported stages (run <stage> -h to get its help)
connect connect to a BGP endpoint over TCP
drop drop messages that match a filter
exec handle messages in a background process
grep drop messages that DO NOT match a filter
limit limit prefix lengths and counts
listen let a BGP client connect over TCP
pipe process messages through a named pipe
read read messages from file or URL
speaker run a simple BGP speaker
stdin read messages from stdin
stdout print messages to stdout
tag add or drop message tags
update modify UPDATE messages
websocket process messages over websocket
write write messages to file
From the above output, you can learn the basic syntax of a pipeline, which is a sequence of stages. Usually the stages are separated by --
characters; otherwise, bgpipe
will try to separate the stages automatically, although this can lead to ambiguities for more complex pipelines. Global bgpipe
options are specified before the first stage, and options for each stage are specified immediately after the stage name.
A stage is a specific processing step in the pipeline, such as connecting to a BGP endpoint, filtering messages, or executing a command. You can think of it as a building block that performs a specific task in the overall message processing flow. In order to learn more about a specific stage, you can run bgpipe <stage> -h
, for example:
$ bgpipe connect -h
Stage usage: connect [OPTIONS] ADDR
Description: connect to a BGP endpoint over TCP
Options:
--timeout duration connect timeout (0 means none) (default 1m0s)
--closed duration half-closed timeout (0 means none) (default 1s)
--md5 string TCP MD5 password
Common Options:
-L, --left operate in the L direction
-R, --right operate in the R direction
-A, --args consume all CLI arguments till --
-W, --wait strings wait for given event before starting
-S, --stop strings stop after given event is handled
-N, --new string which stage to send new messages to (default "next")
-O, --of string stage output filter (drop non-matching output)
As you can see, the connect
stage has its own set of options, such as --timeout
, --closed
, and --md5
, which are specific to establishing a BGP connection. The common options, such as -L
, -R
, etc. are available for all stages and control how the stage operates in the pipeline context.
By default, all stages operate in the right (-R
) direction, meaning that they process BGP messages flowing from left to right. The direction controls which messages to capture for processing in a stage, and where to send new messages. However, if the last stage connects to a BGP endpoint, by default it will operate in the left (-L
) direction, meaning it will send new messages to the left of the pipeline. Usually, the left-most and/or right-most stage is the one that connects to a BGP endpoint, while the other stages process messages in between. If you want bidirectional processing, use the -L
and -R
options together, ie. -LR
.
Reading MRT files
Let's demonstrate basic message processing by reading MRT files. MRT files are a standard format for storing BGP messages, and bgpipe
can read them from a file or a URL. You can even stream MRT files directly from the RIPE NCC RIS or RouteViews archives.
Below is an example of reading a compressed MRT file from the RIPE NCC RIS archive, filtering it for a specific prefix, and printing the results to stdout:
$ bgpipe \
-- read --mrt https://data.ris.ripe.net/rrc01/latest-update.gz \
-- grep 'prefix ~ 8.0.0.0/8' \
-- stdout
2025-07-04 13:17:47 INF streaming https://data.ris.ripe.net/rrc01/latest-update.gz stage="[1] read"
["R",6826,"2025-07-04T13:05:19.000",74,"UPDATE",{"reach":["8.20.247.0/24","8.26.56.0/24","104.37.179.0/24","199.167.65.0/24"],"attrs":{"ORIGIN":{"flags":"T","value":"IGP"},"ASPATH":{"flags":"T","value":[8218,174,20473,23393]},"NEXTHOP":{"flags":"T","value":"5.57.80.210"},"MED":{"flags":"O","value":4},"COMMUNITY":{"flags":"OT","value":["8218:102","8218:20000","8218:20110"]}}},{"PEER_AS":"8218","PEER_IP":"5.57.80.210","LOCAL_AS":"12654","LOCAL_IP":"5.57.80.4"}]
["R",7431,"2025-07-04T13:05:21.000",77,"UPDATE",{"reach":["8.20.247.0/24","8.26.56.0/24","104.37.179.0/24","199.167.65.0/24"],"attrs":{"ORIGIN":{"flags":"T","value":"IGP"},"ASPATH":{"flags":"T","value":[8218,20473,23393]},"NEXTHOP":{"flags":"T","value":"5.57.80.210"},"MED":{"flags":"O","value":4},"COMMUNITY":{"flags":"OT","value":["8218:102","8218:20000","8218:20110"]},"OTC":{"flags":"OTP","value":"0x00001a79"}}},{"LOCAL_AS":"12654","LOCAL_IP":"5.57.80.4","PEER_AS":"8218","PEER_IP":"5.57.80.210"}]
// ...
In the above, the read
stage streams the latest BGP updates from the rrc01
RIPE RIS collector, uncompresses the data on the fly, and sends back to the pipeline for further processing. Next, the grep
stage captures these messages, applies a BGP message filter (IP prefix must overlap with the 8.0.0.0/8
IPv4 prefix), and sends accepted messages to the next stage (non-matching traffic is dropped). Finally, the stdout
stage converts the messages to JSON format and prints them to stdout.
bgpipe
provides the --explain
(short -n
) debugging option that prints the pipeline as configured, but without actually running anything. For example:
$ bgpipe -n \
-- read --mrt https://data.ris.ripe.net/rrc01/latest-update.gz \
-- grep 'prefix ~ 8.0.0.0/8' \
-- stdout
--> MESSAGES FLOWING RIGHT -->
[1] read --mrt https://data.ris.ripe.net/rrc01/latest-update.gz
writes messages to pipeline inputs=1
[2] grep prefix ~ 8.0.0.0/8
reads messages from pipeline callbacks=1 types=[ALL]
[3] stdout
reads messages from pipeline callbacks=1 types=[ALL]
<-- MESSAGES FLOWING LEFT <--
(none)
Last but not least, instead of putting the stdout
stage explicitly in the pipeline, you can use the --stdout
(short -o
) option to bgpipe
, in order to print BGP messages to stdout automatically. It will print all messages that make it to the very end of the left-hand side and right-hand side of the pipeline, ie. all messages that are not dropped by any stage.
$ bgpipe -o \
-- read --mrt https://data.ris.ripe.net/rrc01/latest-update.gz \
-- grep 'prefix ~ 8.0.0.0/8'
...
Connecting to a BGP speaker
Now that you know how to read MRT files, let's connect to a BGP speaker and process messages in real-time. You can use the connect
stage to establish the TCP connection, and the speaker
stage to open and maintain a BGP session.
We will use this opportunity to connect to one of the BGP projects run by Ćukasz Bromirski. The following command connects to the BGP Blackholing with Flowspec endpoint and prints the conversation to stdout, which demonstrates that bgpipe
supports Flowspec:
$ bgpipe -o \
-- speaker --active --asn 65055 \
-- connect 85.232.240.180
2025-07-11 10:47:20 INF dialing 85.232.240.180:179 stage="[2] connect"
2025-07-11 10:47:20 INF connection R_LOCAL = 192.168.200.202:59438 stage="[2] connect"
2025-07-11 10:47:20 INF connection R_REMOTE = 85.232.240.180:179 stage="[2] connect"
2025-07-11 10:47:20 INF connected 192.168.200.202:59438 -> 85.232.240.180:179 stage="[2] connect"
["R",1,"2025-07-11T08:47:20.650",-1,"OPEN",{"bgp":4,"asn":65055,"id":"0.0.0.1","hold":90,"caps":{"MP":["IPV4/UNICAST","IPV4/FLOWSPEC","IPV6/UNICAST","IPV6/FLOWSPEC"],"ROUTE_REFRESH":true,"EXTENDED_MESSAGE":true,"AS4":65055}},{}]
["L",1,"2025-07-11T08:47:22.659",56,"OPEN",{"bgp":4,"asn":65055,"id":"85.232.240.180","hold":7200,"caps":{"MP":["IPV4/FLOWSPEC"],"ROUTE_REFRESH":true,"EXTENDED_NEXTHOP":["IPV4/UNICAST/IPV6","IPV4/MULTICAST/IPV6","IPV4/MPLS_VPN/IPV6"],"AS4":65055,"PRE_ROUTE_REFRESH":true}},{}]
["L",2,"2025-07-11T08:47:22.659",0,"KEEPALIVE",null,{}]
["R",2,"2025-07-11T08:47:22.659",0,"KEEPALIVE",null,{}]
2025-07-11 10:47:22 INF negotiated session capabilities caps="{\"MP\":[\"IPV4/FLOWSPEC\"],\"ROUTE_REFRESH\":true,\"AS4\":65055}"
2025-07-11 10:47:22 INF event bgpfix/pipe.ESTABLISHED evseq=15 vals=[1752223642]
...
Proxying BGP sessions
Finally, let's see how to use bgpipe
to proxy BGP sessions. You can use the listen
stage to accept incoming connections and the connect
stage to forward BGP messages to another router. This allows you to create a transparent proxy that can filter, modify, or log BGP messages.
For example, let's use the Vultr's BGP feature, where you already have a local BIRD instance running on a VM, with the following configuration:
log syslog all;
router id 1.2.3.4;
protocol bgp vultr
{
local as 123;
source address 1.2.3.4;
ipv4 {
import none;
export none;
};
graceful restart on;
multihop 2;
neighbor 169.254.169.254 as 64515;
password "solarwinds123";
}
Let's say you'd like to see all UPDATEs that match a specific ASN 15169
. First, let's run a bgpipe
proxy that listens on port 1790
and connects to the upstream router with TCP-MD5 when its client connects.
$ bgpipe \
-- connect --wait listen --md5 "solarwinds123" 169.254.169.254 \
-- stdout -LR --if "as_path = 15169" \
-- listen localhost:1790
2025-07-11 09:16:47 INF listening on 127.0.0.1:1790 stage="[3] listen"
Now let's reconfigure the BIRD instance to connect to bgpipe
instead of the upstream router. Change the neighbor
line in the BIRD configuration to point to localhost:1790
:
// ...
protocol bgp vultr
{
// ...
neighbor 127.0.0.1 port 1790 as 64515;
// password ""; // no password needed
}
Finally, restart your BIRD instance and you should see bgpipe
reporting new connections, followed by JSON representations of BGP messages matching your filter:
2025-07-11 11:23:45 INF connection R_LOCAL = 127.0.0.1:1790 stage="[3] listen"
2025-07-11 11:23:45 INF connection R_REMOTE = 1.2.3.4:36297 stage="[3] listen"
2025-07-11 11:23:45 INF connected 127.0.0.1:1790 -> 1.2.3.4:36297 stage="[3] listen"
2025-07-11 11:23:45 INF dialing 169.254.169.254:179 stage="[1] connect"
2025-07-11 11:23:45 INF connection L_LOCAL = 1.2.3.4:33514 stage="[1] connect"
2025-07-11 11:23:45 INF connection L_REMOTE = 169.254.169.254:179 stage="[1] connect"
2025-07-11 11:23:45 INF connected 1.2.3.4:33514 -> 169.254.169.254:179 stage="[1] connect"
2025-07-11 11:23:46 INF negotiated session capabilities caps="{\"MP\":[\"IPV4/UNICAST\"],\"ROUTE_REFRESH\":true,\"GRACEFUL_RESTART\":true,\"AS4\":64515,\"ENHANCED_ROUTE_REFRESH\":true,\"LLGR\":true}"
2025-07-11 11:23:46 INF event bgpfix/pipe.ESTABLISHED evseq=15 vals=[1752233026]
2025-07-11 11:23:49 INF event bgpfix/pipe.EOR evdir=L evseq=18
["R",243,"2025-07-11T11:23:50.860",1459,"UPDATE",{"reach":[...],"attrs":{"ORIGIN":{"flags":"T","value":"EGP"},"ASPATH":{"flags":"TX","value":[64515,65534,20473,15169,396982]},"NEXTHOP":{"flags":"T","value":"169.254.169.254"},"COMMUNITY":{"flags":"OT","value":["20473:300","20473:15169","64515:44"]},"LARGE_COMMUNITY":{"flags":"OT","value":["20473:300:15169"]}}},{}]
...
Conclusion
For more practical pipelines and advanced use cases, check out the examples page. It contains real-world bgpipe command lines for BGP monitoring, proxying, filtering, and more.
Happy bgpiping!