FRRoutingでMPLS L3-VPNのようなもの

# はじめに
ほぼ同じことやってる方がおりました。くやしい。
https://blog.swineson.me/en/use-linux-as-an-mpls-router/

そのうちvyosにも実装されるようなので、ここまで頑張る必要無いかもしれないです。
https://phabricator.vyos.net/T915

----

急にLinuxでMPLSが動かしたくなり、故に実行しました。

# L3-VPNについて
[RFC4364](https://tools.ietf.org/html/rfc4364.html) らしいです。
結局のところ、MP-BGPとMPLSでVPNを実現します。

# FRRoutingについて
ルーティングのためのソフトウェアらしいです。
BGPなどのルーティングプロトコルを実装するデーモンや、ネットワーク機器ライクなシェルなどが利用できます。

Quaggaのフォークです。

詳しくは公式ページがわかりやすいです。
http://docs.frrouting.org/en/latest/overview.html

# 環境

以下のようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547524/3124946b-e402-bd68-e99c-c19b6b792cbe.png)


- Pルータ
 - P
- PEルータ 
 - PE1
 - PE2
 - PE3
- CEルータ（Customer A）
 - CEA1
 - CEA2
 - CEA3
- CEルータ（Customer B）
 - CEB1
 - CEB2

最後には、
`Customer A`のルータは`Customer A`のルータと、`Customer B`のルータは`Customer B`のルータと通信できることを確認します。

ここですべてのノードはUbuntu VMとします。
以下です。

- Ubuntu 20.04 LTS
 - Kernelは `5.4.0` です。VRFやMPLSなど、古いカーネルでは対応していないことがあります。
 - systemd-networkdに頼ったので、CentOSは厳しい…
- FRR 7.2.1

# 作業を始める前に

おおまかな流れを示します。

- VMごとに細かい設定を行う。
- PEルータ、PルータでIGPを動かす。
- LDPを有効にする。
- PEルータでMP-BGPを動かす。
- PEルータ、CEルータでルート情報を交換する。
- PEルータでルートの再配送設定を行う。


# VM設定

VMの設定をLinuxらしく行っていきます。
再起動しても設定を維持できるように、設定ファイルを書き換えていきます。

## FRRインストール

```bash:frr_install

sudo apt-get install frr
sudo systemctl enable frr
```
FRRをインストールしておきます。

## systemd-networkdの有効化
```yaml:/etc/netplan/00-config.yaml
# This is the network config written by 'subiquity'
network:
  version: 2
```

まずは、昨今のUbuntuでおなじみのnetplanです。
すべてのインターフェイスで `systemd-networkd` を使いたいので、余分な設定は削除します。

このあとはインターフェイス用のファイルを作ります。
書式については `systemd.netdev`、 `systemd.network` 等のmanページがわかりやすいです。

## Dummy Interface作成
すべてのルータで作成します。
Network機器のループバック代わりです。

```config:/etc/systemd/network/dum0.netdev
[NetDev]
Kind=dummy
Name=dum0
```


## VRF作成
PEルータで作成します。
FRRはネットワーク機器とは違い、VRFの作成はできないため、事前に作っておきます。


```/etc/systemd/network/c1-vrf.netdev
[NetDev]
Kind=vrf
Name=c1-vrf

[VRF]
Table=10 # 適当な値。他のVRFとかぶらないもの。
```

```/etc/systemd/network/c1-vrf.network
[Match]
Name=c1-vrf
```

```/etc/systemd/network/c2-vrf.netdev
[NetDev]
Kind=vrf
Name=c2-vrf

[VRF]
Table=20 # 適当な値。他のVRFとかぶらないもの。
```

```/etc/systemd/network/c2-vrf.network
[Match]
Name=c2-vrf
```

ここで、`.network`ファイルを作らないと、起動時にVRFがダウン状態になります。
ダウン状態では通信ができないようです。

```bash:ダウンした状態
$ ip link list type vrf
5: c1-vrf: <NOARP,MASTER> mtu 65536 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
    link/ether c2:bb:1b:ad:20:5f brd ff:ff:ff:ff:ff:ff
6: c2-vrf: <NOARP,MASTER> mtu 65536 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
    link/ether d2:c3:87:fb:4f:fc brd ff:ff:ff:ff:ff:ff
```
```bash:アップした状態
$ ip link list type vrf
5: c1-vrf: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether c2:bb:1b:ad:20:5f brd ff:ff:ff:ff:ff:ff
6: c2-vrf: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether d2:c3:87:fb:4f:fc brd ff:ff:ff:ff:ff:ff
```

## VRF割当て
インターフェイスにVRFを割り当てます。
構成に合わせて変更します。

```/etc/systemd/network/ens7.network
[Match]
Name=ens7

[Network]
VRF=c1-vrf
```

```/etc/systemd/network/ens8.network
[Match]
Name=ens8

[Network]
VRF=c2-vrf
```

## MPLSモジュールロード、sysctl変数設定
必要なモジュールをロードします。
http://docs.frrouting.org/en/latest/installation.html にも記載があります。

mpls_routerはPEルータ、Pルータのみ必要です。

```bash:/etc/modules-load.d/modules.conf
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.

mpls_router
```
必要なsysctl変数を設定します。
やはり公式に記載があります。

`net.ipv4.ip_forwarding`はすべてのルータで必要です。

`net.mpls.platform_labels`はすべてのPEルータ、Pルータで、
`net.mpls.conf.<if>.input`はMPLSを動かすすべてのインターフェイスで必要です。

```bash:/etc/sysctl.d/local.conf
# これはすべてのルータで必要。IP Forwardingを有効化。
net.ipv4.ip_forward=1

# 以下はPルータ、PEルータのMPLSを使うインターフェイスで必要。
net.mpls.conf.ens3.input=1
net.mpls.conf.ens7.input=1
net.mpls.conf.dum0.input=1

# 以下はPルータとPEルータで必要。デフォルトの0では動作しない。
net.mpls.platform_labels=1024
```

また、Dummy Interfaceは起動時、
sysctlが適用されるタイミングでインターフェイスが存在しないため、上記設定が反映されません。
そのため、udevルールを追加して、インターフェイスが追加された時点でsysctlが適用されるようにします。

既存ルール（ `/lib/udev/rules.d/99-systemd.rules` あたり） を真似しました。

```bash:/etc/udev/rules.d/local.rules
# Apply sysctl variables to network devices.
ACTION=="add", SUBSYSTEM=="net", KERNEL!="lo", RUN+="/lib/systemd/systemd-sysctl --prefix=/net/mpls/conf/$name"
```

---
**以上でInterfaceまわりの設定は終わりです。**
このあたりでVMを再起動すると、設定が反映できます。

再起動せず、プロセス再起動、sysctlの手動適用などでも反映できます。

## FRR Daemons設定
FRRの設定ファイルで起動するDaemonを指定します。
各プロトコルの意味は後の手順で明らかになります。

### Pルータ
```bash:/etc/frr/daemons
# 略
bgpd=no
ospfd=yes
ospf6d=no
ripd=no
ripngd=no
isisd=no
pimd=no
ldpd=yes
nhrpd=no
eigrpd=no
# 略
```

### PEルータ
```bash:/etc/frr/daemons
# 略
bgpd=yes
ospfd=yes
ospf6d=no
ripd=no
ripngd=no
isisd=no
pimd=no
ldpd=yes
nhrpd=no
eigrpd=no
# 略
```
### CEルータ
```bash:/etc/frr/daemons
# 略
bgpd=no
ospfd=yes
ospf6d=no
ripd=no
ripngd=no
isisd=no
pimd=no
ldpd=no
nhrpd=no
eigrpd=no
# 略
```

FRRの設定を適用するには、VMを再起動するか、以下のコマンドを実行します。

```bash:frr
$ sudo systemctl reload frr
```

以降は、FRRの `vtysh` でネットワーク機器ライクに設定を行います。
ほんへです。

# PEルータ、PルータでIGPを有効化

のちほど利用するので、すべてのPEルータ、PルータでIGPを動かし、
Dummy Interfaceに到達できるようにします。

今回はOSPFを利用します。

## Pルータ
すべてのインターフェイスでOSPFを動作させます。

```console:IGP(P)
$ sudo vtysh

# configure

(config)# interface dum0
(config-if)# ip address 1.1.1.1/32
(config-if)# exit

(config)# interface ens3
(config-if)# ip address 10.0.1.1/24
(config-if)# exit

(config)# interface ens7
(config-if)# ip address 10.0.2.1/24
(config-if)# exit

(config)# interface ens8
(config-if)# ip address 10.0.3.1/24
(config-if)# exit

(config)# router ospf
(config-router)# ospf router-id 1.1.1.1
(config-router)# network 1.1.1.1/32 area 0
(config-router)# network 10.0.1.0/24 area 0
(config-router)# network 10.0.2.0/24 area 0
(config-router)# network 10.0.3.0/24 area 0
(config-router)# end

# copy running-config startup-config
# ! 適宜configを保存する。

# ! 以降、Configの内容のみ示す。
```

## PEルータ

CEルータと接続するインターフェイスはOSPFの`network`コマンドで指定しないようにします。
（VRFが違うから、やろうとしてもできぬが…）

```config:IGP(PE1-config)
interface dum0
 ip address 2.2.2.2/32
!
interface ens3
 ip address 10.0.1.2/24
!

router ospf
 ospf router-id 2.2.2.2
 network 2.2.2.2/32 area 0
 network 10.0.1.0/24 area 0
!
```
PE2、PE3も同様にします。

## IGP確認
すべてのダミーインターフェイスについて、ルートを学習したことを確認します。
Pルータで確認してみます。

```console:IGP(P)
# show ip ospf neighbor 

Neighbor ID     Pri State           Dead Time Address         Interface            RXmtL RqstL DBsmL
2.2.2.2           1 Full/Backup       39.851s 10.0.1.2        ens3:10.0.1.1            0     0     0
3.3.3.3           1 Full/Backup       32.337s 10.0.2.2        ens7:10.0.2.1            0     0     0
4.4.4.4           1 Full/Backup       37.635s 10.0.3.2        ens8:10.0.3.1            0     0     0

# 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 route, r - rejected route

O   1.1.1.1/32 [110/10] via 0.0.0.0, dum0 onlink, 00:07:20
C>* 1.1.1.1/32 is directly connected, dum0, 00:08:21
O>* 2.2.2.2/32 [110/11] via 10.0.1.2, ens3, 00:03:54
O>* 3.3.3.3/32 [110/11] via 10.0.2.2, ens7, 00:02:27
O>* 4.4.4.4/32 [110/11] via 10.0.3.2, ens8, 00:01:02
O   10.0.1.0/24 [110/1] is directly connected, ens3, 00:07:14
C>* 10.0.1.0/24 is directly connected, ens3, 00:08:10
O   10.0.2.0/24 [110/1] is directly connected, ens7, 00:07:07
C>* 10.0.2.0/24 is directly connected, ens7, 00:07:59
O   10.0.3.0/24 [110/1] is directly connected, ens8, 00:07:02
C>* 10.0.3.0/24 is directly connected, ens8, 00:07:37
```

# LDP有効化
LDPを有効にします。
隣接するルータとLabel情報をやりとりすることで、MPLSネットワーク内ではIPアドレスではなくLabelをもとにデータを転送することが可能になります。

## Pルータ

```config:LDP(P)
mpls ldp
 !
 address-family ipv4
  discovery transport-address 1.1.1.1
  !
  interface dum0
  !
  interface ens3
  !
  interface ens7
  !
  interface ens8
  !
 exit-address-family
 !
!
```

## PEルータ

CEルータと接続するインターフェイスは…（以下略

```config:LDP(PE1)
mpls ldp
 !
 address-family ipv4
  discovery transport-address 2.2.2.2
  !
  interface dum0
  !
  interface ens3
  !
 exit-address-family
 !
!
```
PE2、PE3も同様にします。

## LDP確認

Label情報が交換されていることを確認します。
Pルータで確認してみます。

```console:LDP(P)
# show mpls ldp neighbor
AF   ID              State       Remote Address    Uptime
ipv4 10.0.1.2        OPERATIONAL 2.2.2.2         00:02:36
ipv4 10.0.2.2        OPERATIONAL 3.3.3.3         00:01:36
ipv4 10.0.3.2        OPERATIONAL 4.4.4.4         00:00:10
# show mpls ldp binding
AF   Destination          Nexthop         Local Label Remote Label  In Use
ipv4 1.1.1.1/32           10.0.1.2        imp-null    16                no
ipv4 1.1.1.1/32           10.0.2.2        imp-null    16                no
ipv4 1.1.1.1/32           10.0.3.2        imp-null    16                no
ipv4 2.2.2.2/32           10.0.1.2        16          imp-null         yes
ipv4 2.2.2.2/32           10.0.2.2        16          17                no
ipv4 2.2.2.2/32           10.0.3.2        16          17                no
ipv4 3.3.3.3/32           10.0.1.2        17          19                no
ipv4 3.3.3.3/32           10.0.2.2        17          imp-null         yes
ipv4 3.3.3.3/32           10.0.3.2        17          18                no
ipv4 4.4.4.4/32           10.0.1.2        18          20                no
ipv4 4.4.4.4/32           10.0.2.2        18          20                no
ipv4 4.4.4.4/32           10.0.3.2        18          imp-null         yes
ipv4 10.0.1.0/24          10.0.1.2        imp-null    imp-null          no
ipv4 10.0.1.0/24          10.0.2.2        imp-null    18                no
ipv4 10.0.1.0/24          10.0.3.2        imp-null    19                no
ipv4 10.0.2.0/24          10.0.1.2        imp-null    17                no
ipv4 10.0.2.0/24          10.0.2.2        imp-null    imp-null          no
ipv4 10.0.2.0/24          10.0.3.2        imp-null    20                no
ipv4 10.0.3.0/24          10.0.1.2        imp-null    18                no
ipv4 10.0.3.0/24          10.0.2.2        imp-null    19                no
ipv4 10.0.3.0/24          10.0.3.2        imp-null    imp-null          no

# show mpls table
 Inbound                            Outbound
   Label     Type          Nexthop     Label
--------  -------  ---------------  --------
      16      LDP         10.0.1.2  implicit-null
      17      LDP         10.0.2.2  implicit-null
      18      LDP         10.0.3.2  implicit-null
```

# MP-BGP設定
PEルータでMP-BGPの設定をします。
VRFごとの`IPv4`設定と、`VPN-IPv4`の設定が必要です。


やはりわかりやすい公式
http://docs.frrouting.org/en/latest/bgp.html

## VPN-IPv4 Address Family設定

通常のBGP設定を行い、PE間でiBGPを動かします。
加えて、VPN-IPv4のアドレス情報をやりとりするようにPeerに対して設定します。

（他に有名なコマンドとして`send-community ...`があり、Extended Communityを有効にするために使うのですが、デフォルトで有効なようです。） 

```config:BGP(PE1)
router bgp 65001

 neighbor 3.3.3.3 remote-as 65001
 neighbor 3.3.3.3 update-source 2.2.2.2

 neighbor 4.4.4.4 remote-as 65001
 neighbor 4.4.4.4 update-source 2.2.2.2

 !
 address-family ipv4 vpn
  neighbor 3.3.3.3 activate
  neighbor 4.4.4.4 activate
 exit-address-family
!
```
PE2、PE3でも同様にします。

## IPv4 Address Family設定
各VRFでBGPを動かします。

また、VPN-IPv4アドレスを構成するためのRDと、Attributeとしてアドレス情報に関連付けるためのRTを指定します。
なんでも動きますが、どちらも`<AS>:<数字>`としました。

このとき、同じCustomerのRTはすべてのPEで同じものにします。

```config:BGP(IPv4)
router bgp 65001 vrf c1-vrf
 !
 address-family ipv4 unicast
  label vpn export auto
  rd vpn export 65001:1
  rt vpn both 65001:1
  export vpn
  import vpn
 exit-address-family
!
router bgp 65001 vrf c2-vrf
 !
 address-family ipv4 unicast
  label vpn export auto
  rd vpn export 65001:2
  rt vpn both 65001:2
  export vpn
  import vpn
 exit-address-family
!
```
PE2、PE3でも設定します。

## BGP確認
Neighbor状態を確認します。

PE1でやってみます。


```console:BGP(PE1)
# show ip bgp summary

IPv4 Unicast Summary:
BGP router identifier 10.0.1.2, local AS number 65001 vrf-id 0
BGP table version 0
RIB entries 0, using 0 bytes of memory
Peers 2, using 41 KiB of memory

Neighbor        V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd
3.3.3.3         4      65001      14      14        0    0    0 00:04:54            0
4.4.4.4         4      65001      13      14        0    0    0 00:04:01            0

Total number of neighbors 2

IPv4 VPN Summary:
BGP router identifier 10.0.1.2, local AS number 65001 vrf-id 0
BGP table version 0
RIB entries 0, using 0 bytes of memory
Peers 2, using 41 KiB of memory

Neighbor        V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd
3.3.3.3         4      65001      14      14        0    0    0 00:04:54            0
4.4.4.4         4      65001      13      14        0    0    0 00:04:01            0

Total number of neighbors 2
#
#
# show ip bgp neighbor
BGP neighbor is 3.3.3.3, remote AS 65001, local AS 65001, internal link
Hostname: PE2
  BGP version 4, remote router ID 10.0.2.2, local router ID 10.0.1.2
  BGP state = Established, up for 00:05:42
  Last read 00:00:42, Last write 00:00:42
  Hold time is 180, keepalive interval is 60 seconds
  Neighbor capabilities:
    4 Byte AS: advertised and received
    AddPath:
      IPv4 Unicast: RX advertised IPv4 Unicast and received
      IPv4 VPN: RX advertised IPv4 VPN and received
    Route refresh: advertised and received(old & new)
    Address Family IPv4 Unicast: advertised and received
    Address Family IPv4 VPN: advertised and received
    Hostname Capability: advertised (name: PE1,domain name: n/a) received (name: PE2,domain name: n/a)
    Graceful Restart Capabilty: advertised and received
      Remote Restart timer is 120 seconds
      Address families by peer:
        none
  Graceful restart information:
    End-of-RIB send: IPv4 Unicast, IPv4 VPN
    End-of-RIB received: IPv4 Unicast, IPv4 VPN
  Message statistics:
    Inq depth is 0
    Outq depth is 0
                         Sent       Rcvd
    Opens:                  3          3
    Notifications:          2          2
    Updates:                3          3
    Keepalives:             7          7
    Route Refresh:          0          0
    Capability:             0          0
    Total:                 15         15
  Minimum time between advertisement runs is 0 seconds
  Update source is 2.2.2.2

 For address family: IPv4 Unicast
  Update group 2, subgroup 2
  Packet Queue length 0
  Community attribute sent to this neighbor(all)
  0 accepted prefixes

 For address family: IPv4 VPN
  Update group 3, subgroup 3
  Packet Queue length 0
  Community attribute sent to this neighbor(all)
  0 accepted prefixes

  Connections established 2; dropped 1
  Last reset 00:05:44,   No AFI/SAFI activated for peer
  Message received that caused BGP to send a NOTIFICATION:
    FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
    00580104 FDE900B4 0A000202 3B020601
    04000100 01020601 04000100 80020280
    00020202 00020641 040000FD E9020A45
    08000101 01000180 01020749 05035045
    32000204 40028078
Local host: 2.2.2.2, Local port: 179
Foreign host: 3.3.3.3, Foreign port: 38767
Nexthop: 2.2.2.2
Nexthop global: fe80::30c0:f9ff:fe1d:dbba
Nexthop local: fe80::30c0:f9ff:fe1d:dbba
BGP connection: non shared network
BGP Connect Retry Timer in Seconds: 120
Read thread: on  Write thread: on  FD used: 26

BGP neighbor is 4.4.4.4, remote AS 65001, local AS 65001, internal link
Hostname: PE3
## <略>
```
Establishedであることを確認します。

# PEルータ、CEルータでルート情報交換
今回はOSPFでルート情報を交換します。

## CEルータ
普通にOSPFを動かします。

```config:OSPF(CEA1)
interface dum0
 ip address 192.168.1.1/24
!
interface ens3
 ip address 10.10.1.2/24
!
router ospf
 network 192.168.1.0/24 area 0
 network 10.10.1.0/24 area 0
!
```
CEA2、CEA3、CEB1、CEB2も同様にします。

## PEルータ
VRFごとにOSPFを動かします。

```config:OSPF(PE1)
interface ens7 vrf c1-vrf
 ip address 10.10.1.1/24
!
interface ens8 vrf c2-vrf
 ip address 10.10.1.1/24
!
router ospf vrf c1-vrf
 network 10.10.1.0/24 area 0
!
router ospf vrf c2-vrf
 network 10.10.1.0/24 area 0
!
```
PE2、PE3も同様にします。

# 再配送設定
PEルータで再配送の設定を行います。

```config:Redistribute(PE)
router bgp 65001 vrf c1-vrf
 !
 address-family ipv4 unicast
  redistribute ospf
 exit-address-family
!
router bgp 65001 vrf c2-vrf
 !
 address-family ipv4 unicast
  redistribute ospf
 exit-address-family
!

router ospf vrf c1-vrf
 redistribute bgp
!
router ospf vrf c2-vrf
 redistribute bgp
!
```
PE2、PE3でも同様にします。

PE1で確認します。

```console:Route(PE)
# show bgp ipv4 vpn
BGP table version is 3, local router ID is 10.0.1.2, vrf id 0
Default local pref 100, local AS 65001
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
               i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes:  i - IGP, e - EGP, ? - incomplete

   Network          Next Hop            Metric LocPrf Weight Path
Route Distinguisher: 65001:1
*> 192.168.1.0/24   10.10.1.2@5<        11         32768 ?
    UN=10.10.1.2 EC{65001:1} label=144 type=bgp, subtype=5
*>i192.168.2.0/24   3.3.3.3        11    100      0 ?
    UN=3.3.3.3 EC{65001:1} label=144 type=bgp, subtype=0
*>i192.168.3.0/24   4.4.4.4        11    100      0 ?
    UN=4.4.4.4 EC{65001:1} label=144 type=bgp, subtype=0
Route Distinguisher: 65001:2
*> 192.168.1.0/24   10.10.1.2@6<        11         32768 ?
    UN=10.10.1.2 EC{65001:2} label=145 type=bgp, subtype=5
*>i192.168.2.0/24   3.3.3.3        11    100      0 ?
    UN=3.3.3.3 EC{65001:2} label=145 type=bgp, subtype=0

Displayed  5 routes and 5 total paths


# show bgp vrf c1-vrf ipv4
BGP table version is 3, local router ID is 10.10.1.1, vrf id 5
Default local pref 100, local AS 65001
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
               i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes:  i - IGP, e - EGP, ? - incomplete

   Network          Next Hop            Metric LocPrf Weight Path
*> 192.168.1.0/24   10.10.1.2               11         32768 ?
*> 192.168.2.0/24   3.3.3.3@0<              11    100      0 ?
*> 192.168.3.0/24   4.4.4.4@0<              11    100      0 ?

Displayed  3 routes and 3 total paths

# show ip route vrf c1-vrf
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 route, r - rejected route


VRF c1-vrf:
O   10.10.1.0/24 [110/1] is directly connected, ens7, 00:20:47
C>* 10.10.1.0/24 is directly connected, ens7, 00:21:44
O>* 192.168.1.0/24 [110/11] via 10.10.1.2, ens7, 00:18:07
B>  192.168.2.0/24 [200/11] via 3.3.3.3(vrf default) (recursive), label 144, 00:04:39
  *                           via 10.0.1.1, ens3(vrf default), label 17/144, 00:04:39
B>  192.168.3.0/24 [200/11] via 4.4.4.4(vrf default) (recursive), label 144, 00:04:12
  *                           via 10.0.1.1, ens3(vrf default), label 18/144, 00:04:12
```

**これで設定は完了です。**

ちなみに、このあたりでパケットキャプチャするとBGPのUpdateが見えることがあります。
（vtyshで`clear bgp *`としても確認できます。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547524/1e5fd004-6eaf-cc83-175b-b90a002dc795.png)
RDやRTを探すのは楽しいですね。


# 動作確認

CEルータでPingしてVPN動作を確認できます。
このとき、普通にするとPEに向かうインターフェイス（`ens3`）を使ってしまいます。
このアドレスは広告しておらずReplyができないため、**明示的に`dum0`のアドレスを指定します。**

```Ping(CEA1)
# route。192.168.3.0/24を知っている。
$ ip r
10.10.1.0/24 dev ens3 proto kernel scope link src 10.10.1.2 
192.168.1.0/24 dev dum0 proto kernel scope link src 192.168.1.1 
192.168.2.0/24 via 10.10.1.1 dev ens3 proto ospf metric 20 
192.168.3.0/24 via 10.10.1.1 dev ens3 proto ospf metric 20

$ ping -I 192.168.1.1 192.168.2.1
PING 192.168.2.1 (192.168.2.1) from 192.168.1.1 : 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=62 time=4.80 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=62 time=1.04 ms
64 bytes from 192.168.2.1: icmp_seq=3 ttl=62 time=0.942 ms
^C
--- 192.168.2.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 0.942/2.262/4.803/1.797 ms
```

このとき、パケットキャプチャを使うと面白いです。
例えば、PE1のインターフェイスでは以下のように見えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547524/db9fed8e-c2a8-4db6-8b24-60d790130499.png)
MPLSのラベルが２つあるようです。

いろいろな宛先にPingしてみます。

```bash:Ping(CEA1)
# CEA2のdum0、届く
$ ping -I 192.168.1.1 192.168.2.1
PING 192.168.2.1 (192.168.2.1) from 192.168.1.1 : 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=62 time=0.927 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=62 time=0.988 ms
64 bytes from 192.168.2.1: icmp_seq=3 ttl=62 time=1.00 ms
^C
--- 192.168.2.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.927/0.973/1.004/0.033 ms

# CEA3のdum0、届く
$ ping -I 192.168.1.1 192.168.3.1
PING 192.168.3.1 (192.168.3.1) from 192.168.1.1 : 56(84) bytes of data.
64 bytes from 192.168.3.1: icmp_seq=1 ttl=62 time=0.950 ms
64 bytes from 192.168.3.1: icmp_seq=2 ttl=62 time=1.10 ms
64 bytes from 192.168.3.1: icmp_seq=3 ttl=62 time=0.951 ms
^C
--- 192.168.3.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 0.950/1.000/1.101/0.070 ms
```
このとき、`CEA2`への通信と`CEA3`への通信を比べると、ラベルが少し異なります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547524/fd45b745-0bfd-fd17-bcef-a2918aa150c6.png)
CEA2に向かうとき、ラベルは **17**。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547524/dba1365f-8e5b-9f21-1236-17f5e85381a1.png)
CEA2に向かうとき、ラベルは **18**。


念のため、CEB2のdum0と通信しないことを確認します。

```bash:Ping(CEA1)
# CEB2のdum0と同じアドレスだが、届かん。
$ ping -I 192.168.1.1 192.168.2.2
PING 192.168.2.2 (192.168.2.2) from 192.168.1.1 : 56(84) bytes of data.
^C
--- 192.168.2.2 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2032ms
```

CEB1でも確認してみます。

```bash:Ping(CEB1)
# route。192.168.3.0/24は知らない。
$ ip r
10.10.1.0/24 dev ens3 proto kernel scope link src 10.10.1.2 
192.168.1.0/24 dev dum0 proto kernel scope link src 192.168.1.1 
192.168.2.0/24 via 10.10.1.1 dev ens3 proto ospf metric 20

# CEB2のdum0、届く。
$ ping -I 192.168.1.1 192.168.2.2
PING 192.168.2.2 (192.168.2.2) from 192.168.1.1 : 56(84) bytes of data.
64 bytes from 192.168.2.2: icmp_seq=1 ttl=62 time=0.895 ms
64 bytes from 192.168.2.2: icmp_seq=2 ttl=62 time=1.12 ms
64 bytes from 192.168.2.2: icmp_seq=3 ttl=62 time=1.02 ms
^C
--- 192.168.2.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.895/1.012/1.119/0.091 ms

# CEA2のdum0と同じアドレスだが、届かん。
$ ping -I 192.168.1.1 192.168.2.1
PING 192.168.2.1 (192.168.2.1) from 192.168.1.1 : 56(84) bytes of data.
^C
--- 192.168.2.1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2035ms
```
CEB2への通信をキャプチャすると、ラベルが少し異なります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547524/6ac04f91-1364-b33c-e0b4-0069c09de1df.png)
CEA2への通信と比較すると、ラベルが**144**から**145**になっています。


だいたい動いてそうですね。

# 終わりに

動いてよかった（小並）。

ちなみにPEルータで、VPN内のアドレスや他VRFのアドレスがデフォルトVRFのアドレスと一致すると**うまく動かない**みたいです。
宛先アドレスがインターフェイスアドレスと一致したとき、PEルータがパケットを処理してしまいます。（転送しない）

設定が足りないのか仕様なのか不明です。

EVPNもやりたい。