Try running OSPF with FR Routing on Docker

Introduction

It seems that there is surprisingly little information, so I will write it here. I think Docker + FR Routing is a good option when you want to try routing with as little resource as possible, such as on a personal computer.

Premise

As shown in the figure below, build FR Routing as a Docker container and Alpine Linux as a terminal on Ubuntu on VirtualBox.

image.png

The version used is as follows. VirtualBox 6.1 Ubuntu 18.04 Docker 19.03.13 FRRouting 7.5

Network configuration you want to create

Let's create such a minimum network and try to run OSPF.

image.png

Run OSPF with frr1 and frr2, and aim to ping alpine1 → alpine2.

Create Docker network and container

First, refer to this page and create a network (bridge). https://qiita.com/BooookStore/items/5862515209a31658f88c

# docker network create net1 --subnet=172.18.0.0/16
# docker network create net2 --subnet=172.19.0.0/16
# docker network create net3 --subnet=172.20.0.0/16
# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f7691e525fcd        bridge              bridge              local
5df12997a7cf        host                host                local
ad914b22edf4        net1                bridge              local
e7366bce6e2f        net2                bridge              local
9b0317dba894        net3                bridge              local
315847e7b1fe        none                null                local

net1 ~ net3 are completed.

Next, make alpine1 and alpine2. Add --privileged to edit the routing table.

# docker run -dit --name alpine1 --hostname alpine1 --privileged --net net1 alpine
# docker run -dit --name alpine2 --hostname alpine2 --privileged --net net3 alpine

Create frr1 and frr2 and connect to net1 and net2, net2 and net3 respectively. It doesn't seem to work without --privileged.

# docker run -dit --name frr1 --hostname frr1 --privileged --net net1 frrouting/frr:v7.5.0
# docker network connect net2 frr1
# docker run -dit --name frr2 --hostname frr2 --privileged --net net2 frrouting/frr:v7.5.0
# docker network connect net3 frr2

Alpine settings

Enter alpine1 and check the routing table.

# docker exec -it alpine1 /bin/sh
/ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.18.0.1      0.0.0.0         UG    0      0        0 eth0
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

The default gateway is bridge (172.18.0.1), so change it to frr1.

/ # route add default gw 172.18.0.3
/ # route del default gw 172.18.0.1
/ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.18.0.3      0.0.0.0         UG    0      0        0 eth0
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

/ # exit

alpine2 changes the default gateway as well.

# docker exec -it alpine2 /bin/sh
/ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.20.0.1      0.0.0.0         UG    0      0        0 eth0
172.20.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

/ # route add default gw 172.20.0.3
/ # route del default gw 172.20.0.1
/ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.20.0.3      0.0.0.0         UG    0      0        0 eth0
172.20.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

/ # exit

Make sure that you can't ping alpine1 → alpine2 yet.

# docker exec -it alpine1 /bin/sh
/ # ping 172.20.0.2
PING 172.20.0.2 (172.20.0.2): 56 data bytes
^C
--- 172.20.0.2 ping statistics ---
6 packets transmitted, 0 packets received, 100% packet loss

FR Routing settings

frr1 settings

Enter frr1 and set the routing.

# docker exec -it frr1 /bin/sh
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /sbin/tini -- /usr/lib/frr/docker-start
    6 root      0:00 tail -f /dev/null
   21 root      0:00 /usr/lib/frr/watchfrr -d -F traditional zebra staticd
   33 frr       0:00 /usr/lib/frr/zebra -d -F traditional -A 127.0.0.1 -s 90000000
   38 frr       0:00 /usr/lib/frr/staticd -d -F traditional -A 127.0.0.1
   40 root      0:00 /bin/sh
   46 root      0:00 ps

You can see that watchfrr, zebra, and staticd are already running. ospf is not working by default.

After this, we will configure the router using vtysh, but before that, create /etc/frr/vtysh.conf as a preset. Without this file, when you start vtysh,

/ # vtysh
% Can't open configuration file /etc/frr/vtysh.conf due to 'No such file or directory'.

Get angry like.

/ # cp /etc/frr/vtysh.conf.sample /etc/frr/vtysh.conf

By the way, I also set integrated-vtysh-config. In FRRouting, you can choose whether to use /etc/frr/*.conf for each daemon as a configuration file or to put them together in /etc/frr/frr.conf. I want to summarize this time, so set integrated-vtysh-config. Official docs also seems to recommend integrated.

/etc/frr/vtysh.conf


!
! Sample configuration file for vtysh.
!
!service integrated-vtysh-config
!hostname quagga-router
!username root nopassword
!
service integrated-vtysh-config

Added the last line.

Enter vtysh and check various settings.

/ # vtysh

Hello, this is FRRouting (version 7.5_git).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

frr1# show run
Building configuration...

Current configuration:
!
frr version 7.5_git
frr defaults traditional
hostname frr1
no ipv6 forwarding
service integrated-vtysh-config
!
line vty
!
end

frr1# show int brief
Interface       Status  VRF             Addresses
---------       ------  ---             ---------
eth0            up      default         172.18.0.3/16
eth1            up      default         172.19.0.2/16
lo              up      default

frr1# show ip route
Codes: K - kernel route, C - connected, S - static, R - RIP,
       O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
       F - PBR, f - OpenFabric,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup

K>* 0.0.0.0/0 [0/0] via 172.18.0.1, eth0, 00:01:54
C>* 172.18.0.0/16 is directly connected, eth0, 00:01:54
C>* 172.19.0.0/16 is directly connected, eth1, 00:01:49

Edit the config file (/ etc/frr/daemons) to start ospfd with ospfd = yes.

/etc/frr/daemons


# ATTENTION:
#
# When activating a daemon for the first time, a config file, even if it is
# empty, has to be present *and* be owned by the user and group "frr", else
# the daemon will not be started by /etc/init.d/frr. The permissions should
# be u=rw,g=r,o=.
# When using "vtysh" such a config file is also needed. It should be owned by
# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
#
# The watchfrr, zebra and staticd daemons are always started.
#
bgpd=no
ospfd=yes
ospf6d=no
ripd=no
The following is omitted

To reflect the settings, exit frr1 once and restart FRR. (Note that it is not /etc/init.d/frr restart in the container) (Addition: It seems that all processes can be restarted by /usr/lib/frr/frrinit.sh restart in the container.)

/ # exit
# docker restart frr1
frr1

Enter frr1 again and check.

# docker exec -it frr1 /bin/sh
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /sbin/tini -- /usr/lib/frr/docker-start
    7 root      0:00 tail -f /dev/null
   14 root      0:00 /usr/lib/frr/watchfrr -d -F traditional zebra ospfd staticd
   32 frr       0:00 /usr/lib/frr/zebra -d -F traditional -A 127.0.0.1 -s 90000000
   37 frr       0:00 /usr/lib/frr/ospfd -d -F traditional -A 127.0.0.1
   40 frr       0:00 /usr/lib/frr/staticd -d -F traditional -A 127.0.0.1
   42 root      0:00 /bin/sh
   48 root      0:00 ps

ospfd is running.

Now, let's set ospf on vtysh.

/ # vtysh

Hello, this is FRRouting (version 7.5_git).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

frr1# conf t
frr1(config)# interface lo
frr1(config-if)# ip address 1.1.1.1/32
frr1(config-if)# exit
frr1(config)# router ospf
frr1(config-router)# router-info area 0.0.0.0
frr1(config-router)# network 172.18.0.0/16 area 0.0.0.0
frr1(config-router)# network 172.19.0.0/16 area 0.0.0.0
frr1(config-router)# end
frr1# show run
Building configuration...

Current configuration:
!
frr version 7.5_git
frr defaults traditional
hostname frr1
no ipv6 forwarding
service integrated-vtysh-config
!
interface lo
 ip address 1.1.1.1/32
!
router ospf
 network 172.18.0.0/16 area 0.0.0.0
 network 172.19.0.0/16 area 0.0.0.0
 router-info area
!
line vty
!
end

It has been set. Also check the show ip route.

frr1# show ip route
Codes: K - kernel route, C - connected, S - static, R - RIP,
       O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
       F - PBR, f - OpenFabric,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup

K>* 0.0.0.0/0 [0/0] via 172.18.0.1, eth0, 00:03:30
C>* 1.1.1.1/32 is directly connected, lo, 00:01:54
O   172.18.0.0/16 [110/10] is directly connected, eth0, weight 1, 00:00:43
C>* 172.18.0.0/16 is directly connected, eth0, 00:03:30
O   172.19.0.0/16 [110/10] is directly connected, eth1, weight 1, 00:00:37
C>* 172.19.0.0/16 is directly connected, eth1, 00:03:30

Persist the settings (if necessary).

frr1# write mem
Note: this version of vtysh never writes vtysh.conf
Building Configuration...
Integrated configuration saved to /etc/frr/frr.conf
[OK]
/ # cat /etc/frr/frr.conf
frr version 7.5_git
frr defaults traditional
hostname frr1
no ipv6 forwarding
service integrated-vtysh-config
!
interface lo
 ip address 1.1.1.1/32
!
router ospf
 network 172.18.0.0/16 area 0.0.0.0
 network 172.19.0.0/16 area 0.0.0.0
 router-info area
!
line vty
!

Written in frr.conf.

frr2 settings

Set frr2 in the same way. (Settings in /etc/frr/vtysh.conf,/etc/frr/daemons → FRR restart part is omitted)

/ # vtysh

Hello, this is FRRouting (version 7.5_git).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

frr2# conf t
frr2(config)# interface lo
frr2(config-if)# ip address 2.2.2.2/32
frr2(config-if)# exit
frr2(config)# router ospf
frr2(config-router)# router-info area 0.0.0.0
frr2(config-router)# network 172.19.0.0/16 area 0.0.0.0
frr2(config-router)# network 172.20.0.0/16 area 0.0.0.0
frr2(config-router)# end

It also persists the frr2 settings (if needed).

With the settings up to this point, if you enter frr1 and check the ip route, 172.20.0.0/16 is added in OSPF.

frr1# show ip route
Codes: K - kernel route, C - connected, S - static, R - RIP,
       O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
       F - PBR, f - OpenFabric,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup

K>* 0.0.0.0/0 [0/0] via 172.18.0.1, eth0, 00:49:06
C>* 1.1.1.1/32 is directly connected, lo, 00:47:30
O   172.18.0.0/16 [110/10] is directly connected, eth0, weight 1, 00:46:19
C>* 172.18.0.0/16 is directly connected, eth0, 00:49:06
O   172.19.0.0/16 [110/10] is directly connected, eth1, weight 1, 00:46:13
C>* 172.19.0.0/16 is directly connected, eth1, 00:49:06
O>* 172.20.0.0/16 [110/20] via 172.19.0.3, eth1, weight 1, 00:04:26

The neighbor is also properly recognized.

frr1# show ip ospf neighbor

Neighbor ID     Pri State           Dead Time Address         Interface                        RXmtL RqstL DBsmL
2.2.2.2           1 Full/Backup       34.411s 172.19.0.3      eth1:172.19.0.2                      0     0     0

Try to ping alpine1 → alpine2.

# docker exec -it alpine1 /bin/sh
/ # ping 172.20.0.2
PING 172.20.0.2 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=62 time=0.386 ms
64 bytes from 172.20.0.2: seq=1 ttl=62 time=0.468 ms
64 bytes from 172.20.0.2: seq=2 ttl=62 time=0.467 ms
64 bytes from 172.20.0.2: seq=3 ttl=62 time=0.464 ms
^C
--- 172.20.0.2 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.386/0.446/0.468 ms

I passed!

Postscript

I made it docker-compose. If you want to make it in an instant, please. https://github.com/tkna/docker_frrouting

reference

Recommended Posts

Try running OSPF with FR Routing on Docker
Try running MPLS-VPN with FR Routing on Docker
Try running cloudera manager with docker
Try running Slack's (Classic) Bot with docker
Try WildFly with Docker
Try running an app made with Quarkus on Heroku
Try Docker on Windows 10 Home
I tried running WordPress with docker preview on M1 Mac.
Try using Redmine on Mac docker
WordPress with Docker Compose on CentOS 8
Try Docker on Windows Home (September 2020)
Try running Spring Boot on Kubernetes
Easily try C # 9 (.NET 5) on Docker
Try running SlackBot made with Ruby x Sinatra on AWS Lambda
I tried running Docker on Windows Server 2019
Try running Word2vec model on AWS Lambda
Try running MySql and Blazor with docker-compose
Scraping with puppeteer in Nuxt on Docker.
Starting with installing Docker on EC2 and running Yellowfin in a container
Try using Kong + Konga with Docker Compose.
Try putting Docker in ubuntu on WSL
Build an environment with Docker on AWS
Try the Docker environment on AWS ECS
Launched Redmine with Docker on Raspberry Pi 3
Run Ubuntu + ROS with Docker on Mac
Try building Express + PostgreSQL + Sequelize with Docker [Part 2]
Try running ScalarDB on WSL Ubuntu (Environment Construction)
Introducing Rspec with Ruby on Rails x Docker
Environment construction command memo with Docker on AWS
Keep docker container running with no resident process running
Run JSP Hello World with Tomcat on Docker
Notes on building Rails6 / PostgreSQL with Docker Compose
Update container image with KUSANAGI Runs on Docker
I tried running Ansible on a Docker container
Try building Express + PostgreSQL + Sequelize with Docker [Part 1]
Try using another Servlet container Jetty with Docker
Liberty on Docker
Redmine on Docker
Try running ScalarDB on WSL Ubuntu (Sample application creation)
Compile with Java 6 and test with Java 11 while running Maven on Java 8
Error encountered with notes when deploying docker on rails
[ARM64] Docker server monitoring with New Relic on Docker on RasPi4
Feel free to try Elasticsearch cluster with WSL2 + Docker
Try something like sharding with Spring's Abstract Routing DataSource!
Display ROS application on Docker with GUI on host side
Try connecting to AzureCosmosDB Emulator for Docker with Java
Run Mosquitto with Docker and try WebSocket communication with MQTT
Try running the Embulk command with your Lambda function