運用する際に理解しておきたい OpenStack Neutron DVR の Packet Flow

# はじめに
OpenStack では ネットワークのコンポーネントとして neutron が広く使われています。
neutron に対応した実装としては、商用・Open Source 共に沢山の SDN製品が提供されていますが、Upstream Version(Default で提供される標準実装) でも最近のリリースでは機能・性能が大幅に改善されつつあります。
しかしながら、冗長構成・スケーラビリティを高める機能である Distributed Virtual Router (DVR) は複雑なため、プロダクション環境で運用するためには一通りの Packet Flow を理解しておく必要があると思います。

本ドキュメントでは、OpenStack Ocata (2017年2月リリース)の devstack を構築して、実際の運用に役立つ Packet Flow の追いかけ方について、解説をいたします。

# Neutron Distributed Virtual Router (DVR)

DVR の Packet Flow は大きく分けて、次の4つに分かれます。これら4つについて理解すれば、DVR の通信内容を追いかけることが容易になります。

1. Same Subnet / Different compute-node
2. Different Subnet / Different compute-node
3. SNAT (Not Floating-IP)
4. Floating-IP

本ドキュメントでは、上記4つについて、それぞれ解説していきます。
なお、ドキュメントでは Packet Flow を詳細に追っていきますが、全部読むだけの時間がない人は、各セクションにあるフロー図を覚えておくだけでも不具合の切り分け等に役立つと思います。


# Network 構成
devstack の Network 構成は、次のようになります。

![network-diagram1.png](https://qiita-image-store.s3.amazonaws.com/0/96389/a25c9e99-dd78-10b6-a073-41365dafdc55.png)


Neutronネットワーク の論理構成は、次のようになります。

<img width="764" alt="network-overview.png" src="https://qiita-image-store.s3.amazonaws.com/0/96389/2fab6ded-f296-99ad-4d71-ab926f78a08b.png">


# devstack 構築手順

Vagrant / VirtualBox を用いて、3台VM構成の devstack を構築します。
なお、devstack を構築するためには 最低でも 8GB 以上の Memory が搭載された端末が必要です。

下記 Vagrantfile では、increase_swap.sh ([参照](https://gist.github.com/shovon/9dd8d2d1a556b8bf9c82))を provisioning時に実行することで、swapfile を自動作成し、Memory が少ない環境でも動作するようにしています。

```bash:Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.provision "shell", path: "increase_swap.sh"
 
  config.vm.define "node1" do |node|
    node.vm.network "private_network", ip: "192.168.1.11"
    node.vm.network "private_network", ip: "172.24.4.251"
    (1..node.vm.networks.count {|nw| !nw.include? :forwarded_port}).each do |i|
      node.vm.provider :VirtualBox do |vb|
        vb.customize ["modifyvm", :id, "--nicpromisc#{i+1}", "allow-all"]
      end
    end
    node.vm.network :forwarded_port, host: 8080, guest: 80
    node.vm.hostname = "node1"
    node.vm.provider :virtualbox do |domain|
      domain.memory = 4096
      domain.cpus = 2
    end
  end
 
  config.vm.define "node2" do |node|
    node.vm.network "private_network", ip: "192.168.1.12"
    node.vm.network "private_network", ip: "172.24.4.252"
    (1..node.vm.networks.count {|nw| !nw.include? :forwarded_port}).each do |i|
      node.vm.provider :VirtualBox do |vb|
        vb.customize ["modifyvm", :id, "--nicpromisc#{i+1}", "allow-all"]
      end
    end
    node.vm.hostname = "node2"
    node.vm.provider :virtualbox do |domain|
      domain.memory = 2048
      domain.cpus = 2
    end
  end
 
  config.vm.define "node3" do |node|
    node.vm.network "private_network", ip: "192.168.1.13"
    node.vm.network "private_network", ip: "172.24.4.253"
    (1..node.vm.networks.count {|nw| !nw.include? :forwarded_port}).each do |i|
      node.vm.provider :VirtualBox do |vb|
        vb.customize ["modifyvm", :id, "--nicpromisc#{i+1}", "allow-all"]
      end
    end
    node.vm.hostname = "node3"
    node.vm.provider :virtualbox do |domain|
      domain.memory = 2048
      domain.cpus = 2
    end
  end
end
```

```bash:increase_swap.sh
#!/bin/sh

# size of swapfile
swapsize=4G

# does the swap file already exist?
grep -q "swapfile" /etc/fstab

# if not then create it
if [ $? -ne 0 ]; then
  echo 'swapfile not found. Adding swapfile.'
  fallocate -l ${swapsize} /swapfile
  chmod 600 /swapfile
  mkswap /swapfile
  swapon /swapfile
  echo '/swapfile none swap defaults 0 0' >> /etc/fstab
else
  echo 'swapfile found. No changes made.'
fi

# output results to terminal
df -h
cat /proc/swaps
cat /proc/meminfo | grep Swap
```

上記2つのファイル(Vagrantfile, increase_swap.sh)を任意のディレクトリに作成後、次のコマンドを実行して 3つのVMを作成します。

```bash:vagrant_up
vagrant up
```

public network の default route (172.24.4.1) は node1 に設定されているので、Virtual Box 側で自動的に割り当てられたアドレスについては削除します。

```bash:remove_172.24.4.1
sudo ifconfig vboxnet5 delete 172.24.4.1
```

devstack を用いて OpenStack を構築します。
まず、node1 (all-in-one node) を作成します。

```bash:create_devstack
vagrant ssh node1

git clone https://github.com/openstack-dev/devstack
cd devstack
cp samples/local.conf ./

# devstack 設定ファイルを編集します
vi local.conf

sudo apt-get -y install python-os-testr bridge-utils

# OpenStack を構築します
./stack.sh
```

```bash:local.conf(node1)
...
Q_PLUGIN=ml2
Q_ML2_TENANT_NETWORK_TYPE=vxlan
Q_DVR_MODE=dvr

# Replace HOST_IP with IP of eth0
HOST_IP=192.168.1.11
PUBLIC_INTERFACE=enp0s9
Q_PLUGIN=ml2
Q_ML2_TENANT_NETWORK_TYPE=vxlan
Q_DVR_MODE=dvr_snat
  
[[post-config|/$Q_PLUGIN_CONF_FILE]]
[agent]
arp_responder=True
```

次に、nova-compute ノード (node2, node3) を構築します。
devstack の構築手順は node1 と同一ですが、local.conf については次のファイルに変更する必要があります。

```bash:local.conf(node2)
...
Q_PLUGIN=ml2
Q_ML2_TENANT_NETWORK_TYPE=vxlan
Q_DVR_MODE=dvr

# Replace HOST_IP with IP of eth0
HOST_IP=192.168.1.12
PUBLIC_INTERFACE=enp0s9
# Replace SERVICE_HOST with IP of eth0 on node1
SERVICE_HOST=192.168.1.11
MYSQL_HOST=$SERVICE_HOST
RABBIT_HOST=$SERVICE_HOST
ENABLED_SERVICES=n-cpu,neutron,n-novnc,q-agt,q-l3,q-meta,placement-client
  
[[post-config|/$Q_PLUGIN_CONF_FILE]]
[agent]
arp_responder=True
```

```bash:local.conf(node3)
...
Q_PLUGIN=ml2
Q_ML2_TENANT_NETWORK_TYPE=vxlan
Q_DVR_MODE=dvr

# Replace HOST_IP with IP of eth0
HOST_IP=192.168.1.13
PUBLIC_INTERFACE=enp0s9
# Replace SERVICE_HOST with IP of eth0 on node1
SERVICE_HOST=192.168.1.11
MYSQL_HOST=$SERVICE_HOST
RABBIT_HOST=$SERVICE_HOST
ENABLED_SERVICES=n-cpu,neutron,n-novnc,q-agt,q-l3,q-meta,placement-client
  
[[post-config|/$Q_PLUGIN_CONF_FILE]]
[agent]
arp_responder=True
```


node2 及び node3 の構築が完了した後に、node1 上で次のコマンドを実行します。

```bash:devstack_post
source openrc admin

# Update cells
nova-manage cell_v2 discover_hosts

# Prepare security groups
sudo apt-get install -y jq
openstack security group list
openstack security group list -f json | jq -r '.[].ID' | xargs -I {} openstack security group rule create {} --protocol tcp --ingress --dst-port 22
openstack security group list -f json | jq -r '.[].ID' | xargs -I {} openstack security group rule create {} --protocol icmp

# Create another tenant segment
openstack network create private2
openstack subnet create private2-subnet --network private2 --subnet-range 10.1.0.0/24
openstack router set router1 --external-gateway public
openstack router add subnet router1 private2-subnet

# Create instances
private_id=`openstack network list | grep private\ | awk '{print $2}'`
private2_id=`openstack network list | grep private2\ | awk '{print $2}'`
router1_id=`openstack router list | grep router1 | awk '{print $2}'`
openstack server create --flavor m1.tiny --image cirros-0.3.5-x86_64-disk --availability-zone nova:node1:node1 --nic net-id=$private_id test01
openstack server create --flavor m1.tiny --image cirros-0.3.5-x86_64-disk --availability-zone nova:node2:node2 --nic net-id=$private_id test02
openstack server create --flavor m1.tiny --image cirros-0.3.5-x86_64-disk --availability-zone nova:node2:node2 --nic net-id=$private2_id test03
openstack server create --flavor m1.tiny --image cirros-0.3.5-x86_64-disk --availability-zone nova:node3:node3 --nic net-id=$private2_id test04
openstack server create --flavor m1.tiny --image cirros-0.3.5-x86_64-disk --availability-zone nova:node3:node3 --nic net-id=$private_id test05

# Create a SNAPT rule so that outbound traffic from instances can be reached to the outer networks
sudo iptables -t nat -A POSTROUTING -o enp0s3 -s 172.24.4.0/24 -j MASQUERADE

# Display instances
ubuntu@node1:~/devstack$ openstack server list
+--------------------------------------+--------+--------+--------------------------------------------------------+--------------------------+
| ID                                   | Name   | Status | Networks                                               | Image Name               |
+--------------------------------------+--------+--------+--------------------------------------------------------+--------------------------+
| 7567c60a-2fcb-4db2-b56e-e55822838b6c | test05 | ACTIVE | private=10.0.0.4, fda0:6cec:a994:0:f816:3eff:fe96:e2a4 | cirros-0.3.5-x86_64-disk |
| 1b130d17-da5b-490a-9d6a-0fa44614d85c | test04 | ACTIVE | private2=10.1.0.10                                     | cirros-0.3.5-x86_64-disk |
| cfe97f47-12db-4906-b73b-8cd08c1cd50e | test03 | ACTIVE | private2=10.1.0.12                                     | cirros-0.3.5-x86_64-disk |
| df94802d-1c7d-4059-8a4d-8c732163a538 | test02 | ACTIVE | private=10.0.0.8, fda0:6cec:a994:0:f816:3eff:fe76:4775 | cirros-0.3.5-x86_64-disk |
| 40d6518d-be98-4611-b6ce-50e030688876 | test01 | ACTIVE | private=10.0.0.7, fda0:6cec:a994:0:f816:3eff:fe5a:6e54 | cirros-0.3.5-x86_64-disk |
+--------------------------------------+--------+--------+--------------------------------------------------------+--------------------------+

```

## Instance への SSHログイン手順
Instance にSSHログインをする場合は、compute-node にログインした上で qrouter namespace に切り替えて sshコマンドを実行します。
または、network node (node1)にて qdhcp namespace に切り替えて、各インスタンスにSSH接続をすることができます。

```bash
sudo ip netns exec qdhcp-$private_id bash
ssh cirros@10.0.0.5
```


# DVR 設定内容の確認
devstack にて設定された DVR の内容を確認します。
DVR を使用する場合は、neutron.conf、l3_agent.ini 及び ml2_conf.ini それぞれに設定が必要となります。

neutron.conf の設定に、'router_distributed = True' が追加されていることを確認します。

```bash:neutron.conf
[DEFAULT]
router_distributed = True
```

L3 Agent の設定について、agent_mode = dvr_snat (node1) 及び dvr (node2, node3) が設定されていることを確認します。

```bash:l3_agent.ini(node1)
[DEFAULT]
agent_mode = dvr_snat
```

```bash:l3_agent.ini(node2,node3)
[DEFAULT]
agent_mode = dvr
```

L2 Agent (ML2)の設定について、DVR の設定がされていることを確認します。
また、arp responder (proxy-arp機能) が有効になっていることを確認します。

```bash:ml2_conf.ini
[ml2]
mechanism_drivers = openvswitch,linuxbridge,l2population

[agent]
enable_distributed_routing = True
l2_population = True
arp_responder = True
```

## Packet Flow (Same Subnet / Different Compute Node)

同一ホスト / 異なる Compute Node での Packet Flow について解説します。
図で表すと、次のようになります。

![same-net1.png](https://qiita-image-store.s3.amazonaws.com/0/96389/eaecd981-fabd-479e-5953-e7ed847438ad.png)


```bash:node2
vagrant ssh node2
source ~/devstack/openrc admin

private_id=`openstack network list | grep private\ | awk '{print $2}'`
private2_id=`openstack network list | grep private2\ | awk '{print $2}'`
router1_id=`openstack router list | grep router1 | awk '{print $2}'`

test02_ifname=qvo`openstack port list | grep 10.0.0.8 | awk '{print $2}' | cut -c1-11`
test02_qrname=qbr`openstack port list | grep 10.0.0.8 | awk '{print $2}' | cut -c1-11`
test02_hwaddr=`openstack port list | grep 10.0.0.8 | awk '{print $5}'`
test02_port=`sudo ovs-ofctl show br-int | grep $test02_ifname | cut -d'(' -f1 | cut -d' ' -f2`
test05_hwaddr=`openstack port list | grep 10.0.0.4 | awk '{print $5}'`
```

```bash:node3
vagrant ssh node2
source ~/devstack/openrc admin

private_id=`openstack network list | grep private\ | awk '{print $2}'`
private2_id=`openstack network list | grep private2\ | awk '{print $2}'`
router1_id=`openstack router list | grep router1 | awk '{print $2}'`

test05_ifname=qvo`openstack port list | grep 10.0.0.4 | awk '{print $2}' | cut -c1-11`
test05_qrname=qbr`openstack port list | grep 10.0.0.4 | awk '{print $2}' | cut -c1-11`
test05_hwaddr=`openstack port list | grep 10.0.0.4 | awk '{print $5}'`
test05_port=`sudo ovs-ofctl show br-int | grep $test05_ifname | cut -d'(' -f1 | cut -d' ' -f2`
node2_host='192.168.1.12'
test02_vxifname=`printf "vxlan-%02x%02x%02x%02x" ${node2_host//./ }`
test02_vxport=`sudo ovs-ofctl show br-tun | grep $test02_vxifname | cut -d'(' -f1 | cut -d' ' -f2`
private_segid=$(openstack network show `openstack network list | grep private\ | awk '{print $2}'` | grep segmentation_id | awk '{print $4}')
```

VM(test02)に関連する virtual interface は次の4つになります。

- tap28e6e267-f3
  - qemu の VM に直接接続されている tapインタフェース
- qvb28e6e267-f3
  - Linux Bridge を経由して tapインタフェースは veth(qvb28e6e267-f3)に接続されています
  - upstream neutron では security group を ovs ではなく iptables で実現しているため、VM から ovs へ直接接続せずに Linux Bridge を経由する形の実装をしています
- qvo28e6e267-f3
  - veth(qvb28e6e267-f3)の対向側インタフェースになります
  - ovs に接続されています
- qbr28e6e267-f3
  - Linux Bridge 名

ホスト側(node2)で ip addr コマンドを実行すると、次のように出力されます。

```bash
ubuntu@node2:~/devstack$ ip addr show | grep `echo $test02_ifname | cut - -c4-15`
11: qbr28e6e267-f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
12: qvo28e6e267-f3@qvb28e6e267-f3: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1450 qdisc noqueue master ovs-system state UP group default qlen 1000
13: qvb28e6e267-f3@qvo28e6e267-f3: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1450 qdisc noqueue master qbr28e6e267-f3 state UP group default qlen 1000
14: tap28e6e267-f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc pfifo_fast master qbr28e6e267-f3 state UNKNOWN group default qlen 1000
```

ホスト側(node3) で ip addr 同様にコマンドを実行した結果は次のようになります。

```bash
ubuntu@node3:~/devstack$ ip addr show | grep `echo $test05_ifname | cut - -c4-15`
19: qbr4a577779-93: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
20: qvo4a577779-93@qvb4a577779-93: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1450 qdisc noqueue master ovs-system state UP group default qlen 1000
21: qvb4a577779-93@qvo4a577779-93: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1450 qdisc noqueue master qbr4a577779-93 state UP group default qlen 1000
22: tap4a577779-93: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc pfifo_fast master qbr4a577779-93 state UNKNOWN group default qlen 1000
```

```bash:ip_netns(node2)
ubuntu@node2:~/devstack$ ip netns
qrouter-bd7982cb-bb78-4cc6-b3f0-f8a828947718
```

```bash:ip_netns(node2)
ubuntu@node3:~/devstack$ ip netns
qrouter-bd7982cb-bb78-4cc6-b3f0-f8a828947718
ubuntu@node3:~/devstack$ 
```

Linux Bridge の構成は、次の通りです。

```bash:brctl_show(node2)
ubuntu@node2:~/devstack$ brctl show $test02_qrname
bridge name     bridge id               STP enabled     interfaces
qbr28e6e267-f3          8000.423053f1d9d1       no              qvb28e6e267-f3
                                                        tap28e6e267-f3
```

```bash:brctl_show(node3)
ubuntu@node3:~/devstack$ brctl show $test05_qrname
bridge name     bridge id               STP enabled     interfaces
qbr4a577779-93          8000.86472aa71764       no              qvb4a577779-93
                                                        tap4a577779-93
```

### ovs configuration (node2)

```bash:ovs_vsctl_show(node2)
ubuntu@node2:~/devstack$ sudo ovs-vsctl show 
d3fa01df-cedd-422b-aaf1-84edbf40825a
    Manager "ptcp:6640:127.0.0.1"
        is_connected: true
    Bridge br-int
        Controller "tcp:127.0.0.1:6633"
            is_connected: true
        fail_mode: secure
        Port "qr-aae8ab78-22"
            tag: 1
            Interface "qr-aae8ab78-22"
                type: internal
        Port br-int
            Interface br-int
                type: internal
        Port int-br-ex
            Interface int-br-ex
                type: patch
                options: {peer=phy-br-ex}
        Port patch-tun
            Interface patch-tun
                type: patch
                options: {peer=patch-int}
        Port "qvo28e6e267-f3"
            tag: 1
            Interface "qvo28e6e267-f3"
        Port "qr-2909fe1f-46"
            tag: 2
            Interface "qr-2909fe1f-46"
                type: internal
        Port "qr-12fa6289-8f"
            tag: 1
            Interface "qr-12fa6289-8f"
                type: internal
        Port "qvo06557f2b-83"
            tag: 2
            Interface "qvo06557f2b-83"
    Bridge br-ex
        Controller "tcp:127.0.0.1:6633"
            is_connected: true
        fail_mode: secure
        Port "enp0s9"
            Interface "enp0s9"
        Port phy-br-ex
            Interface phy-br-ex
                type: patch
                options: {peer=int-br-ex}
        Port br-ex
            Interface br-ex
                type: internal
    Bridge br-tun
        Controller "tcp:127.0.0.1:6633"
            is_connected: true
        fail_mode: secure
        Port "vxlan-c0a8010d"
            Interface "vxlan-c0a8010d"
                type: vxlan
                options: {df_default="true", in_key=flow, local_ip="192.168.1.12", out_key=flow, remote_ip="192.168.1.13"}
        Port "vxlan-c0a8010b"
            Interface "vxlan-c0a8010b"
                type: vxlan
                options: {df_default="true", in_key=flow, local_ip="192.168.1.12", out_key=flow, remote_ip="192.168.1.11"}
        Port patch-int
            Interface patch-int
                type: patch
                options: {peer=patch-tun}
        Port br-tun
            Interface br-tun
                type: internal
    ovs_version: "2.5.0"
```

### ovs configuration (node3)

```bash:ovs_vsctl_show(node3)
ubuntu@node3:~/devstack$ sudo ovs-vsctl show                                                                                                                                                    [16/9926]
ce0d36f3-fbaf-4b5b-8d06-a511ce4f62dc
    Manager "ptcp:6640:127.0.0.1"
        is_connected: true
    Bridge br-tun
        Controller "tcp:127.0.0.1:6633"
            is_connected: true
        fail_mode: secure
        Port "vxlan-c0a8010b"
            Interface "vxlan-c0a8010b"
                type: vxlan
                options: {df_default="true", in_key=flow, local_ip="192.168.1.13", out_key=flow, remote_ip="192.168.1.11"}
        Port br-tun
            Interface br-tun
                type: internal
        Port "vxlan-c0a8010c"
            Interface "vxlan-c0a8010c"
                type: vxlan
                options: {df_default="true", in_key=flow, local_ip="192.168.1.13", out_key=flow, remote_ip="192.168.1.12"}
        Port patch-int
            Interface patch-int
                type: patch
                options: {peer=patch-tun}
    Bridge br-ex
        Controller "tcp:127.0.0.1:6633"
            is_connected: true
        fail_mode: secure
        Port phy-br-ex
            Interface phy-br-ex
                type: patch
                options: {peer=int-br-ex}
        Port "enp0s9"
            Interface "enp0s9"
        Port br-ex
            Interface br-ex
                type: internal
    Bridge br-int
        Controller "tcp:127.0.0.1:6633"
            is_connected: true
        fail_mode: secure
        Port br-int
            Interface br-int
                type: internal
        Port patch-tun
            Interface patch-tun
                type: patch
                options: {peer=patch-int}
        Port "qvo4a577779-93"
            tag: 2
            Interface "qvo4a577779-93"
        Port "qr-12fa6289-8f"
            tag: 2
            Interface "qr-12fa6289-8f"
                type: internal
        Port "qvo62806dde-b9"
            tag: 1
            Interface "qvo62806dde-b9"
        Port int-br-ex
            Interface int-br-ex
                type: patch
                options: {peer=phy-br-ex}
        Port "qr-aae8ab78-22"
            tag: 2
            Interface "qr-aae8ab78-22"
                type: internal
        Port "qr-2909fe1f-46"
            tag: 1
            Interface "qr-2909fe1f-46"
                type: internal
    ovs_version: "2.5.0"
```

### ovs port assignment of br-int (node2)

```bash:ovs_ofctl_show_br_int(node2)
ubuntu@node2:~/devstack$ sudo ovs-ofctl show br-int
OFPT_FEATURES_REPLY (xid=0x2): dpid:0000cae496175d45
n_tables:254, n_buffers:256
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
 1(int-br-ex): addr:f2:94:80:31:fc:4a
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 2(patch-tun): addr:1a:96:d2:ec:73:8b
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 3(qvo28e6e267-f3): addr:9a:c1:b7:06:5e:02
     config:     0
     state:      0
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 0 Mbps max
 4(qr-12fa6289-8f): addr:47:b0:00:00:00:00
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
 5(qr-2909fe1f-46): addr:ba:1a:00:00:00:00
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
 6(qr-aae8ab78-22): addr:62:d1:00:00:00:00
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
 7(qvo06557f2b-83): addr:c2:b6:30:38:d9:eb
     config:     0
     state:      0
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 0 Mbps max
 LOCAL(br-int): addr:ca:e4:96:17:5d:45
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0
```

### ovs port assignment of br-tun (node2)

```bash:ovs_ofctl_show_br_tun(node2)
ubuntu@node2:~/devstack$ sudo ovs-ofctl show br-tun
OFPT_FEATURES_REPLY (xid=0x2): dpid:00004ee254492b46
n_tables:254, n_buffers:256
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
 1(patch-int): addr:5e:b4:f6:eb:e0:36
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 2(vxlan-c0a8010b): addr:fa:ad:60:4e:b5:c2
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 3(vxlan-c0a8010d): addr:7e:d6:39:32:84:72
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 LOCAL(br-tun): addr:4e:e2:54:49:2b:46
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0
```

### ovs port assignment of br-int (node3)

```bash:ovs_ofctl_show_br_int(node3)
ubuntu@node3:~/devstack$ sudo ovs-ofctl show br-int
OFPT_FEATURES_REPLY (xid=0x2): dpid:0000da558b6e624d
n_tables:254, n_buffers:256
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
 1(int-br-ex): addr:ba:85:ce:60:67:0d
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 2(patch-tun): addr:1a:4c:47:74:ba:5d
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 3(qvo62806dde-b9): addr:2e:79:47:b9:56:b3
     config:     0
     state:      0
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 0 Mbps max
 4(qr-12fa6289-8f): addr:47:b0:00:00:00:00
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
 5(qr-2909fe1f-46): addr:ba:1a:00:00:00:00
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
 6(qr-aae8ab78-22): addr:62:d1:00:00:00:00
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
 7(qvo4a577779-93): addr:4a:95:4b:0d:1e:16
     config:     0
     state:      0
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 0 Mbps max
 LOCAL(br-int): addr:da:55:8b:6e:62:4d
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0
```

### ovs port assignment of br-tun (node3)

```bash:ovs_ofctl_show_br_tun(node3)
ubuntu@node3:~/devstack$ sudo ovs-ofctl show br-tun
OFPT_FEATURES_REPLY (xid=0x2): dpid:0000a270f1066e47
n_tables:254, n_buffers:256
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
 1(patch-int): addr:86:1b:a5:c6:ae:84
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 2(vxlan-c0a8010c): addr:96:ed:60:fb:3e:a1
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 3(vxlan-c0a8010b): addr:d2:7e:09:52:7a:27
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 LOCAL(br-tun): addr:a2:70:f1:06:6e:47
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0
```

### ovs packet trace (node2)
VM(test02) -> VM(test05) 宛のパケットが実際に br-int でどのように処理されるか、ovs-appctl ofproto/trace コマンドにて確認することができます。

次のコマンドの実行結果より、Port 3 (qvo28e6e267-f3) に入力された icmp packet (10.0.0.8 -> 10.0.0.4) は tunnel_id=0x42 で encap されて Port: 3 に output されることが分かります。

trace結果が示している内容は、次の通りです。

1. table=0 の match rule により、table: 25 に移る
2. table=25 の NORMAL action により、l2 switch として forwarding される
3. br-tun 側に処理が移る
4. table:0 -> table: 1 -> table: 2 -> table: 20 の順で処理が進み、table: 20 では Unicastパケットの L2 Population 処理が実施された上で encap 情報が付加される

br-int は br-tun に patch 接続されているので、当該パケットは encap された上で br-tun に output されます。

```bash:ofproto/trace(node2)
ubuntu@node2:~/devstack$ sudo ovs-appctl ofproto/trace br-int in_port=$test02_port,icmp,nw_src=10.0.0.8,nw_dst=10.0.0.4,dl_src=$test02_hwaddr,dl_dst=$test05_hwaddr
Bridge: br-int
Flow: icmp,in_port=3,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_src=10.0.0.8,nw_dst=10.0.0.4,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0

Rule: table=0 cookie=0xdf4e2bbac0635a0b priority=9,in_port=3
OpenFlow actions=goto_table:25

        Resubmitted flow: icmp,in_port=3,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_src=10.0.0.8,nw_dst=10.0.0.4,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
        Resubmitted  odp: drop
        Resubmitted megaflow: recirc_id=0,ip,in_port=3,dl_src=fa:16:3e:76:47:75,nw_frag=no
        Rule: table=25 cookie=0xdf4e2bbac0635a0b priority=2,in_port=3,dl_src=fa:16:3e:76:47:75
        OpenFlow actions=NORMAL
        forwarding to learned port

                Resubmitted flow: icmp,in_port=1,dl_vlan=1,dl_vlan_pcp=0,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_src=10.0.0.8,nw_dst=10.0.0.4,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
                Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                Resubmitted  odp: drop
                Resubmitted megaflow: recirc_id=0,ip,in_port=3,vlan_tci=0x0000/0x1fff,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_frag=no
                Rule: table=0 cookie=0x18f25abfba9cb2e7 priority=1,in_port=1
                OpenFlow actions=goto_table:1

                        Resubmitted flow: unchanged
                        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                        Resubmitted  odp: drop
                        Resubmitted megaflow: recirc_id=0,ip,in_port=3,vlan_tci=0x0000/0x1fff,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_frag=no
                        Rule: table=1 cookie=0x18f25abfba9cb2e7 priority=0
                        OpenFlow actions=goto_table:2

                                Resubmitted flow: unchanged
                                Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                                Resubmitted  odp: drop
                                Resubmitted megaflow: recirc_id=0,ip,in_port=3,vlan_tci=0x0000/0x1fff,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_frag=no
                                Rule: table=2 cookie=0x18f25abfba9cb2e7 priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00
                                OpenFlow actions=goto_table:20

                                        Resubmitted flow: unchanged
                                        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                                        Resubmitted  odp: drop
                                        Resubmitted megaflow: recirc_id=0,ip,in_port=3,vlan_tci=0x0000/0x1fff,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_frag=no
                                        Rule: table=20 cookie=0x18f25abfba9cb2e7 priority=2,dl_vlan=1,dl_dst=fa:16:3e:96:e2:a4
                                        OpenFlow actions=pop_vlan,set_field:0x42->tun_id,output:3
                                        output to kernel tunnel

Final flow: icmp,in_port=3,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_src=10.0.0.8,nw_dst=10.0.0.4,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
Megaflow: recirc_id=0,ip,tun_id=0,in_port=3,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_ecn=0,nw_frag=no
Datapath actions: set(tunnel(tun_id=0x42,src=192.168.1.12,dst=192.168.1.13,ttl=64,flags(df|key))),9
```

### ovs packet trace (node3)
node3側で packet trace を実行すると、br-tun から br-int に転送され、normal forward (L2転送)が実施されることが分かります。

```bash:ofproto/trace(node3)
ubuntu@node3:~/devstack$ sudo ovs-appctl ofproto/trace br-tun in_port=$test02_vxport,tun_id=$private_segid,icmp,nw_src=10.0.0.8,nw_dst=10.0.0.4,dl_src=$test02_hwaddr,dl_dst=$test05_hwaddr
Bridge: br-tun
Flow: icmp,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_src=10.0.0.8,nw_dst=10.0.0.4,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0

Rule: table=0 cookie=0xc87c8aa025742883 priority=1,in_port=2
OpenFlow actions=goto_table:4

        Resubmitted flow: icmp,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_src=10.0.0.8,nw_dst=10.0.0.4,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
        Resubmitted  odp: drop
        Resubmitted megaflow: recirc_id=0,ip,tun_id=0x42,in_port=2,nw_frag=no
        Rule: table=4 cookie=0xc87c8aa025742883 priority=1,tun_id=0x42
        OpenFlow actions=push_vlan:0x8100,set_field:4098->vlan_vid,goto_table:9

                Resubmitted flow: icmp,tun_id=0x42,in_port=2,dl_vlan=2,dl_vlan_pcp=0,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_src=10.0.0.8,nw_dst=10.0.0.4,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
                Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                Resubmitted  odp: drop
                Resubmitted megaflow: recirc_id=0,ip,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,nw_frag=no
                Rule: table=9 cookie=0xc87c8aa025742883 priority=0
                OpenFlow actions=goto_table:10

                        Resubmitted flow: unchanged
                        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                        Resubmitted  odp: drop
                        Resubmitted megaflow: recirc_id=0,ip,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,nw_frag=no
                        Rule: table=10 cookie=0xc87c8aa025742883 priority=1
                        OpenFlow actions=learn(table=20,hard_timeout=300,priority=1,cookie=0xc87c8aa025742883,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:0->NXM_OF_VLAN_TCI[],load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],output:OXM_OF_IN_PORT[]),output:1

                                Resubmitted flow: icmp,in_port=2,dl_vlan=2,dl_vlan_pcp=0,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_src=10.0.0.8,nw_dst=10.0.0.4,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
                                Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                                Resubmitted  odp: drop
                                Resubmitted megaflow: recirc_id=0,ip,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,nw_frag=no
                                Rule: table=0 cookie=0xe938f5bca5c51f3c priority=1
                                OpenFlow actions=NORMAL
                                forwarding to learned port

Final flow: icmp,tun_id=0x42,in_port=2,dl_vlan=2,dl_vlan_pcp=0,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_src=10.0.0.8,nw_dst=10.0.0.4,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
Megaflow: recirc_id=0,ip,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:96:e2:a4,nw_frag=no
Datapath actions: 10
```

### node3 watch ovs-ofctl dump-flows
今度は、ofproto/trace は使わずに dump-flows コマンドを用いて br-tun の packet flow を 追跡します。

次のように、watch コマンドと組み合わせて ovs-ofctl dump-flows コマンドを実行することで、リアルタイムに適用されたフローのカウントなどを確認できます。

```bash:watch_dump-flows
watch -n.5 "sudo ovs-ofctl dump-flows br-tun | grep -v n_packets=0"
watch -n.5 "sudo ovs-ofctl dump-flows br-int | grep -v n_packets=0"
```

dump-flows br-tun コマンドを実行すると、カウントアップされている flow が次の2つであることが分かります。

1. cookie=0xc87c8aa025742883, duration=6228.829s, table=10, n_packets=2333, n_bytes=222605, idle_age=0, priority=1 actions=learn(table=20,hard_timeout=300,priority=1,cookie=0xc87c8aa025742883,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:0->NXM_OF_VLAN_TCI[],load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],output:OXM_OF_IN_PORT[]),output:1
2. cookie=0xc87c8aa025742883, duration=6070.579s, table=20, n_packets=2370, n_bytes=224812, idle_age=0, priority=2,dl_vlan=2,dl_dst=fa:16:3e:76:47:75 actions=strip_vlan,load:0x42->NXM_NX_TUN_ID[],output:2

"2."は output:2(vxlan-c0a8010c)のため、icmp reply packet になります。

"1." が適用されることで、outbound の icmp-echo packet は table=20(l2 population table) を learning table として用いて、br-int に packet が転送されます。

dump-flows br-int コマンドを実行すると、カウントアップされている flow は次であることが分かります。

- cookie=0xe938f5bca5c51f3c, duration=6603.378s, table=0,n_packets=2976, n_bytes=286958, idle_age=0, priority=1 actions=NORMAL

上記flowが適用されることで、br-int に届いた icmp-echo packet は NORMAL action (通常の l2 forwarding) 動作により、VM(test05)にパケットが着信します。


## Packet Flow (Different Subnet / Different Compute Node)

異なる Subnet への通信の場合、下図のように outbound / inbound で異なる経路となります。
outbound側の qrouter にて routing処理がされる点を除き、同一の Subnet での Packet Flow と同じになります。

![different-net1.png](https://qiita-image-store.s3.amazonaws.com/0/96389/45060abc-a213-3290-72ca-c24694c7a49b.png)


```bash:node2
test02_qrifname=qr-`openstack port list | grep 10.0.0.1 | awk '{print $2}' | cut -c1-11`
test02_qrhwaddr=`openstack port list | grep 10.0.0.1 | awk '{print $5}'`
test04_qrifname=qr-`openstack port list | grep \'10.1.0.1\' | awk '{print $2}' | cut -c1-11`
test03_qrhwaddr=`openstack port list | grep \'10.1.0.1\' | awk '{print $5}'`
test04_hwaddr=`openstack port list | grep 10.1.0.10 | awk '{print $5}'`
test04_qrhwaddr=`openstack port list | grep \'10.1.0.1\' | awk '{print $5}'`
test04_ifname=qvo`openstack port list | grep 10.1.0.10 | awk '{print $2}' | cut -c1-11`
test02_nhport=`sudo ovs-ofctl show br-int | grep $test04_qrifname | cut -d'(' -f1 | cut -d' ' -f2`
```

### node2 outbound Traffic Flow (router)
次の コマンド出力 は、qvo28e6e267-f3(10.0.0.1/24) から送信された icmp パケットの flow になります。
出力結果より、normal forward (通常の L2転送)が実施されることが分かります。
以上より、normal forward が実施されることにより、default route の qr-aae8ab78-22 (10.0.0.1) がパケット転送することになります。

```bash
ubuntu@node2:~/devstack$ sudo ovs-appctl ofproto/trace br-int in_port=$test02_port,icmp,nw_src=10.0.0.8,nw_dst=10.1.0.10,dl_src=$test02_hwaddr,dl_dst=$test02_qrhwaddr
Bridge: br-int
Flow: icmp,in_port=3,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:9c:cf:de,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0

Rule: table=0 cookie=0xdf4e2bbac0635a0b priority=9,in_port=3
OpenFlow actions=goto_table:25

        Resubmitted flow: icmp,in_port=3,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:9c:cf:de,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
        Resubmitted  odp: drop
        Resubmitted megaflow: recirc_id=0,ip,in_port=3,dl_src=fa:16:3e:76:47:75,nw_frag=no
        Rule: table=25 cookie=0xdf4e2bbac0635a0b priority=2,in_port=3,dl_src=fa:16:3e:76:47:75
        OpenFlow actions=NORMAL
        forwarding to learned port

Final flow: icmp,in_port=3,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:9c:cf:de,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
Megaflow: recirc_id=0,ip,in_port=3,vlan_tci=0x0000/0x1fff,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:9c:cf:de,nw_frag=no
Datapath actions: 8
```

次に、qrouter では connected route による routing が実施され、qr-2909fe1f-46 から当該パケットが送信されます。

qr-2909fe1f-46 から送信されたパケットの flow は次のようなコマンドで確認することができます。コマンド出力結果より、VXLAN にて port: 3 (vxlan-c0a8010d) にパケットが出力されることが分かります。

```bash
ubuntu@node2:~/devstack$ sudo ovs-appctl ofproto/trace br-int in_port=$test02_nhport,icmp,nw_src=10.0.0.8,nw_dst=10.1.0.10,dl_src=$test04_qrhwaddr,dl_dst=$test04_hwaddr                         [9/9511]
Bridge: br-int
Flow: icmp,in_port=5,vlan_tci=0x0000,dl_src=fa:16:3e:5c:3d:f9,dl_dst=fa:16:3e:23:c5:28,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0

Rule: table=0 cookie=0xdf4e2bbac0635a0b priority=1
OpenFlow actions=NORMAL
no learned MAC for destination, flooding

        Resubmitted flow: icmp,in_port=2,dl_vlan=2,dl_vlan_pcp=0,dl_src=fa:16:3e:5c:3d:f9,dl_dst=fa:16:3e:23:c5:28,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
        Resubmitted  odp: push_vlan(vid=2,pcp=0),1
        Resubmitted megaflow: recirc_id=0,ip,in_port=5,vlan_tci=0x0000,dl_src=fa:16:3e:5c:3d:f9,dl_dst=fa:16:3e:23:c5:28,nw_frag=no
        Rule: table=0 cookie=0x575f21b14190a9c3 priority=2,in_port=2
        OpenFlow actions=goto_table:1

                Resubmitted flow: unchanged
                Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                Resubmitted  odp: push_vlan(vid=2,pcp=0),1
                Resubmitted megaflow: recirc_id=0,ip,in_port=5,vlan_tci=0x0000,dl_src=fa:16:3e:5c:3d:f9,dl_dst=fa:16:3e:23:c5:28,nw_frag=no
                Rule: table=1 cookie=0x575f21b14190a9c3 priority=0
                OpenFlow actions=goto_table:2

                        Resubmitted flow: unchanged
                        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                        Resubmitted  odp: push_vlan(vid=2,pcp=0),1
                        Resubmitted megaflow: recirc_id=0,ip,in_port=5,vlan_tci=0x0000,dl_src=fa:16:3e:5c:3d:f9,dl_dst=fa:16:3e:23:c5:28,nw_frag=no
                        Rule: table=2 cookie=0x575f21b14190a9c3 priority=2,in_port=2
                        OpenFlow actions=drop

        Resubmitted flow: icmp,in_port=1,dl_vlan=2,dl_vlan_pcp=0,dl_src=fa:16:3e:5c:3d:f9,dl_dst=fa:16:3e:23:c5:28,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
        Resubmitted  odp: push_vlan(vid=2,pcp=0),1
        Resubmitted megaflow: recirc_id=0,ip,in_port=5,vlan_tci=0x0000,dl_src=fa:16:3e:5c:3d:f9,dl_dst=fa:16:3e:23:c5:28,nw_frag=no
        Rule: table=0 cookie=0x18f25abfba9cb2e7 priority=1,in_port=1
        OpenFlow actions=goto_table:1

                Resubmitted flow: unchanged
                Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                Resubmitted  odp: push_vlan(vid=2,pcp=0),1
                Resubmitted megaflow: recirc_id=0,ip,in_port=5,vlan_tci=0x0000,dl_src=fa:16:3e:5c:3d:f9,dl_dst=fa:16:3e:23:c5:28,nw_frag=no
                Rule: table=1 cookie=0x18f25abfba9cb2e7 priority=1,dl_vlan=2,dl_src=fa:16:3e:5c:3d:f9
                OpenFlow actions=set_field:fa:16:3f:73:c3:04->eth_src,goto_table:2

                        Resubmitted flow: icmp,in_port=1,dl_vlan=2,dl_vlan_pcp=0,dl_src=fa:16:3f:73:c3:04,dl_dst=fa:16:3e:23:c5:28,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
                        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                        Resubmitted  odp: push_vlan(vid=2,pcp=0),1
                        Resubmitted megaflow: recirc_id=0,ip,in_port=5,vlan_tci=0x0000,dl_src=fa:16:3e:5c:3d:f9,dl_dst=fa:16:3e:23:c5:28,nw_frag=no
                        Rule: table=2 cookie=0x18f25abfba9cb2e7 priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00
                        OpenFlow actions=goto_table:20

                                Resubmitted flow: unchanged
                                Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                                Resubmitted  odp: push_vlan(vid=2,pcp=0),1
                                Resubmitted megaflow: recirc_id=0,ip,in_port=5,vlan_tci=0x0000,dl_src=fa:16:3e:5c:3d:f9,dl_dst=fa:16:3e:23:c5:28,nw_frag=no
                                Rule: table=20 cookie=0x18f25abfba9cb2e7 priority=2,dl_vlan=2,dl_dst=fa:16:3e:23:c5:28
                                OpenFlow actions=pop_vlan,set_field:0x5->tun_id,output:3
                                output to kernel tunnel
```

### qrouter に同一の IPアドレスが割り当てられているのに通信できるのは何故?
ところで、IP Routing に詳しいエンジニアであれば、各 compute-node の qrouter にそれぞれ 同一の IPアドレスが設定されているのに通信ができるのはおかしいと気づくと思います。

どのようにして複数ノードに割り当てられた同一IPアドレスで通信が成立するのでしょうか。上記 Packet Flow を観察すると、動作の仕掛けが分かります。

- OpenFlow actions=set_field:fa:16:3f:73:c3:04->eth_src,goto_table:2

対応する Flow は、次のようになります。qr-2909fe1f-46(10.1.0.1) の MACアドレスは fa:16:3e:5c:3d:f9 なので、ds_src にマッチして action (mod_dl_src) が実行されます。
つまり、トンネルからの送信時に Src MACアドレス が fa:16:3f:73:c3:04 に書き換えられます。

```bash
ubuntu@node2:~/devstack$ sudo ovs-ofctl dump-flows br-tun | grep -v n_packets=0 | grep fa:16:3e:5c:3d:f9
 cookie=0x18f25abfba9cb2e7, duration=99527.353s, table=1, n_packets=6801, n_bytes=666498, idle_age=0, hard_age=65534, priority=1,dl_vlan=2,dl_src=fa:16:3e:5c:3d:f9 actions=mod_dl_src:fa:16:3f:73:c3:04,resubmit(,2)
```

node3では、br-int にて fa:16:3f:73:c3:04 に書きられられた MACアドレスの書き戻しを実施しています。
宛先のMACアドレスが fa:16:3e:23:c5:28 (10.1.0.10) の場合は、action(mod_dl_src:fa:16:3e:5c:3d:f9) が実行されることにより、あたかも node3内の qrouter から受信したパケットのように振舞われています。

少々トリッキーな仕掛けではありますが、このような仕掛けにより DVR では 各 compute node で L3 Routing を実現することができます。

なお、node3 側での当該 Flow は、次のようになります。

```bash
ubuntu@node3:~$ sudo ovs-ofctl dump-flows br-int | grep -v n_packets=0 | grep 3d:f9
 cookie=0xe938f5bca5c51f3c, duration=100130.672s, table=1, n_packets=7435, n_bytes=728630, idle_age=0, hard_age=65534, priority=4,dl_vlan=1,dl_dst=fa:16:3e:23:c5:28 actions=strip_vlan,mod_dl_src:fa:16:3e:5c:3d:f9,output:3
```

### ovs packet trace (node3)
node3側で br-tun を起点として packet trace を実行すると、br-tun から br-int に転送され、normal forward (L2転送)が実施されることが分かります。


```bash:node3
test02_hwaddr=`openstack port list | grep 10.0.0.8 | awk '{print $5}'`
test04_hwaddr=`openstack port list | grep 10.1.0.10 | awk '{print $5}'`
private2_segid=$(openstack network show `openstack network list | grep private2\ | awk '{print $2}'` | grep segmentation_id | awk '{print $4}')
```

```bash:ofproto/trace(node3)
ubuntu@node3:~/devstack$ sudo ovs-appctl ofproto/trace br-tun in_port=$test02_vxport,tun_id=$private2_segid,icmp,nw_src=10.0.0.8,nw_dst=10.1.0.10,dl_src=$test02_hwaddr,dl_dst=$test04_hwaddr
Bridge: br-tun
Flow: icmp,tun_id=0x5,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:23:c5:28,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0

Rule: table=0 cookie=0xc87c8aa025742883 priority=1,in_port=2
OpenFlow actions=goto_table:4

        Resubmitted flow: icmp,tun_id=0x5,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:23:c5:28,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
        Resubmitted  odp: drop
        Resubmitted megaflow: recirc_id=0,ip,tun_id=0x5,in_port=2,nw_frag=no
        Rule: table=4 cookie=0xc87c8aa025742883 priority=1,tun_id=0x5
        OpenFlow actions=push_vlan:0x8100,set_field:4097->vlan_vid,goto_table:9

                Resubmitted flow: icmp,tun_id=0x5,in_port=2,dl_vlan=1,dl_vlan_pcp=0,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:23:c5:28,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
                Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                Resubmitted  odp: drop
                Resubmitted megaflow: recirc_id=0,ip,tun_id=0x5,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,nw_frag=no
                Rule: table=9 cookie=0xc87c8aa025742883 priority=0
                OpenFlow actions=goto_table:10

                        Resubmitted flow: unchanged
                        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                        Resubmitted  odp: drop
                        Resubmitted megaflow: recirc_id=0,ip,tun_id=0x5,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,nw_frag=no
                        Rule: table=10 cookie=0xc87c8aa025742883 priority=1
                        OpenFlow actions=learn(table=20,hard_timeout=300,priority=1,cookie=0xc87c8aa025742883,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:0->NXM_OF_VLAN_TCI[],load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],output:OXM_OF_IN_PORT[]),output:1

                                Resubmitted flow: icmp,in_port=2,dl_vlan=1,dl_vlan_pcp=0,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:23:c5:28,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
                                Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                                Resubmitted  odp: drop
                                Resubmitted megaflow: recirc_id=0,ip,tun_id=0x5,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,nw_frag=no
                                Rule: table=0 cookie=0xe938f5bca5c51f3c priority=1
                                OpenFlow actions=NORMAL
                                forwarding to learned port

Final flow: icmp,tun_id=0x5,in_port=2,dl_vlan=1,dl_vlan_pcp=0,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:23:c5:28,nw_src=10.0.0.8,nw_dst=10.1.0.10,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
Megaflow: recirc_id=0,ip,tun_id=0x5,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:23:c5:28,nw_frag=no
Datapath actions: 5
```

### tcpdump (node3)
ping 通信が発生している状態で node3 で packet dump を取得すると、VNI: 5 にて VXLAN encap された icmp-echo を受信していることが分かります。

```bash:tcpdump_node3_datapath
ubuntu@node3:~/devstack$ sudo tcpdump -n -e -v -i enp0s8
tcpdump: listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes
18:52:49.260843 08:00:27:8b:a7:13 > 08:00:27:aa:d4:28, ethertype IPv4 (0x0800), length 148: (tos 0x0, ttl 64, id 54582, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.1.12.51074 > 192.168.1.13.4789: VXLAN, flags [I] (0x08), vni 5
fa:16:3f:73:c3:04 > fa:16:3e:23:c5:28, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 31944, offset 0, flags [DF], proto ICMP (1), length 84)
    10.0.0.8 > 10.1.0.10: ICMP echo request, id 27393, seq 3615, length 64
18:52:49.261417 08:00:27:aa:d4:28 > 08:00:27:8b:a7:13, ethertype IPv4 (0x0800), length 148: (tos 0x0, ttl 64, id 29082, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.1.13.46416 > 192.168.1.12.4789: VXLAN, flags [I] (0x08), vni 66
fa:16:3f:59:35:b1 > fa:16:3e:76:47:75, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 63351, offset 0, flags [none], proto ICMP (1), length 84)
    10.1.0.10 > 10.0.0.8: ICMP echo reply, id 27393, seq 3615, length 64
```

## Packet Flow (SNAT; Not Floating-IP)
SNAT(Not Floating-IP)の Packet Flow について解説します。

DVR を有効化している場合、次の namespace が追加されます。
- snat-(id of neutron router)
- router-(id of neutron router)

snat の場合、上記のうち snat-* にて SNAT処理(iptables)が実施されます。

Packet Flow は、次の図のようになります。

![snat.png](https://qiita-image-store.s3.amazonaws.com/0/96389/7de23d28-b1e1-ce56-2481-c8a858e0aac5.png)


```bash:node1
cd ~/devstack; source openrc admin
router1_id=`openstack router list | grep router1 | awk '{print $2}'`
ip netns show
sudo ip netns exec snat-$router1_id ip a
```

node1(Network Node)の namespace / ip address 一覧は、次のようになります。

```bash:seat-ip_a
ubuntu@node1:~/devstack$ ip netns show
qdhcp-1f94d3b2-fab2-4eba-bf5a-09a646744c50
snat-bd7982cb-bb78-4cc6-b3f0-f8a828947718
qrouter-bd7982cb-bb78-4cc6-b3f0-f8a828947718
qdhcp-29c3b4e4-a807-48e3-8df9-71aab99dcd6b

ubuntu@node1:~/devstack$ sudo ip netns exec snat-$router1_id ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    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
13: sg-adafc8f8-1e: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default qlen 1
    link/ether fa:16:3e:47:34:80 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.3/26 brd 10.0.0.63 scope global sg-adafc8f8-1e
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe47:3480/64 scope link 
       valid_lft forever preferred_lft forever
14: qg-242f9c7b-c1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1
    link/ether fa:16:3e:af:c7:ce brd ff:ff:ff:ff:ff:ff
    inet 172.24.4.3/24 brd 172.24.4.255 scope global qg-242f9c7b-c1
       valid_lft forever preferred_lft forever
    inet6 2001:db8::9/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:feaf:c7ce/64 scope link 
       valid_lft forever preferred_lft forever
16: sg-39996102-8b: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default qlen 1
    link/ether fa:16:3e:69:37:93 brd ff:ff:ff:ff:ff:ff
    inet6 fda0:6cec:a994::5/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe69:3793/64 scope link 
       valid_lft forever preferred_lft forever
19: sg-bb562f9c-59: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default qlen 1
    link/ether fa:16:3e:a9:a2:19 brd ff:ff:ff:ff:ff:ff
    inet 10.1.0.6/24 brd 10.1.0.255 scope global sg-bb562f9c-59
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fea9:a219/64 scope link 
       valid_lft forever preferred_lft forever
```

snat-$router1_id の ip address は次のようになります。

- 'sg-*'
  - SNAT traffic の private segment 側接続点になります
- 'qg-*'
  - SNAT traffic の public segment 側接続点になります
  - こちらの NIC に割り当てられた IPアドレスを用いて、SNAT(SNAPT) が掛けられます


また、node2 qrouter-$router1_id の IPアドレス構成は、次のようになります。DVR の場合は、compute-node 側にも default gateway (10.0.0.1) が割り当てられていることが分かります。

```bash:node2_namespace_qrouter
ubuntu@node2:~/devstack$ sudo ip netns exec qrouter-$router1_id ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    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
15: qr-12fa6289-8f: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default qlen 1
    link/ether fa:16:3e:5e:30:73 brd ff:ff:ff:ff:ff:ff
    inet6 fda0:6cec:a994::1/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe5e:3073/64 scope link 
       valid_lft forever preferred_lft forever
16: qr-2909fe1f-46: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default qlen 1
    link/ether fa:16:3e:5c:3d:f9 brd ff:ff:ff:ff:ff:ff
    inet 10.1.0.1/24 brd 10.1.0.255 scope global qr-2909fe1f-46
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe5c:3df9/64 scope link 
       valid_lft forever preferred_lft forever
17: qr-aae8ab78-22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default qlen 1
    link/ether fa:16:3e:9c:cf:de brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.1/26 brd 10.0.0.63 scope global qr-aae8ab78-22
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe9c:cfde/64 scope link 
       valid_lft forever preferred_lft forever
```

### OVS Packet Trace (node2)
vm(test02) の outbound traffic について、node2 で Packet Trace を実施すると、NORMAL forwarding になることが分かります。

```bash:node1
node2_host='192.168.1.12'
test02_vxifname=`printf "vxlan-%02x%02x%02x%02x" ${node2_host//./ }`
test02_vxport=`sudo ovs-ofctl show br-tun | grep $test02_vxifname | cut -d'(' -f1 | cut -d' ' -f2`
private_segid=$(openstack network show `openstack network list | grep private\ | awk '{print $2}'` | grep segmentation_id | awk '{print $4}')
test02_qrhwaddr=`openstack port list | grep 10.0.0.1 | awk '{print $5}'`
test02_hwaddr=`openstack port list | grep 10.0.0.8 | awk '{print $5}'`
router1_id=`openstack router list | grep router1 | awk '{print $2}'`
```

```bash:ofproto_trace_brint
ubuntu@node2:~/devstack$ sudo ovs-appctl ofproto/trace br-int in_port=$test02_port,icmp,nw_src=10.0.0.8,nw_dst=8.8.8.8,dl_src=$test02_hwaddr,dl_dst=$test02_qrhwaddr
Bridge: br-int
Flow: icmp,in_port=3,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:9c:cf:de,nw_src=10.0.0.8,nw_dst=8.8.8.8,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0

Rule: table=0 cookie=0xdf4e2bbac0635a0b priority=9,in_port=3
OpenFlow actions=goto_table:25

        Resubmitted flow: icmp,in_port=3,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:9c:cf:de,nw_src=10.0.0.8,nw_dst=8.8.8.8,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
        Resubmitted  odp: drop
        Resubmitted megaflow: recirc_id=0,ip,in_port=3,dl_src=fa:16:3e:76:47:75,nw_frag=no
        Rule: table=25 cookie=0xdf4e2bbac0635a0b priority=2,in_port=3,dl_src=fa:16:3e:76:47:75
        OpenFlow actions=NORMAL
        forwarding to learned port

Final flow: icmp,in_port=3,vlan_tci=0x0000,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:9c:cf:de,nw_src=10.0.0.8,nw_dst=8.8.8.8,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
Megaflow: recirc_id=0,ip,in_port=3,vlan_tci=0x0000/0x1fff,dl_src=fa:16:3e:76:47:75,dl_dst=fa:16:3e:9c:cf:de,nw_frag=no
Datapath actions: 8
```

### Policy Based Routing / SNAT (node1)
VM(test02) から出力されたパケットは、VXLAN で encap されて node1 に送信されます。
node1 では、snat namespace にて Policy Based Routing(PBR) および SNAT が実施された上で br-ex に転送されます。

ここでは、PBR および SNAT の動作について確認していきます。

br-int の qr-aae8ab78-22 に着信したパケットは、Policy Based Routing により next-hop が 10.0.0.3 に変更されます。
結果として、snat-$router1 namespace のインタフェース(sg-1a14961d-f9)にパケットが転送されます。

```bash:node1_pbr
ubuntu@node1:~$ sudo ip netns exec qrouter-$router1_id ip route show
10.0.0.0/26 dev qr-aae8ab78-22  proto kernel  scope link  src 10.0.0.1 
10.1.0.0/24 dev qr-2909fe1f-46  proto kernel  scope link  src 10.1.0.1 

ubuntu@node1:~$ sudo ip netns exec qrouter-$router1_id ip rule show
0:      from all lookup local 
32766:  from all lookup main 
32767:  from all lookup default 
167772161:      from 10.0.0.1/26 lookup 167772161 
167837697:      from 10.1.0.1/24 lookup 167837697 

# table(167772161) の routing table を確認すると、default route が 10.0.0.3 であることが分かります。
ubuntu@node1:~$ sudo ip netns exec qrouter-$router1_id ip route show table 167772161
default via 10.0.0.3 dev qr-aae8ab78-22 
```

node2 の namespace(qrouter) にて tcpdump を実行すると、VM(test02) fa:16:3e:76:47:75 -> default route (```fa:16:3e:9c:cf:de```) の通信が次の MAC アドレス にて再送されていることが分かります。

- 10.0.0.1 (```fa:16:3e:9c:cf:de```) -> 10.0.0.3 (```fa:16:3e:47:34:80```)

```bash:node2_tcpdump
ubuntu@node2:~/devstack$ sudo ip netns exec qrouter-$router1_id tcpdump -nn -e -i qr-aae8ab78-22: icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on qr-aae8ab78-22:, link-type EN10MB (Ethernet), capture size 262144 bytes
^C06:03:59.410625 fa:16:3e:76:47:75 > fa:16:3e:9c:cf:de, ethertype IPv4 (0x0800), length 98: 10.0.0.8 > 8.8.8.8: ICMP echo request, id 29441, seq 2939, length 64
06:03:59.410650 fa:16:3e:9c:cf:de > fa:16:3e:47:34:80, ethertype IPv4 (0x0800), length 98: 10.0.0.8 > 8.8.8.8: ICMP echo request, id 29441, seq 2939, length 64
06:04:00.411124 fa:16:3e:76:47:75 > fa:16:3e:9c:cf:de, ethertype IPv4 (0x0800), length 98: 10.0.0.8 > 8.8.8.8: ICMP echo request, id 29441, seq 2940, length 64
06:04:00.411149 fa:16:3e:9c:cf:de > fa:16:3e:47:34:80, ethertype IPv4 (0x0800), length 98: 10.0.0.8 > 8.8.8.8: ICMP echo request, id 29441, seq 2940, length 64

4 packets captured
4 packets received by filter
0 packets dropped by kernel
```

icmp通信を Data Path 側で tcpdump すると、次のように src MACアドレスが書き換わっていることが分かります。

- (fa:16:3f:73:c3:04) -> 10.0.0.3 (fa:16:3e:47:34:80)

```bash:node2_tcpdump(datapath)
ubuntu@node2:~/devstack$ sudo tcpdump -n -e -i enp0s8 udp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes
06:44:54.722987 08:00:27:8b:a7:13 > 08:00:27:a6:c6:02, ethertype IPv4 (0x0800), length 148: 192.168.1.12.42055 > 192.168.1.11.4789: VXLAN, flags [I] (0x08), vni 66
fa:16:3f:73:c3:04 > fa:16:3e:47:34:80, ethertype IPv4 (0x0800), length 98: 10.0.0.8 > 8.8.8.8: ICMP echo request, id 33025, seq 542, length 64
06:44:54.785364 08:00:27:a6:c6:02 > 08:00:27:8b:a7:13, ethertype IPv4 (0x0800), length 148: 192.168.1.11.36123 > 192.168.1.12.4789: VXLAN, flags [I] (0x08), vni 66
fa:16:3e:47:34:80 > fa:16:3e:76:47:75, ethertype IPv4 (0x0800), length 98: 8.8.8.8 > 10.0.0.8: ICMP echo reply, id 33025, seq 542, length 64
```

上記の MACアドレス書き換えは、次の Flow Rule で実施されています。

```bash:ofctl_dump(br-tun)
ubuntu@node2:~/devstack$ sudo ovs-ofctl dump-flows br-tun | grep -v n_packets=0 | grep fa:16:3f:73:c3:04
 cookie=0x18f25abfba9cb2e7, duration=61039.306s, table=1, n_packets=2, n_bytes=240, idle_age=61037, priority=1,dl_vlan=1,dl_src=fa:16:3e:5e:30:73 actions=mod_dl_src:fa:16:3f:73:c3:04,resubmit(,2)
 cookie=0x18f25abfba9cb2e7, duration=61036.936s, table=1, n_packets=8449, n_bytes=827930, idle_age=0, priority=1,dl_vlan=1,dl_src=fa:16:3e:9c:cf:de actions=mod_dl_src:fa:16:3f:73:c3:04,resubmit(,2)
 cookie=0x18f25abfba9cb2e7, duration=61036.797s, table=1, n_packets=4300, n_bytes=421400, idle_age=21072, priority=1,dl_vlan=2,dl_src=fa:16:3e:5c:3d:f9 actions=mod_dl_src:fa:16:3f:73:c3:04,resubmit(,2)
```

src / dst の MACアドレスを変更して Packet Flow を Trace すると、次のようになり、src MACアドレスが ```fa:16:3e:9c:cf:de``` に書き戻された上で Port: 5(sg-adafc8f8-1e) に入力されていることが分かります。

```bash
ubuntu@node1:~$ sudo ovs-appctl ofproto/trace br-tun in_port=$test02_vxport,tun_id=$private_segid,icmp,nw_src=10.0.0.8,nw_dst=8.8.8.8,dl_src=fa:16:3f:73:c3:04,dl_dst=fa:16:3e:47:34:80
Bridge: br-tun
Flow: icmp,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3f:73:c3:04,dl_dst=fa:16:3e:47:34:80,nw_src=10.0.0.8,nw_dst=8.8.8.8,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0

Rule: table=0 cookie=0x530c2fbc8a57ee8 priority=1,in_port=2
OpenFlow actions=goto_table:4

        Resubmitted flow: icmp,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3f:73:c3:04,dl_dst=fa:16:3e:47:34:80,nw_src=10.0.0.8,nw_dst=8.8.8.8,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
        Resubmitted  odp: drop
        Resubmitted megaflow: recirc_id=0,ip,tun_id=0x42,in_port=2,nw_frag=no
        Rule: table=4 cookie=0x530c2fbc8a57ee8 priority=1,tun_id=0x42
        OpenFlow actions=push_vlan:0x8100,set_field:4097->vlan_vid,goto_table:9

                Resubmitted flow: icmp,tun_id=0x42,in_port=2,dl_vlan=1,dl_vlan_pcp=0,dl_src=fa:16:3f:73:c3:04,dl_dst=fa:16:3e:47:34:80,nw_src=10.0.0.8,nw_dst=8.8.8.8,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
                Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                Resubmitted  odp: drop
                Resubmitted megaflow: recirc_id=0,ip,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3f:73:c3:04,nw_frag=no
                Rule: table=9 cookie=0x530c2fbc8a57ee8 priority=1,dl_src=fa:16:3f:73:c3:04
                OpenFlow actions=output:1

                        Resubmitted flow: icmp,in_port=2,dl_vlan=1,dl_vlan_pcp=0,dl_src=fa:16:3f:73:c3:04,dl_dst=fa:16:3e:47:34:80,nw_src=10.0.0.8,nw_dst=8.8.8.8,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
                        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                        Resubmitted  odp: drop
                        Resubmitted megaflow: recirc_id=0,ip,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3f:73:c3:04,nw_frag=no
                        Rule: table=0 cookie=0x3bcb5928c0b807d3 priority=2,in_port=2,dl_src=fa:16:3f:73:c3:04
                        OpenFlow actions=goto_table:1

                                Resubmitted flow: unchanged
                                Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
                                Resubmitted  odp: drop
                                Resubmitted megaflow: recirc_id=0,ip,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3f:73:c3:04,dl_dst=fa:16:3e:47:34:80,nw_frag=no
                                Rule: table=1 cookie=0x3bcb5928c0b807d3 priority=4,dl_vlan=1,dl_dst=fa:16:3e:47:34:80
                                OpenFlow actions=pop_vlan,set_field:fa:16:3e:9c:cf:de->eth_src,output:5

Final flow: icmp,tun_id=0x42,in_port=2,dl_vlan=1,dl_vlan_pcp=0,dl_src=fa:16:3f:73:c3:04,dl_dst=fa:16:3e:47:34:80,nw_src=10.0.0.8,nw_dst=8.8.8.8,nw_tos=0,nw_ecn=0,nw_ttl=0,icmp_type=0,icmp_code=0
Megaflow: recirc_id=0,ip,tun_id=0x42,in_port=2,vlan_tci=0x0000,dl_src=fa:16:3f:73:c3:04,dl_dst=fa:16:3e:47:34:80,nw_frag=no
Datapath actions: set(eth(src=fa:16:3e:9c:cf:de,dst=fa:16:3e:47:34:80)),7
```

SNATは、snat-$router1 namespace の iptables にて実施されます。
outboundパケットは Interface(qg-242f9c7b-c1) を通過する際に "--to-source" ルールにより source ip が 172.24.4.3 へ書き換えられます。

```bash
ubuntu@node1:~$ sudo ip netns exec snat-bd7982cb-bb78-4cc6-b3f0-f8a828947718 iptables -S -t nat
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N neutron-l3-agent-OUTPUT
-N neutron-l3-agent-POSTROUTING
-N neutron-l3-agent-PREROUTING
-N neutron-l3-agent-float-snat
-N neutron-l3-agent-snat
-N neutron-postrouting-bottom
-A PREROUTING -j neutron-l3-agent-PREROUTING
-A OUTPUT -j neutron-l3-agent-OUTPUT
-A POSTROUTING -j neutron-l3-agent-POSTROUTING
-A POSTROUTING -j neutron-postrouting-bottom
-A neutron-l3-agent-POSTROUTING ! -i qg-242f9c7b-c1 ! -o qg-242f9c7b-c1 -m conntrack ! --ctstate DNAT -j ACCEPT
-A neutron-l3-agent-snat -o qg-242f9c7b-c1 -j SNAT --to-source 172.24.4.3
-A neutron-l3-agent-snat -m mark ! --mark 0x2/0xffff -m conntrack --ctstate DNAT -j SNAT --to-source 172.24.4.3
-A neutron-postrouting-bottom -m comment --comment "Perform source NAT on outgoing traffic." -j neutron-l3-agent-snat
```

snat-$router1_id namespace の default route は 172.24.4.1 となるため、default route に従って qg-242f9c7b-c1 インタフェースにパケットが出力されます。

```bash
ubuntu@node1:~$ sudo ip netns exec snat-bd7982cb-bb78-4cc6-b3f0-f8a828947718 ip route
default via 172.24.4.1 dev qg-242f9c7b-c1 
10.0.0.0/26 dev sg-adafc8f8-1e  proto kernel  scope link  src 10.0.0.3 
10.1.0.0/24 dev sg-bb562f9c-59  proto kernel  scope link  src 10.1.0.6 
172.24.4.0/24 dev qg-242f9c7b-c1  proto kernel  scope link  src 172.24.4.3 
```

qg-242f9c7b-c1 は ovs では tag: 2 が設定されているので、Bridge: br-ex にて パケットが public network に出力されます。
ovs-ofctl dump-flows コマンドで確認すると、次のルールにマッチして strip_vlan された上で NORMAL forward が実施されることが分かります。

- priority=4,in_port=2,dl_vlan=2 actions=strip_vlan,NORMAL

```bash
ubuntu@node1:~$ sudo ovs-ofctl dump-flows br-ex | grep -v n_packets=0
NXST_FLOW reply (xid=0x4):
 cookie=0xc6d925f0f6def612, duration=63506.992s, table=0, n_packets=9954, n_bytes=944111, idle_age=0, priority=4,in_port=2,dl_vlan=2 actions=strip_vlan,NORMAL
 cookie=0xc6d925f0f6def612, duration=63547.494s, table=0, n_packets=1115, n_bytes=130023, idle_age=36, priority=2,in_port=2 actions=resubmit(,1)
 cookie=0xc6d925f0f6def612, duration=63547.493s, table=0, n_packets=12246, n_bytes=1193999, idle_age=0, priority=1 actions=resubmit(,3)
 cookie=0xc6d925f0f6def612, duration=63547.492s, table=1, n_packets=1115, n_bytes=130023, idle_age=36, priority=0 actions=resubmit(,2)
 cookie=0xc6d925f0f6def612, duration=63547.491s, table=2, n_packets=1115, n_bytes=130023, idle_age=36, priority=2,in_port=2 actions=drop
 cookie=0xc6d925f0f6def612, duration=63547.489s, table=3, n_packets=12246, n_bytes=1193999, idle_age=0, priority=1 actions=NORMAL
```


## Packet Flow (Floating IP)
Floating IP を割り当てたインスタンスの Packet Flow について解説します。
Packet Flow を図で表すと、次のようになります。

![fip2.png](https://qiita-image-store.s3.amazonaws.com/0/96389/93c34af5-9264-d9f7-2549-4b67fafa4749.png)



### Floating IP の割り当て
まずはじめに、VM(test02)に Floating IP を割り当てます。
実行するコマンドは、次のようになります。

```bash:create_floating_ip
ubuntu@node1:~$ openstack floating ip create public
+---------------------+--------------------------------------+
| Field               | Value                                |
+---------------------+--------------------------------------+
| created_at          | 2017-03-25T18:40:07Z                 |
| description         |                                      |
| fixed_ip_address    | None                                 |
| floating_ip_address | 172.24.4.12                          |
| floating_network_id | 6f83ddde-6be3-40d3-a1ec-f5241e7aca3d |
| id                  | a743d180-3409-404e-ae8f-44d1934a10fe |
| name                | None                                 |
| port_id             | None                                 |
| project_id          | 3309e5f3979a41fb860b3c409295bf47     |
| revision_number     | 1                                    |
| router_id           | None                                 |
| status              | DOWN                                 |
| updated_at          | 2017-03-25T18:40:07Z                 |
+---------------------+--------------------------------------+
```

```bash:openstack_floating_ip_list(floating_ip)
ubuntu@node1:~$ openstack floating ip list
+--------------------------------------+---------------------+------------------+------+--------------------------------------+----------------------------------+
| ID                                   | Floating IP Address | Fixed IP Address | Port | Floating Network                     | Project                          |
+--------------------------------------+---------------------+------------------+------+--------------------------------------+----------------------------------+
| a743d180-3409-404e-ae8f-44d1934a10fe | 172.24.4.12         | None             | None | 6f83ddde-6be3-40d3-a1ec-f5241e7aca3d | 3309e5f3979a41fb860b3c409295bf47 |
+--------------------------------------+---------------------+------------------+------+--------------------------------------+----------------------------------+
```

Floating IP (172.24.4.12) を test02 に割り当てます。

```bash
ubuntu@node1:~$ openstack server add floating ip test02 172.24.4.12
```

コマンドを実行すると、次のように test02 に 172.24.4.12 が割り当てられていることが分かります。

```bash:openstack_server_list_after
ubuntu@node1:~$ openstack server list
+--------------------------------------+--------+--------+---------------------------------------------------------------------+--------------------------+
| ID                                   | Name   | Status | Networks                                                            | Image Name               |
+--------------------------------------+--------+--------+---------------------------------------------------------------------+--------------------------+
| 7567c60a-2fcb-4db2-b56e-e55822838b6c | test05 | ACTIVE | private=10.0.0.4, fda0:6cec:a994:0:f816:3eff:fe96:e2a4              | cirros-0.3.5-x86_64-disk |
| 1b130d17-da5b-490a-9d6a-0fa44614d85c | test04 | ACTIVE | private2=10.1.0.10                                                  | cirros-0.3.5-x86_64-disk |
| cfe97f47-12db-4906-b73b-8cd08c1cd50e | test03 | ACTIVE | private2=10.1.0.12                                                  | cirros-0.3.5-x86_64-disk |
| df94802d-1c7d-4059-8a4d-8c732163a538 | test02 | ACTIVE | private=10.0.0.8, fda0:6cec:a994:0:f816:3eff:fe76:4775, 172.24.4.12 | cirros-0.3.5-x86_64-disk |
| 40d6518d-be98-4611-b6ce-50e030688876 | test01 | ACTIVE | private=10.0.0.7, fda0:6cec:a994:0:f816:3eff:fe5a:6e54              | cirros-0.3.5-x86_64-disk |
+--------------------------------------+--------+--------+---------------------------------------------------------------------+--------------------------+
```

### qrouter(node2) routing table
VM(test02) から出力されたパケットは、default route の qr-aae8ab78-22(namespace qrouter-$router1_id) に届きます。
qrouter-$router1_id namespace では table 16 に default route が登録されており、next-hop は 169.254.106.115 (dev rfp-bd7982cb-b) となります。

また、rfp-bd7982cb-b インタフェースは veth として fpr-bd7982cb-b (namespace fip-$router1_id)に接続されているため、fip の namespace に 制御が移ります。

```bash:qrouter_default_router(node2)
ubuntu@node2:~/devstack$ sudo ip netns exec qrouter-$router1_id ip route show table all | grep "default via"
default via 10.0.0.3 dev qr-aae8ab78-22  table 167772161 
default via 10.1.0.6 dev qr-2909fe1f-46  table 167837697 
default via 169.254.106.115 dev rfp-bd7982cb-b  table 16 
default via fda0:6cec:a994::5 dev qr-12fa6289-8f  table 765853562  metric 1024  pref medium
```

なお、DNAT 及び SNAT は  qrouter-$router1_id namespace の iptables にて処理されます。

```bash:dnat_snat_qrouter(node2)
ubuntu@node2:~/devstack$ sudo ip netns exec qrouter-$router1_id iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N neutron-l3-agent-OUTPUT
-N neutron-l3-agent-POSTROUTING
-N neutron-l3-agent-PREROUTING
-N neutron-l3-agent-float-snat
-N neutron-l3-agent-snat
-N neutron-postrouting-bottom
-A PREROUTING -j neutron-l3-agent-PREROUTING
-A OUTPUT -j neutron-l3-agent-OUTPUT
-A POSTROUTING -j neutron-l3-agent-POSTROUTING
-A POSTROUTING -j neutron-postrouting-bottom
-A neutron-l3-agent-POSTROUTING ! -i rfp-bd7982cb-b ! -o rfp-bd7982cb-b -m conntrack ! --ctstate DNAT -j ACCEPT
-A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9697
-A neutron-l3-agent-PREROUTING -d 172.24.4.12/32 -i rfp-bd7982cb-b -j DNAT --to-destination 10.0.0.8
-A neutron-l3-agent-float-snat -s 10.0.0.8/32 -j SNAT --to-source 172.24.4.12
-A neutron-l3-agent-snat -j neutron-l3-agent-float-snat
-A neutron-postrouting-bottom -m comment --comment "Perform source NAT on outgoing traffic." -j neutron-l3-agent-snat
```

### fip-$private_id routing table
fip-$private_id namespace の routing table は次のようになります。

```bash
public_id=`openstack network list | grep public\ | awk '{print $2}'`

ubuntu@node2:~/devstack$ sudo ip netns exec fip-$public_id ip rule show
0:      from all lookup local 
32766:  from all lookup main 
32767:  from all lookup default 
2852022899:     from all iif fpr-bd7982cb-b lookup 2852022899

ubuntu@node2:~/devstack$ sudo ip netns exec fip-$public_id ip route show table 2852022899
default via 172.24.4.1 dev fg-07ec92fd-de 
```

上の例では、fpr-bd7982cb-b から入力されたパケットは table 2852022899 を lookup するため、default router は 172.24.4.1 となります。

以上より、outbound packet は default route 172.24.4.1 に送信されることが分かります。


# まとめ

今回の動作検証にて分かったことを次にまとめます。

- upstream neutron (ML2 + ovs + DVR) では、次のことが実現できます
  - VXLAN overlay を用いたテナントネットワークの構成
  - L2 Population による、Unknown Unicast パケットの flooding 抑制
  - ARP Responder による、ARP パケットの flooding 抑制
  - Controller を必要としない SDN
- 実現できないこと
  - DHCP request パケットの flooding 抑制
  - DNS query の local resolve による query パケットの抑制
  - ネットワークの見える化(Flow をシンプルな方法で追跡する、過去の Flow を調べる等)
- 課題
  - DVRのパケットフローは複雑なため、通信不具合を切り分ける際にはツールによるアシストが欲しい

# 参考文献
- [OpenStack Neutron Packet Walkthrough (DVR)](https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjl-uD1s_7SAhXGVLwKHSspDOsQtwIIGjAA&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D7IXEtUEZslg&usg=AFQjCNGAHKFKhJL-Wj3oHadOLm9eqlbOUQ&bvm=bv.151325232,d.dGc)
- [OVS ARP Responder – Theory and Practice](https://assafmuller.com/2014/05/21/ovs-arp-responder-theory-and-practice/)