最近、GoBGPのドキュメンテーションに、オプション機能"GoBGP as a Go Native BGP library"なるものが記載されていることに気が付きました。
「これは、何なんだろう?」という素朴な疑問を、私なりの解釈で解き明かしてみたいと思います。
◼︎ まずは、GoBGP構築準備から ...
次のようなGoBGP環境を作成します。なお、対向BGP Routerに、GoBGPを配備しても問題ありません。
+---------+ (eth1) iBGP +--------+
... ----------+ | GoBGP | +---------------------------------+ | BGP | +---- ...
| | 192.168.0.1/24 192.168.0.2/24 | Router |
+---------+ +--------+
< AS65000 > < AS65000 >
<--- Target ---> <-- out of scope -->
以下、"GoBGP"側の構築手順を記述します。
(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
- 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インストール
- GoBGPをインストールします。
$ sudo apt-get update
$ sudo apt-get install git
$ go get github.com/osrg/gobgp/gobgpd
$ go get github.com/osrg/gobgp/gobgp
◼︎ いろいろな方法で、GoBGPを動作させてみる
GoBGPを動作させたことがある方にとっては、GoBGP設定ファイルを用いたGoBGP起動方法を思い浮かべることだと思います。
ここでは、いろいろなGoBGP起動方法について、GoBGP動作結果を比較してみたいと思います。
(GoBGP起動方法1) gobgp設定ファイルから、GoBGP起動してBGPピアを開設してみる
こちらは、オーソドックスなGoBGP起動方法ですよね。
- 事前に、GoBGP設定ファイルを作成しておきます
[[neighbors]]
[neighbors.config]
neighbor-address = "192.168.0.2"
peer-as = 65000
local-as = 65000
[global.config]
as = 65000
router-id = "192.168.0.1"
- gobgpdを起動します
$ cd $GOPATH/bin
$ sudo ./gobgpd -f gobgpd.conf -l debug -p
INFO[0000] gobgpd started
INFO[0000] finished reading the config file
INFO[0000] Peer 192.168.0.2 is added
INFO[0000] Add a peer configuration for 192.168.0.2
DEBU[0000] IdleHoldTimer expired Duration=0 Key=192.168.0.2 Topic=Peer
DEBU[0000] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_ACTIVE old=BGP_FSM_IDLE reason=idle-hold-timer-expired
DEBU[0013] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_OPENSENT old=BGP_FSM_ACTIVE reason=new-connection
DEBU[0013] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_OPENCONFIRM old=BGP_FSM_OPENSENT reason=open-msg-received
INFO[0013] Peer Up Key=192.168.0.2 State=BGP_FSM_OPENCONFIRM Topic=Peer
DEBU[0013] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_ESTABLISHED old=BGP_FSM_OPENCONFIRM reason=open-msg-negotiated
DEBU[0013] received update Key=192.168.0.2 Topic=Peer attributes=[{Origin: ?} {Nexthop: 192.168.0.2} {LocalPref: 100}] nlri=[20.20.20.0/24] withdrawals=[]
DEBU[0013] create Destination Key=20.20.20.0/24 Topic=Table
DEBU[0013] Processing destination Key=20.20.20.0/24 Topic=table
DEBU[0013] computeKnownBestPath known pathlist: 1
DEBU[0013] From same AS, ignore. Data={ 20.20.20.0/24 | src: { 192.168.0.2 | as: 65000, id: 192.168.0.2 }, nh: 192.168.0.2 } Key=192.168.0.2 Topic=Peer
DEBU[0043] sent Key=192.168.0.2 State=BGP_FSM_ESTABLISHED Topic=Peer data=&{Header:{Marker:[] Len:19 Type:4} Body:0x1234d78}
DEBU[0073] sent Key=192.168.0.2 State=BGP_FSM_ESTABLISHED Topic=Peer data=&{Header:{Marker:[] Len:19 Type:4} Body:0x1234d78}
DEBU[0103] sent Key=192.168.0.2 State=BGP_FSM_ESTABLISHED Topic=Peer data=&{Header:{Marker:[] Len:19 Type:4} Body:0x1234d78}
- gobgpコマンドから、Peer情報を確認してみます
$ gobgp neighbor 192.168.0.2
BGP neighbor is 192.168.0.2, remote AS 65000
BGP version 4, remote router ID 192.168.0.2
BGP state = BGP_FSM_ESTABLISHED, up for 00:00:10
BGP OutQ = 0, Flops = 0
Hold time is 90, keepalive interval is 30 seconds
Configured hold time is 90, keepalive interval is 30 seconds
Neighbor capabilities:
BGP_CAP_MULTIPROTOCOL:
ipv4-unicast: advertised and received
l2vpn-evpn: received
BGP_CAP_ROUTE_REFRESH: advertised and received
BGP_CAP_FOUR_OCTET_AS_NUMBER: advertised and received
Message statistics:
Sent Rcvd
Opens: 1 1
Notifications: 0 0
Updates: 0 1
Keepalives: 1 1
Route Refesh: 0 0
Discarded: 0 0
Total: 2 3
Route statistics:
Advertised: 0
Received: 1
Accepted: 1
- gobgpコマンドから、rib情報を確認してみます
$ gobgp global rib
Network Next Hop AS_PATH Age Attrs
*> 20.20.20.0/24 192.168.0.2 00:00:38 [{Origin: ?} {LocalPref: 100}]
(GoBGP起動方法2) gobgpコマンドから、BGPピアを開設してみる
続いての起動方法は、GoBGP設定ファイルを使用せずに、gobgpコマンドで、BGPピア開設に必要な設定情報を投入する方法です。
- gobgpdを起動します
$ cd $GOPATH/bin
$ sudo ./gobgpd -l debug -p
INFO[0000] gobgpd started
- gobgpコマンドから、Global情報を設定します
$ gobgp global as 65000 router-id 192.168.0.1
- gobgpコマンドから、BGP Peer情報を設定します
$ gobgp neighbor add 192.168.0.2 as 65000
- 先ほど起動したgobgpdプロセスのログ出力を確認しておきます
$ sudo ./gobgpd -l debug -p
INFO[0000] gobgpd started
INFO[0007] Add a peer configuration for 192.168.0.2
DEBU[0007] IdleHoldTimer expired Duration=0 Key=192.168.0.2 Topic=Peer
DEBU[0007] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_ACTIVE old=BGP_FSM_IDLE reason=idle-hold-timer-expired
DEBU[0012] accepted a new passive connection from 192.168.0.2
DEBU[0012] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_OPENSENT old=BGP_FSM_ACTIVE reason=new-connection
DEBU[0012] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_OPENCONFIRM old=BGP_FSM_OPENSENT reason=open-msg-received
INFO[0012] Peer Up Key=192.168.0.2 State=BGP_FSM_OPENCONFIRM Topic=Peer
DEBU[0012] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_ESTABLISHED old=BGP_FSM_OPENCONFIRM reason=open-msg-negotiated
DEBU[0012] received update Key=192.168.0.2 Topic=Peer attributes=[{Origin: ?} {Nexthop: 192.168.0.2} {LocalPref: 100}] nlri=[20.20.20.0/24] withdrawals=[]
DEBU[0012] create Destination Key=20.20.20.0/24 Topic=Table
DEBU[0012] Processing destination Key=20.20.20.0/24 Topic=table
DEBU[0012] computeKnownBestPath known pathlist: 1
DEBU[0012] From same AS, ignore. Data={ 20.20.20.0/24 | src: { 192.168.0.2 | as: 65000, id: 192.168.0.2 }, nh: 192.168.0.2 } Key=192.168.0.2 Topic=Peer
DEBU[0042] sent Key=192.168.0.2 State=BGP_FSM_ESTABLISHED Topic=Peer data=&{Header:{Marker:[] Len:19 Type:4} Body:0x1234d78}
DEBU[0072] sent Key=192.168.0.2 State=BGP_FSM_ESTABLISHED Topic=Peer data=&{Header:{Marker:[] Len:19 Type:4} Body:0x1234d78}
DEBU[0102] sent Key=192.168.0.2 State=BGP_FSM_ESTABLISHED Topic=Peer data=&{Header:{Marker:[] Len:19 Type:4} Body:0x1234d78}
- gobgpコマンドから、Peer情報を確認してみます
$ gobgp neighbor 192.168.0.2
BGP neighbor is 192.168.0.2, remote AS 65000
BGP version 4, remote router ID 192.168.0.2
BGP state = BGP_FSM_ESTABLISHED, up for 00:03:29
BGP OutQ = 0, Flops = 0
Hold time is 90, keepalive interval is 30 seconds
Configured hold time is 90, keepalive interval is 30 seconds
Neighbor capabilities:
BGP_CAP_MULTIPROTOCOL:
ipv4-unicast: advertised and received
l2vpn-evpn: received
BGP_CAP_ROUTE_REFRESH: advertised and received
BGP_CAP_FOUR_OCTET_AS_NUMBER: advertised and received
Message statistics:
Sent Rcvd
Opens: 1 1
Notifications: 0 0
Updates: 0 1
Keepalives: 7 7
Route Refesh: 0 0
Discarded: 0 0
Total: 8 9
Route statistics:
Advertised: 0
Received: 1
Accepted: 1
- gobgpコマンドから、rib情報を確認してみます
$ gobgp global rib
Network Next Hop AS_PATH Age Attrs
*> 20.20.20.0/24 192.168.0.2 00:04:38 [{Origin: ?} {LocalPref: 100}]
(GoBGP起動方法3) "GoBGP as a Go Native BGP library"活用により、BGPピアを開設してみる
最後の起動方法として、全く馴染みがない"GoBGP as a Go Native BGP library"を活用して、GoBGPを起動してみます。
- 事前に、サンプルコードを準備しておきます
package main
import (
log "github.com/Sirupsen/logrus"
api "github.com/osrg/gobgp/api"
"github.com/osrg/gobgp/gobgp/cmd"
"github.com/osrg/gobgp/packet/bgp"
gobgp "github.com/osrg/gobgp/server"
)
func main() {
log.SetLevel(log.DebugLevel)
s := gobgp.NewBgpServer()
go s.Serve()
// start grpc api server. this is not mandatory
// but you will be able to use `gobgp` cmd with this.
g := gobgp.NewGrpcServer(":50051", s.GrpcReqCh)
go g.Serve()
// global configuration
req := gobgp.NewGrpcRequest(gobgp.REQ_START_SERVER, "", bgp.RouteFamily(0), &api.StartServerRequest{
Global: &api.Global{
As: 65000,
RouterId: "192.168.0.1",
ListenPort: -1, // gobgp won't listen on tcp:179
},
})
s.GrpcReqCh <- req
res := <-req.ResponseCh
if err := res.Err(); err != nil {
log.Fatal(err)
}
// neighbor configuration
req = gobgp.NewGrpcRequest(gobgp.REQ_GRPC_ADD_NEIGHBOR, "", bgp.RouteFamily(0), &api.AddNeighborRequest{
Peer: &api.Peer{
Conf: &api.PeerConf{
NeighborAddress: "192.168.0.2",
PeerAs: 65000,
},
Transport: &api.Transport{
LocalAddress: "192.168.0.1",
},
},
})
s.GrpcReqCh <- req
res = <-req.ResponseCh
if err := res.Err(); err != nil {
log.Fatal(err)
}
// monitor new routes
req = gobgp.NewGrpcRequest(gobgp.REQ_MONITOR_RIB, "", bgp.RF_IPv4_UC, &api.Table{
Type: api.Resource_GLOBAL,
})
s.GrpcReqCh <- req
for res := range req.ResponseCh {
p, _ := cmd.ApiStruct2Path(res.Data.(*api.Destination).Paths[0])
cmd.ShowRoute(p, false, false, false, true, false)
}
}
- example codeを起動します
$ cd $GOPATH/bin
$ go run example_code.go
INFO[0000] Add a peer configuration for 192.168.0.2
DEBU[0000] IdleHoldTimer expired Duration=0 Key=192.168.0.2 Topic=Peer
DEBU[0000] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_ACTIVE old=BGP_FSM_IDLE reason=idle-hold-timer-expired
DEBU[0010] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_OPENSENT old=BGP_FSM_ACTIVE reason=new-connection
DEBU[0010] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_OPENCONFIRM old=BGP_FSM_OPENSENT reason=open-msg-received
INFO[0010] Peer Up Key=192.168.0.2 State=BGP_FSM_OPENCONFIRM Topic=Peer
DEBU[0010] state changed Key=192.168.0.2 Topic=Peer new=BGP_FSM_ESTABLISHED old=BGP_FSM_OPENCONFIRM reason=open-msg-negotiated
DEBU[0010] received update Key=192.168.0.2 Topic=Peer attributes=[{Origin: ?} {Nexthop: 192.168.0.2} {LocalPref: 100}] nlri=[20.20.20.0/24] withdrawals=[]
DEBU[0010] create Destination Key=20.20.20.0/24 Topic=Table
DEBU[0010] Processing destination Key=20.20.20.0/24 Topic=table
DEBU[0010] computeKnownBestPath known pathlist: 1
DEBU[0010] From same AS, ignore. Data={ 20.20.20.0/24 | src: { 192.168.0.2 | as: 65000, id: 192.168.0.2 }, nh: 192.168.0.2 } Key=192.168.0.2 Topic=Peer
[ROUTE] 20.20.20.0/24 via 192.168.0.2 aspath [] attrs [{Origin: ?} {LocalPref: 100}]
DEBU[0040] sent Key=192.168.0.2 State=BGP_FSM_ESTABLISHED Topic=Peer data=&{Header:{Marker:[] Len:19 Type:4} Body:0x1148878}
DEBU[0070] sent Key=192.168.0.2 State=BGP_FSM_ESTABLISHED Topic=Peer data=&{Header:{Marker:[] Len:19 Type:4} Body:0x1148878}
DEBU[0100] sent Key=192.168.0.2 State=BGP_FSM_ESTABLISHED Topic=Peer data=&{Header:{Marker:[] Len:19 Type:4} Body:0x1148878}
- gobgpコマンドから、Peer情報を確認してみます
$ gobgp neighbor 192.168.0.2
BGP neighbor is 192.168.0.2, remote AS 65000
BGP version 4, remote router ID 192.168.0.2
BGP state = BGP_FSM_ESTABLISHED, up for 00:02:13
BGP OutQ = 0, Flops = 0
Hold time is 90, keepalive interval is 30 seconds
Configured hold time is 90, keepalive interval is 30 seconds
Neighbor capabilities:
BGP_CAP_MULTIPROTOCOL:
ipv4-unicast: advertised and received
l2vpn-evpn: received
BGP_CAP_ROUTE_REFRESH: advertised and received
BGP_CAP_FOUR_OCTET_AS_NUMBER: advertised and received
Message statistics:
Sent Rcvd
Opens: 1 1
Notifications: 0 0
Updates: 0 1
Keepalives: 5 5
Route Refesh: 0 0
Discarded: 0 0
Total: 6 7
Route statistics:
Advertised: 0
Received: 1
Accepted: 1
- gobgpコマンドから、rib情報を確認してみます
$ gobgp global rib
Network Next Hop AS_PATH Age Attrs
*> 20.20.20.0/24 192.168.0.2 00:02:48 [{Origin: ?} {LocalPref: 100}]
以上、3つのGoBGP起動方法を試してみました。GoBGP動作結果を比較してみると、概ね、どれも同じ結果になりました。
◼︎ GoBGP起動方法を、DeepDiveしてみる
gobgpdは、"grpcServer"と"bgpServer"から構成されていて、実際のBGP動作に関わる機能ブロックは、"bgpServer"が担っています。そして、BGPピア開設に必要な設定情報を"bgpServer"に伝えるためには、"GrpcReqCh"チャネルを経由することになります。
各々のGoBGP起動方法の全体動作イメージを、簡単にまとめてみました。
(1) gobgp設定ファイルからのBGP Peer設定
GoBGP設定ファイルを、gobgpd起動時に取り込んで、"GrpcReqCh"チャネルに渡してあげると、"bgpServer"は、BGP開設処理が行わるようです。
なお、別途、"grpcServer"も起動しているので、gobgpコマンドから、bgpServer動作状態を確認することも可能です。
(2) gobgpコマンドからのBGP Peer設定
gobgpコマンドで投入された情報は、grpc経由で、gobgpdに伝えられることになります。
そして、"GrpcReqCh"チャネルに渡してあげると、"bgpServer"は、BGP開設処理が行わるようです。
(3) "GoBGP as a Go Native BGP library"活用によるBGP Peer設定
こちらは、Example Codeから、直接"GrpcReqCh"チャネルに渡してあげると、"bgpServer"は、BGP開設処理が行わるようです。
なお、別途、"grpcServer"も起動しているので、gobgpコマンドから、bgpServer動作状態を確認することも可能です。
どのGoBGP起動方法でも、動作原理は、共通している印象がありますね。
◼︎ 最後に、、、
GoBGPのオプション機能"GoBGP as a Go Native BGP library"では、BGP処理に関わるAPIリファレンス的なドキュメントは、一切、提供されていません。GoBGPコードリーディングを通じて、内部動作を理解しながら、カスタマイズ方法を模索していく必要があるのが、難点ですね。
しかしながら、APIリファレンス的な作法を克服してしまえば、GoBGPを自分の好みに応じて、自由にカスタマイズできますというメリットがあります。
まぁ、使い手の判断に委ねられるところですかね。