タイトルは「NIC」としているが、どちらかと言えば「インターフェイス」の意味。要は複数 LAN ポートを同一サブネットに繋ぎたい。
例として、次のように設定する。
- eth0: 192.168.1.11/24 (00-0c-29-11-11-11)
- eth1: 192.168.1.12/24 (00-0c-29-22-22-22)
このとき双方に ping を打つと、実際には eth0 だけが応答する。
>ping 192.168.1.11
>ping 192.168.1.12
>arp -a
インターフェイス: 192.168.1.101 --- 0xc
インターネット アドレス 物理アドレス 種類
192.168.1.11 00-0c-29-11-11-11 動的
192.168.1.12 00-0c-29-11-11-11 動的
これは Linux ネットワークの仕様。RHEL5 だと、次を設定することで両方から ping が返るようになる。
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
>ping 192.168.1.11
>ping 192.168.1.12
>arp -a
インターフェイス: 192.168.1.101 --- 0xc
インターネット アドレス 物理アドレス 種類
192.168.1.11 00-0c-29-11-11-11 動的
192.168.1.12 00-0c-29-22-22-22 動的
しかし、RHEL6 で同じ設定をしても動かない。具体的には、eth1 への ping が返ってこず、ARP テーブルにも登録されない。
>ping 192.168.1.11
>ping 192.168.1.12
>arp -a
インターフェイス: 192.168.1.101 --- 0xc
インターネット アドレス 物理アドレス 種類
192.168.1.11 00-0c-29-11-11-11 動的
この理由がずっと分からなかったが、どうやら RHEL6 から rp_filter の挙動が変わったようだ。結論から言うと、次の設定で RHEL6 でも動くようになる。
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.rp_filter = 2
理由はこの辺りを参照。
- Re: [rhelv6-list] routing/interface question
- ifup.org: reverse path filter (rp_filter) by example
- linux-2.6.git / commitdiff: ip: fix logic of reverse path filter sysctl
RHEL5 では、conf.all.rp_filter と conf.<interface>.rp_filter との論理積(AND)が rp_filter の実効値だったが、RHEL6 では最大値(MAX)が実効値になった。
RHEL5 / RHEL6 のどちらにも、/etc/sysctl.conf に次の設定がある。
# Controls source route verification
net.ipv4.conf.default.rp_filter = 1
よって RHEL5 の場合、rp_filter の値は次のようになる。
[rhel5]# sysctl -a | grep '\.rp_filter' | sort
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 = 0
rp_filter の実効値は、eth0 であれば all.rp_filter AND eth0.rp_filter (=0)となり、eth0 の rp_filter は無効となる。つまり /etc/sysctl.conf にそれらしい設定がありながら、実は 全く効いていなかった ということ。騙された。
RHEL6 の場合は、
[rhel6]# sysctl -a | grep '\.rp_filter' | sort
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
今度は MAX(all.rp_filter, eth0.rp_filter) (=1)となり、rp_filter は有効となる。RHEL5 と全く同じ動作にしたいなら、/etc/sysctl.conf で net.ipv4.conf.default.rp_filter = 0 と設定する必要がある。
今回の目的(同一サブネットに複数インターフェイス)では、rp_filter = 2 にすれば良い。これは loose mode というらしく、いずれかのインターフェイスから到達可能な宛先であればパケットを受信する、というモードのようだ。RFC3704 なんて読む気ないので詳しくは知らない。
そもそも今回の件で rp_filter が影響することが分かり辛いが、極力プライマリインターフェイスで通信しようとする Linux の特性を考えると、何となく理解できなくもない。今回の場合、プライマリ側である eth0 が ARP パケットを処理する際に rp_filter が効くのだろう(と思う)。が、やはり Linux のこの特性は分かりにくい(直感的でない)と思う。
以上のように、Linux で複数インターフェイスを同一サブネットに繋ごうとすると、非常に微妙な領域に足を突っ込むことになる。やるなら 1 個のインターフェイスに仮想 IP アドレスを付ける方法(仮想インターフェイス)をお勧めする。じゃあ私は何故そうしないのかと言うと、現場 SE に「仮想 IP アドレス」とか言っても通じないから。少なくとも自力で設定できるとは思えない。しかし「1 つの LAN ポートに 1 つの IP アドレス」であれば、彼等にも理解してもらえる確率がグッと上がる。:-)
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。