Mirantis OpenStack DVR 徹底解剖（第二回）

[第一回](http://qiita.com/h-otsuka/items/d6ebbca982897a47ed6a)では、DVRの簡単な説明と環境の説明をしました。
第二回では、North-South 通信について見ていきます。

# North-South 通信
## Floating IP を使用しない場合
Floating IP を使用しない場合、外部ネットワークへのアクセスする際は、
以下のように Controller Node を経由して外部との通信を行います。
![simple_ns1 (3).png](https://qiita-image-store.s3.amazonaws.com/0/121387/203752f5-149a-85ee-a972-a4ec613665cd.png)



それでは、順を追って見ていきましょう。

1. VM#1 は、デフォルトゲートウェイの設定に従い、qbr\*\*\* および br-int スイッチを経由して、
自ホストの仮想ルータ（qrouter-\*\*\*）へ到達します。
このとき、Src IP および Src MAC は VM#1 の情報となっています。
<br><br>
2. qrouter に到達した後、Dst MAC が Controller Node の sg-\*\*\* の MAC へと書き換えられます。
<br><br>
3. その後、br-tun にて、Src MAC が DVRを使用する際に使用する自ホストのMAC(※1)へと書き換えられ(※2)、
Dst MAC として sg-\*\*\* が指定されているため、Private ネットワークを使用したトンネル通信（今回の場合 vxlan）で
Controller Node へと向かいます。
<br><br>
4. Controller Node に到達した後、Controller Node 上の sg-\*\*\* へと到達します。
このときの Src MAC は、Controller Node の MACアドレスとなります。
<br><br>
5. Namespace snat-\*\*\* では、外部通信のため、Src MAC/IP が　qg-\*\*\* の情報に、
Dst MAC が Controller Node の Defaultゲートウェイのものへと書き換えられます。
<br><br>
6. その後、Namespace snat-\*\*\* の qg-\*\*\*、br-int、br-floating、br-ex を経由して、 
Dst MAC で指定されているゲートウェイへ到達し、インターネットへアクセスします。


Floating IP を使用しない North-South 通信では、
外部へのアクセスが Controller Node に一極集中しており、DVR のメリットがうまく活きていません。

## Floating IP を使用する場合
Floating IP を使用する場合はどうでしょうか。
![simple_ns2 (1).png](https://qiita-image-store.s3.amazonaws.com/0/121387/a17e6346-0d86-368b-4cd9-03b54a453705.png)

こちらは、Compute Node の br-ex から外部へアクセスしていることが確認できます。

1. Floating IP と同様、VM#1 は、デフォルトゲートウェイの設定に従い、qbr\*\*\* および br-int スイッチを経由して、
自ホストの仮想ルータ（qrouter-\*\*\*）へ到達します。
Src IP および Src MAC は VM#1 の情報となっています。
<br><br>
2. qrouter に到達した後、Dst MAC が fpr-\*\*\* の MAC へと書き換えられ、
Src IP/MAC が、frp-*** のもの（Floating IP と同一）となります。
<br><br>
3. そして、Namespace fip-*** へ到達した後、Src MAC が fg-*** の MAC に、
Dst MAC が Compute Node のデフォルトゲートウェイのMACへと書き換わります。
<br><br>
4. その後、Namespace fip-\*\*\* の fg-\*\*\*、br-int、ber-floating、br-ex を経由して、 
Dst MAC で指定されているゲートウェイへ到達し、インターネットへアクセスします。

# 補足
Namespace を中心に調べた結果をいくつか以下に記載します。

## Namespace
サブネットごとに仮想ルータ（qrouter-\*\*\*）が生成されていきます。
fip-\*\*\* は各 Compute Node 毎に１つとなります。

```bash
root@compute01:~# ip netns
qrouter-703db450-5cd2-4f8c-a525-a0cd9f90cb3f
qrouter-13fe8525-da22-42de-aeb6-84f41a3b607d
fip-02e2d514-529e-4067-bbf4-807943ea6472
qrouter-242fcb80-e9e1-410b-ba4e-7617d1c384ad
```
### Namespace fip-\*\*\* の NIC
以下の通り、仮想マシンへ Floating IP を割り当てた際に対応する仮想ルータと接続するための NIC（fpr-***）が生成されます。

- 仮想マシン（VM#1）への Floating IP 割り当て前

```bash
root@compute01:~# ip netns exec fip-02e2d514-529e-4067-bbf4-807943ea6472 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
21: fpr-703db450-5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 3a:0b:24:74:57:0d brd ff:ff:ff:ff:ff:ff
    inet 169.254.30.51/31 scope global fpr-703db450-5
       valid_lft forever preferred_lft forever
    inet6 fe80::380b:24ff:fe74:570d/64 scope link
       valid_lft forever preferred_lft forever
26: fg-6e12764c-ba: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
    link/ether fa:16:3e:d2:85:89 brd ff:ff:ff:ff:ff:ff
    inet 192.168.74.103/24 brd 192.168.74.255 scope global fg-6e12764c-ba
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fed2:8589/64 scope link
       valid_lft forever preferred_lft forever
```

- 仮想マシン（VM#1）への Floating IP 割り当て後

```bash
root@compute01:~# ip netns exec fip-02e2d514-529e-4067-bbf4-807943ea6472 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
19: fpr-13fe8525-d: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 2e:8b:6f:f5:ee:8d brd ff:ff:ff:ff:ff:ff
    inet 169.254.31.105/31 scope global fpr-13fe8525-d
       valid_lft forever preferred_lft forever
    inet6 fe80::2c8b:6fff:fef5:ee8d/64 scope link
       valid_lft forever preferred_lft forever
21: fpr-703db450-5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 3a:0b:24:74:57:0d brd ff:ff:ff:ff:ff:ff
    inet 169.254.30.51/31 scope global fpr-703db450-5
       valid_lft forever preferred_lft forever
    inet6 fe80::380b:24ff:fe74:570d/64 scope link
       valid_lft forever preferred_lft forever
26: fg-6e12764c-ba: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
    link/ether fa:16:3e:d2:85:89 brd ff:ff:ff:ff:ff:ff
    inet 192.168.74.103/24 brd 192.168.74.255 scope global fg-6e12764c-ba
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fed2:8589/64 scope link
       valid_lft forever preferred_lft forever
```

### Namespace qrouter-\*\*\* の NIC
qrouter-\*\*\* も fip-\*\*\* と同様、仮想マシンへ Floating IP を割り当てた際に
対応する仮想ルータと接続するための NIC（frp-\*\*\*）が生成されます。

- 仮想マシン（VM#1）への Floating IP 割り当て前

```bash
root@compute01:~# ip netns exec qrouter-242fcb80-e9e1-410b-ba4e-7617d1c384ad ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
24: qr-b4b97d8a-7c: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65000 qdisc noqueue state UNKNOWN group default
    link/ether fa:16:3e:ac:30:ff brd ff:ff:ff:ff:ff:ff
    inet 192.168.111.1/24 brd 192.168.111.255 scope global qr-b4b97d8a-7c
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:feac:30ff/64 scope link
       valid_lft forever preferred_lft forever
```

- 仮想マシン（VM#1）への Floating IP 割り当て後

```bash
root@compute01:~# ip netns exec qrouter-242fcb80-e9e1-410b-ba4e-7617d1c384ad ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
3: rfp-242fcb80-e: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 02:9f:83:86:46:4c brd ff:ff:ff:ff:ff:ff
    inet 169.254.31.74/31 scope global rfp-242fcb80-e
       valid_lft forever preferred_lft forever
    inet 192.168.74.104/32 brd 192.168.74.104 scope global rfp-242fcb80-e
       valid_lft forever preferred_lft forever
    inet6 fe80::9f:83ff:fe86:464c/64 scope link
       valid_lft forever preferred_lft forever
24: qr-b4b97d8a-7c: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65000 qdisc noqueue state UNKNOWN group default
    link/ether fa:16:3e:ac:30:ff brd ff:ff:ff:ff:ff:ff
    inet 192.168.111.1/24 brd 192.168.111.255 scope global qr-b4b97d8a-7c
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:feac:30ff/64 scope link
       valid_lft forever preferred_lft forever
```

### Namespace 内の NIC での tcpdump
Namespace 内の NIC に対しても `tcpdump`コマンドを使用したパケットキャプチャをすることができます。

```bash
root@compute01:~# ip netns exec qrouter-13fe8525-da22-42de-aeb6-84f41a3b607d tcpdump -n -i qr-85285e17-5d
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on qr-85285e17-5d, link-type EN10MB (Ethernet), capture size 65535 bytes
^C02:54:00.544983 IP 10.16.0.3 > 8.8.8.8: ICMP echo request, id 42550, seq 5, length 64
02:54:00.545021 IP 10.16.0.3 > 8.8.8.8: ICMP echo request, id 42550, seq 5, length 64
02:54:00.548426 ARP, Request who-has 10.16.0.1 tell 10.16.0.3, length 28
02:54:00.548440 ARP, Reply 10.16.0.1 is-at fa:16:3e:84:64:cc, length 28
02:54:01.545141 IP 10.16.0.3 > 8.8.8.8: ICMP echo request, id 42550, seq 6, length 64
02:54:01.545172 IP 10.16.0.3 > 8.8.8.8: ICMP echo request, id 42550, seq 6, length 64
02:54:02.545399 IP 10.16.0.3 > 8.8.8.8: ICMP echo request, id 42550, seq 7, length 64
```

# 注釈
※1&nbsp;&nbsp;&nbsp;DVRを使用する際に使用する自ホストのMAC

DVRを使用する場合、内部通信で使用される MAC アドレスです。
各ホストごとにユニークな値となっており、dvr_host_macs テーブルで管理されています。
（neutron.conf の dvr_base_mac でMACアドレスを変更することもできるようです。）

```bash
mysql> select * from neutron.dvr_host_macs;
+-------------------------+-------------------+
| host                    | mac_address       |
+-------------------------+-------------------+
| compute02.domain.tld    | fa:16:3f:6d:9f:cd |
| compute01.domain.tld    | fa:16:3f:86:5c:5c |
| controller01.domain.tld | fa:16:3f:e7:70:87 |
+-------------------------+-------------------+
3 rows in set (0.00 sec)
```

※2&nbsp;&nbsp;&nbsp;br-tun における Src MAC の DVRを使用する際に使用する自ホストのMAC への書き換え

以下のケースでは、
> Src MAC が、compute01 の仮想ルータ(qrouter-\*\*\*) の qr-\*\*\* の MAC となっている場合、
DVRを使用する際に使用する自ホスト(compute01)のMAC へと書き換えられる

```
root@compute01:~# ovs-ofctl dump-flows br-tun
 cookie=0x9993ab7371e38af2, duration=8878.130s, table=1, n_packets=1838, n_bytes=179875, idle_age=0, priority=1,dl_vlan=1,dl_src=fa:16:3e:bc:4c:74 actions=mod_dl_src:fa:16:3f:86:5c:5c,resubmit(,2)
```