1. はじめに
IBM Cloud: Network Attachments/Virtual Network Interface(VNI)方式とLegacy Network Interface方式の違いにて、VNIについて記載しました。実はVNI方式には、VNIのattach/detachができることやSecondary IPを持てること以外にも嬉しいことがあります。
それは、VNIに対して1つのFloating IPを割り当てることができるため、VNIが複数あれば1つのVSI内で複数Floating IPを持てることです(Legacy Network Interface方式だと、UIでは1つ目のinterfaceにしかFloating IPを紐づけることができなかった。APIを使えば2つ目以降のinterfaceにFloating IPを紐づけることができるのだが、その場合でも結局VSI1つにつき1つのFloating IPしか利用できないことは変わりがなかった)。
このVNIを利用したVSI環境にて、eth0とeth1の両方のFloating IPを利用できることを確認したいというのが今回の記事の趣旨になります。なお、今回はこのサーバー内にHTTPサーバーを既に構築し起動してあります。
2. デフォルトの状態 -> NG
ネットワークの初期構成は以下の通りです。
[root@syasuda-vni-test1 ~]# cat /etc/redhat-release
CentOS Stream release 9
[root@syasuda-vni-test1 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 02:00:05:02:70:58 brd ff:ff:ff:ff:ff:ff
altname enp0s3
altname ens3
inet 10.0.0.11/24 brd 10.0.0.255 scope global dynamic eth0
valid_lft 312sec preferred_lft 312sec
inet6 fe80::5ff:fe02:7058/64 scope link noprefixroute
valid_lft forever preferred_lft forever
4: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 02:00:09:02:70:58 brd ff:ff:ff:ff:ff:ff
altname enp0s4
altname ens4
inet 10.0.0.12/24 brd 10.0.0.255 scope global dynamic noprefixroute eth1
valid_lft 259sec preferred_lft 259sec
inet6 fe80::b772:2c76:ebf2:56fc/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[root@syasuda-vni-test1 ~]# ip r
default via 10.0.0.1 dev eth0
default via 10.0.0.1 dev eth0 proto dhcp src 10.0.0.11 metric 100
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.11
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.11 metric 100
10.0.0.0/24 dev eth1 proto kernel scope link src 10.0.0.12 metric 101
この状態で、eth0側にアクセスすることは当然できます。
syasuda@MacBook-Pro ~ % curl http://xxx.xxx.xxx.159
Hello World
しかし、eth1のFloating IPにはアクセスできません。これは、eth1からサーバーに入ってきたパケットがクライアントに返る際には、上記のrouting tableに従うとeth0を通って返ろうとするからです(非対称ルーティング)。一般的に、主なLinux環境のデフォルト構成では、このようなパケットが入ってきたインターフェースとパケットが出ていくインターフェースが異なるような非対称ルーティングはブロックされています。
syasuda@MacBook-Pro ~ % curl http://xxx.xxx.xxx.35
(応答なし)
[root@syasuda-vni-test1 ~]# tcpdump -i any port 80 -nn
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
03:46:26.810053 eth1 In IP 111.xxx.x.xxx.51561 > 10.0.0.12.80: Flags [SEW], seq 1224915020, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1125728783 ecr 0,sackOK,eol], length 0
03:46:27.809119 eth1 In IP 111.xxx.x.xxx.51561 > 10.0.0.12.80: Flags [S], seq 1224915020, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1125729783 ecr 0,sackOK,eol], length 0
03:46:28.807648 eth1 In IP 111.xxx.x.xxx.51561 > 10.0.0.12.80: Flags [S], seq 1224915020, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1125730783 ecr 0,sackOK,eol], length 0
03:46:29.807612 eth1 In IP 111.xxx.x.xxx.51561 > 10.0.0.12.80: Flags [S], seq 1224915020, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1125731784 ecr 0,sackOK,eol], length 0
03:46:30.809726 eth1 In IP 111.xxx.x.xxx.51561 > 10.0.0.12.80: Flags [S], seq 1224915020, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1125732785 ecr 0,sackOK,eol], length 0
03:46:31.809163 eth1 In IP 111.xxx.x.xxx.51561 > 10.0.0.12.80: Flags [S], seq 1224915020, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1125733785 ecr 0,sackOK,eol], length 0
3. rp_filterを無効にする方法 -> NG
色々ググってみると分かりますが、この非対称ルーティングをブロックしているのはLinux Kernelにおけるrp_filterというパラメーターです。以下のKBも参考になります。
細かいことは省きますが、要はrp_filterを2にすると非対称ルーティングは可能になります。
[root@syasuda-vni-test1 ~]# sysctl -a |grep '\.rp_filter'
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 1
[root@syasuda-vni-test1 ~]# sysctl -w net.ipv4.conf.all.rp_filter=2
[root@syasuda-vni-test1 ~]# sysctl -w net.ipv4.conf.default.rp_filter=2
しかし、eth1のFloating IPには依然としてアクセスできません。tcpdumpを見ると、先ほどの結果と異なり、eth1から受け取ったパケットをeth0から返そうとしています。よって、rp_filter=2は正しく機能しています。これは、floating IPが紐づいているインターフェースとは異なるインターフェースからパケットが応答しているため、VPC SDN内部のprotocol state filteringが働いてブロックされてしまっていると思われます。(※なお、IP Spoofingをenableにしても結果は同じです。)
syasuda@MacBook-Pro ~ % curl http://xxx.xxx.xxx.35
[root@syasuda-vni-test1 ~]# tcpdump -i any port 80 -nn
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
04:05:51.636017 eth1 In IP 111.xxx.x.xxx.51781 > 10.0.0.12.80: Flags [SEW], seq 1422579047, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1492728522 ecr 0,sackOK,eol], length 0
04:05:51.636069 eth0 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.51781: Flags [S.E], seq 2068287172, ack 1422579048, win 31856, options [mss 1460,sackOK,TS val 3348392710 ecr 1492728522,nop,wscale 7], length 0
04:05:52.636887 eth1 In IP 111.xxx.x.xxx.51781 > 10.0.0.12.80: Flags [S], seq 1422579047, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1492729522 ecr 0,sackOK,eol], length 0
04:05:52.636933 eth0 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.51781: Flags [S.E], seq 2068287172, ack 1422579048, win 31856, options [mss 1460,sackOK,TS val 3348393711 ecr 1492728522,nop,wscale 7], length 0
04:05:53.636915 eth1 In IP 111.xxx.x.xxx.51781 > 10.0.0.12.80: Flags [S], seq 1422579047, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1492730523 ecr 0,sackOK,eol], length 0
04:05:53.636960 eth0 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.51781: Flags [S.E], seq 2068287172, ack 1422579048, win 31856, options [mss 1460,sackOK,TS val 3348394711 ecr 1492728522,nop,wscale 7], length 0
04:05:54.637820 eth1 In IP 111.xxx.x.xxx.51781 > 10.0.0.12.80: Flags [S], seq 1422579047, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1492731524 ecr 0,sackOK,eol], length 0
04:05:54.637866 eth0 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.51781: Flags [S.E], seq 2068287172, ack 1422579048, win 31856, options [mss 1460,sackOK,TS val 3348395712 ecr 1492728522,nop,wscale 7], length 0
04:05:55.641045 eth1 In IP 111.xxx.x.xxx.51781 > 10.0.0.12.80: Flags [S], seq 1422579047, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1492732525 ecr 0,sackOK,eol], length 0
04:05:55.641070 eth0 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.51781: Flags [S.E], seq 2068287172, ack 1422579048, win 31856, options [mss 1460,sackOK,TS val 3348396715 ecr 1492728522,nop,wscale 7], length 0
04:05:56.641908 eth1 In IP 111.xxx.x.xxx.51781 > 10.0.0.12.80: Flags [S], seq 1422579047, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1492733527 ecr 0,sackOK,eol], length 0
04:05:56.641992 eth0 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.51781: Flags [S.E], seq 2068287172, ack 1422579048, win 31856, options [mss 1460,sackOK,TS val 3348397716 ecr 1492728522,nop,wscale 7], length 0
04:05:57.657615 eth0 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.51781: Flags [S.E], seq 2068287172, ack 1422579048, win 31856, options [mss 1460,sackOK,TS val 3348398731 ecr 1492728522,nop,wscale 7], length 0
04:05:58.641693 eth1 In IP 111.xxx.x.xxx.51781 > 10.0.0.12.80: Flags [S], seq 1422579047, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1492735528 ecr 0,sackOK,eol], length 0
04:05:58.641738 eth0 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.51781: Flags [S.E], seq 2068287172, ack 1422579048, win 31856, options [mss 1460,sackOK,TS val 3348399716 ecr 1492728522,nop,wscale 7], length 0
04:06:00.665622 eth0 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.51781: Flags [S.E], seq 2068287172, ack 1422579048, win 31856, options [mss 1460,sackOK,TS val 3348401739 ecr 1492728522,nop,wscale 7], length 0
04:06:02.644209 eth1 In IP 111.xxx.x.xxx.51781 > 10.0.0.12.80: Flags [S], seq 1422579047, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1492739529 ecr 0,sackOK,eol], length 0
04:06:02.644233 eth0 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.51781: Flags [S.E], seq 2068287172, ack 1422579048, win 31856, options [mss 1460,sackOK,TS val 3348403718 ecr 1492728522,nop,wscale 7], length 0
4. Policy Based Routingの設定 -> 成功
上記の結果より、eth1から受け取ったパケットはeth1から返すように構成する必要がありそうです。
(先ほどのカーネルパラメーターの変更を初期化するように、事前にOSを再起動しておきます。またIP_Spoofingは再度無効にしておきます。)。
# 10.0.0.12からのパケットは、table 1001を利用する
[root@syasuda-vni-test1 ~]# ip rule add from 10.0.0.12 table 1001 priority 1001
[root@syasuda-vni-test1 ~]# ip rule show
0: from all lookup local
1001: from 10.0.0.12 lookup 1001
32766: from all lookup main
32767: from all lookup default
# table 1001に経路情報を追加する。
[root@syasuda-vni-test1 ~]# ip r show table 1001
Error: ipv4: FIB table does not exist.
Dump terminated
[root@syasuda-vni-test1 ~]# ip r add 10.0.0.0/24 dev eth1 proto kernel scope link src 10.0.0.12 table 1001
[root@syasuda-vni-test1 ~]# ip r add default via 10.0.0.1 table 1001
[root@syasuda-vni-test1 ~]# ip r show table 1001
default via 10.0.0.1 dev eth1
10.0.0.0/24 dev eth1 proto kernel scope link src 10.0.0.12
syasuda@MacBook-Pro ~ % curl http://xxx.xxx.xxx.159
Hello World
[root@syasuda-vni-test1 ~]# tcpdump -i any port 80 -nn
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
04:57:10.861120 eth0 In IP 111.xxx.x.xxx.52075 > 10.0.0.11.80: Flags [SEW], seq 3368161315, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 3254033399 ecr 0,sackOK,eol], length 0
04:57:10.861180 eth0 Out IP 10.0.0.11.80 > 111.xxx.x.xxx.52075: Flags [S.E], seq 1396456261, ack 3368161316, win 31856, options [mss 1460,sackOK,TS val 2690683001 ecr 3254033399,nop,wscale 7], length 0
04:57:10.885469 eth0 In IP 111.xxx.x.xxx.52075 > 10.0.0.11.80: Flags [.], ack 1, win 2058, options [nop,nop,TS val 3254033427 ecr 2690683001], length 0
04:57:10.885471 eth0 In IP 111.xxx.x.xxx.52075 > 10.0.0.11.80: Flags [P.], seq 1:79, ack 1, win 2058, options [nop,nop,TS val 3254033427 ecr 2690683001], length 78: HTTP: GET / HTTP/1.1
04:57:10.885509 eth0 Out IP 10.0.0.11.80 > 111.xxx.x.xxx.52075: Flags [.], ack 79, win 249, options [nop,nop,TS val 2690683025 ecr 3254033427], length 0
04:57:10.885836 eth0 Out IP 10.0.0.11.80 > 111.xxx.x.xxx.52075: Flags [P.], seq 1:261, ack 79, win 249, options [nop,nop,TS val 2690683026 ecr 3254033427], length 260: HTTP: HTTP/1.1 200 OK
04:57:10.909283 eth0 In IP 111.xxx.x.xxx.52075 > 10.0.0.11.80: Flags [.], ack 261, win 2054, options [nop,nop,TS val 3254033451 ecr 2690683026], length 0
04:57:10.910621 eth0 In IP 111.xxx.x.xxx.52075 > 10.0.0.11.80: Flags [F.], seq 79, ack 261, win 2054, options [nop,nop,TS val 3254033451 ecr 2690683026], length 0
04:57:10.910774 eth0 Out IP 10.0.0.11.80 > 111.xxx.x.xxx.52075: Flags [F.], seq 261, ack 80, win 249, options [nop,nop,TS val 2690683050 ecr 3254033451], length 0
04:57:10.934487 eth0 In IP 111.xxx.x.xxx.52075 > 10.0.0.11.80: Flags [.], ack 262, win 2054, options [nop,nop,TS val 3254033476 ecr 2690683050], length 0
syasuda@MacBook-Pro ~ % curl http://xxx.xxx.xxx.35
Hello World
[root@syasuda-vni-test1 ~]# tcpdump -i any port 80 -nn
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
04:57:57.053426 eth1 In IP 111.xxx.x.xxx.52085 > 10.0.0.12.80: Flags [SEW], seq 2146802607, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 4098607537 ecr 0,sackOK,eol], length 0
04:57:57.053488 eth1 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.52085: Flags [S.E], seq 646286585, ack 2146802608, win 31856, options [mss 1460,sackOK,TS val 3402270254 ecr 4098607537,nop,wscale 7], length 0
04:57:57.076807 eth1 In IP 111.xxx.x.xxx.52085 > 10.0.0.12.80: Flags [.], ack 1, win 2058, options [nop,nop,TS val 4098607561 ecr 3402270254], length 0
04:57:57.076809 eth1 In IP 111.xxx.x.xxx.52085 > 10.0.0.12.80: Flags [P.], seq 1:78, ack 1, win 2058, options [nop,nop,TS val 4098607561 ecr 3402270254], length 77: HTTP: GET / HTTP/1.1
04:57:57.076851 eth1 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.52085: Flags [.], ack 78, win 249, options [nop,nop,TS val 3402270278 ecr 4098607561], length 0
04:57:57.077377 eth1 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.52085: Flags [P.], seq 1:261, ack 78, win 249, options [nop,nop,TS val 3402270278 ecr 4098607561], length 260: HTTP: HTTP/1.1 200 OK
04:57:57.099966 eth1 In IP 111.xxx.x.xxx.52085 > 10.0.0.12.80: Flags [.], ack 261, win 2054, options [nop,nop,TS val 4098607585 ecr 3402270278], length 0
04:57:57.102700 eth1 In IP 111.xxx.x.xxx.52085 > 10.0.0.12.80: Flags [F.], seq 78, ack 261, win 2054, options [nop,nop,TS val 4098607585 ecr 3402270278], length 0
04:57:57.102853 eth1 Out IP 10.0.0.12.80 > 111.xxx.x.xxx.52085: Flags [F.], seq 261, ack 79, win 249, options [nop,nop,TS val 3402270304 ecr 4098607585], length 0
04:57:57.126726 eth1 In IP 111.xxx.x.xxx.52085 > 10.0.0.12.80: Flags [.], ack 262, win 2054, options [nop,nop,TS val 4098607611 ecr 3402270304], length 0
5. (おまけ)IPアドレスベースのApacheの VirtualHost 設定
Apacheにて、以下のようにIPアドレスベースのVirtualHost設定をしておく
[root@syasuda-vni-test1 ~]# cat /etc/httpd/conf/httpd.conf
(途中省略)
<VirtualHost 10.0.0.11:80>
ServerName www.example.com
ServerAdmin admin@example.com
DocumentRoot /var/www/html_11
</VirtualHost>
<VirtualHost 10.0.0.12:80>
ServerName www.example.com
ServerAdmin admin@example.com
DocumentRoot /var/www/html_12
</VirtualHost>
(途中省略)
[root@syasuda-vni-test1 ~]# cat /var/www/html_11/index.html
This is 11
[root@syasuda-vni-test1 ~]# cat /var/www/html_12/index.html
This is 12
すると、(同一VSIにも関わらず)アクセスするIPアドレスによって異なる結果を得ることができる。
syasuda@MacBook-Pro ~ % curl http://xxx.xxx.xxx.159
This is 11
syasuda@MacBook-Pro ~ % curl http://xxx.xxx.xxx.35
This is 12