GoBGPのオプション機能"FIB manipulation"を活用して、BGPルータ動作を試してみる

GoBGPを活用することにより、BGPによるルーティング情報を制御することができます。
しかしながら、GoBGP基本機能には、データプレーン機能が提供されていないので、ルーティング情報を用いたIPパケット転送は動作しません。そこで、GoBGPのオプション機能["FIB manipulation"](https://github.com/osrg/gobgp/blob/master/docs/sources/zebra.md)を活用して、Ubuntuサーバを、BGPルータとして動作させてみたいと思います。


# ◼︎ GoBGPとは
Go言語で記述されたBGPエンジンであり、オープンソース["GoBGP"](https://github.com/osrg/gobgp)として提供されております。
最近、流行りのSD-WAN領域へのデプロイを想定して、ホワイトボックススイッチへの搭載を念頭に置いたアーキテクチャになっているようです。
従って、GoBGP活用事例も、キャリアグレードから、エンタープライズ、パーソナルユースなど多岐にわたっているようです。

# ◼︎ 今回のBGP環境整備

まずは、２台のLinux環境を準備しておきます。
BGP構成は、次のような感じです。

```
                        +---------+                      +---------+
+-----+ .1           .2 |         | .1      eBGP      .2 |         | .1           .2 +-----+
| pc1 | +-------------+ | GoBGP-1 | +------------------+ | GoBGP-2 | +-------------+ | pc2 |
+-----+  172.16.0.0/24  |         |    192.168.0.0/24    |         |  172.16.1.0/24  +-----+
                        +---------+                      +---------+
                        < AS65001 >                      < AS65002 >
```

# ◼︎ まずは、GoBGP構築準備から ...
GoBGPの環境構築は、ライブラリ依存関係を意識したりする必要がなく、至ってシンプルにインストールすることができます。ちなみに、今回の動作確認では、Ubuntu Server版に、GoBGPをインストールしました。

```
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS"
```
以下、"GoBGP-1"側の構築手順を記述します。

## (1) Linux基本設定

- Linuxネットワーク設定

```
$ sudo vi /etc/network/interfaces

...(snip)
auto eth1
iface eth1 inet static
address 192.168.0.1
netmask 255.255.255.0

auto eth2
iface eth2 inet static
address 172.16.0.2
netmask 255.255.255.0
```

- IPv4フォワーディング有効化

```
$ sudo vi /etc/sysctl.conf

...(snip)
net.ipv4.ip_forward=1

$ sudo sysctl -p /etc/sysctl.conf
net.ipv4.ip_forward = 1
```

- golangのインストール

```
$ vi $HOME/.profile

...(snip)
export GOPATH=$HOME/golang
export PATH=$GOPATH/bin:/usr/local/go/bin:$PATH

$ wget --no-check-certificate https://storage.googleapis.com/golang/go1.6.2.linux-amd64.tar.gz
$ sudo tar -C /usr/local -xzf go1.6.2.linux-amd64.tar.gz
$ mkdir $HOME/golang
$ source .profile

$ go version
go version go1.6.2 linux/amd64
```

## (2) GoBGP基本設定

- まずは、quagga環境を整備しておきます。

```
$ sudo apt-get install quagga
$ cd /etc/quagga/
$ sudo vi daemons

...(snip)
zebra=yes

$ sudo cp /usr/share/doc/quagga/examples/zebra.conf.sample /etc/quagga/zebra.conf


$ sudo /etc/init.d/quagga restart
Stopping Quagga monitor daemon: (watchquagga).
Stopping Quagga daemons (prio:0): (zebra) (bgpd) (ripd) (ripngd) (ospfd) (ospf6d) (isisd) (babeld).
Removing all routes made by zebra.
Loading capability module if not yet done.
Starting Quagga daemons (prio:10): zebra.
Starting Quagga monitor daemon: watchquagga.
```

- GoBGPをインストールします。

```
$ sudo apt-get update
$ sudo apt-get install git
$ go get -u github.com/osrg/gobgp/gobgpd
$ go get -u github.com/osrg/gobgp/gobgp
```

- GoBGP設定ファイルを作成します。

```text:$HOME/golang/bin/gobgpd.conf
[global]
 [global.config]
   as = 65001
   router-id = "192.168.0.1"
[zebra]
 [zebra.config]
   enabled = true
   url = "unix:/var/run/quagga/zserv.api"

[[neighbors]]
 [neighbors.config]
   peer-type = "external"
   neighbor-address = "192.168.0.2"
   peer-as = 65002
   local-as = 65001
[[neighbors.afi-safis]]
 [neighbors.afi-safis.config]
   afi-safi-name = "ipv4-unicast"
```

# ◼︎ いよいよ、BGPルータとしての動作を確認してみる
なお、”GoBGP-2”側は、以下の手順相当を事前に実施しておきます。

## (1) GoBGPを起動する

- 早速、GoBGP設定ファイルを指定して、GoBGPデーモンを起動します。

```
$ cd $GOPATH/bin
$ sudo ./gobgpd -f gobgpd.conf 
{"level":"info","msg":"gobgpd started","time":"2016-05-01T08:39:14+09:00"}
{"level":"info","msg":"finished reading the config file","time":"2016-05-01T08:39:14+09:00"}
{"level":"info","msg":"Peer 192.168.0.2 is added","time":"2016-05-01T08:39:14+09:00"}
{"level":"info","msg":"Add a peer configuration for 192.168.0.2","time":"2016-05-01T08:39:14+09:00"}
{"Key":"192.168.0.2","State":"BGP_FSM_OPENCONFIRM","Topic":"Peer","level":"info","msg":"Peer Up","time":"2016-05-01T08:40:23+09:00"}
```

- 別ターミナルより、gobgpコマンドを用いて、BGP隣接状態を確認します。

```
$ gobgp neighbor
Peer                AS  Up/Down State       |#Advertised Received Accepted
192.168.0.2      65002 00:02:03 Establ      |          0        1        1
```

- gobgpコマンドを用いて、BGPテーブルを確認します。

```
$ gobgp global rib
    Network             Next Hop             AS_PATH              Age        Attrs
*>  172.16.1.0/24       192.168.0.2          65002                00:00:05   [{Origin: ?}]
```

- gobgpコマンドを用いて、BGP経路を追加します。

```
$ gobgp global rib add 172.16.0.0/24
```

- 再度、BGPテーブルを確認します。

```
$ gobgp global rib
    Network             Next Hop             AS_PATH              Age        Attrs
*>  172.16.0.0/24       0.0.0.0                                   00:00:05   [{Origin: ?}]
*>  172.16.1.0/24       192.168.0.2          65002                00:01:40   [{Origin: ?}]
```

- Linuxのルーティング情報も確認しておきます。

```
$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.195.2   0.0.0.0         UG    0      0        0 eth0
172.16.0.0      0.0.0.0         255.255.255.0   U     0      0        0 eth2
172.16.1.0      192.168.0.2     255.255.255.0   UG    0      0        0 eth1
192.168.0.0     0.0.0.0         255.255.255.0   U     0      0        0 eth1
192.168.195.0   0.0.0.0         255.255.255.0   U     0      0        0 eth0
```
以上より、先ほど追加したBGP経路と、”GoBGP-2”側から広告されたBGP経路が、Linuxのルーティング情報に注入されている様子が確認できました。

## (2) 実際、エンドエンドで通信してみる
以下、pc1端末での作業を記述します。

- デフォルトルートを確認する。

```
tsubo@pc1:~$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.16.0.2      0.0.0.0         UG    0      0        0 eth1
172.16.0.0      0.0.0.0         255.255.255.0   U     0      0        0 eth1
192.168.195.0   0.0.0.0         255.255.255.0   U     0      0        0 eth0
```

- pc2向けに、エンドエンド通信してみる

```
tsubo@pc1:~$ ping 172.16.1.2
PING 172.16.1.2 (172.16.1.2) 56(84) bytes of data.
64 bytes from 172.16.1.2: icmp_seq=1 ttl=62 time=1.20 ms
64 bytes from 172.16.1.2: icmp_seq=2 ttl=62 time=1.28 ms
64 bytes from 172.16.1.2: icmp_seq=3 ttl=62 time=1.13 ms
64 bytes from 172.16.1.2: icmp_seq=4 ttl=62 time=1.19 ms
64 bytes from 172.16.1.2: icmp_seq=5 ttl=62 time=1.14 ms
^C
--- 172.16.1.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4009ms
rtt min/avg/max/mdev = 1.132/1.192/1.280/0.056 ms
```

はい、想定どおりに、エンドエンドでのping通院も成功しておりますね！

# ◼︎ 最後に
GoBGPのオプション機能"FIB manipulation"を活用して、UbuntuサーバをBGPルータとして動作させることができました。なお、ここで記載している内容は、かなり基本動作の部類になるので、高度なBGP機能を活用したい場合には、"FIB manipulation"では対応が難しい局面が存在しております。
ただ、ホワイトボックススイッチにBGPルーティング機能をデプロイしたい場合、GoBGP活用は、かなり有望だと感じておりますので、もっと、GoBGP活用事例を考えていきたいと思います。