同じサブネットに属するIPアドレスを持つ複数のNICを扱う方法

(How to configure routing tables for multiple NICs assigned IP addresses on the same subnet)

なんでそんなことしたかったかというと

  • Amazon VPC を使っていて、複数の Elastic IP アドレスを 1 インスタンスに関連づけるため、複数の private IP addresses を 1 インスタンスに割り当てたかった。
  • しかし、1 つの ENI (Elastic Network Interface) に紐付けることのできる private IP addresses の数には制限があり、それがインスタンス毎に違う。
  • m1.small (1 ENI あたり 4 個)、を使うまでもない案件であり、t1.micro で 2 ENIs - 2 private addresses の合計 4 つで足りる。
  • しかし...

アホな例

ネットワークのことはなんも知らないので、とりあえず昔の記憶を頼りに次のように設定してみた。ネットワークインターフェイスのエイリアスというやつです。

ちなみに以下のような環境となっています。

ネットワーク: 10.0.0.0/24
ゲートウェイ: 10.0.0.1
ブロードキャストアドレス: 10.0.0.255

ENI #1 primary 10.0.0.128
~ secondary 10.0.0.129
ENI #2 primary 10.0.0.130
~ secondary 10.0.0.131

/etc/network/interfaces:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
address 10.0.0.128
netmask 255.255.255.0
gateway 10.0.0.1

auto eth0:0
iface eth0:0 inet static
address 10.0.0.129
netmask 255.255.255.0

auto eth1
iface eth1 inet static
address 10.0.0.130
netmask 255.255.255.0
gateway 10.0.0.1

auto eth1:0
iface eth1:0 inet static
address 10.0.0.131
netmask 255.255.255.0

これして、

$ service networking restart

をやってみると、まあ応答がなくなるわけです。

仕方ないので、EBSボリュームを同じリージョンの別のインスタンスに attach してサルベージしました。

何が悪いか、どうすればいいか

同じルーティングテーブル上で、同じネットワークやデフォルトのルートは当然の事ながら 1 つしか許可されません。なので、inbound については区別がつきますが、outbound については区別をしてあげる必要があります。

eth0 の IP address を source とする outbound の場合は、eth0、 eth1 の IP address を source とする outbound の場合は、eth1 を使うように設定します。

結局どうしたか

いろいろ検索してみても、ぴったりの回答が得られなかったのですが、いろいろな情報をもとに試行錯誤した結果です。基本的には、ip コマンドフル活用でpolicy-based routingします。

まず eth1 の IP アドレスですが、エイリアスを使うのはやめて ip コマンドでやってしまいましょう。

# ip addr add 10.0.0.130/24 broadcast 10.0.0.255 dev eth1
# ip addr add 10.0.0.131/24 broadcast 10.0.0.255 dev eth1

eth0 の場合はデフォルトで設定されるので、eth1 の場合のみ別のルーティングテーブルを作り対処します。

まずはルーティングテーブルに手頃な名前をつけるために /etc/iproute2/rt_tables を編集します。

/etc/iproute2/rt_tables:

#
# reserved values
#
255     local
254     main
253     default
0         unspec
#
# local
#
1         sibling_eth1

ルーティングテーブルにはそれぞれ 1〜255 の番号がついていて、253〜255 はシステムで予約されています。1〜252 のうちで使っていない番号を選んで、sibling_eth1 という名称にします。

次に、 sibling_eth1 をクリアします。

# ip route flush table sibling_eth1

sibling_eth1 に、ルートを足します

# ip route add table sibling_eth1 10.0.0.0/24 dev eth1 proto kernel scope link
# ip route add table sibling_eth1 default via 10.0.0.1 dev eth1

main のテーブルに eth1 用のルールが足されているといけないので、これを消します

# ip route del 10.0.0.0/24 dev eth1 

最後に、source が 10.0.0.130 か 10.0.0.131 だった場合にこのルーティングテーブルを代わりに使うようにルールを設定します。

# ip rule add from 10.0.0.130 table sibling_eth1
# ip rule add from 10.0.0.131 table sibling_eth1

これで OK なはず。

リブート後も有効になるようにしたければ、
/etc/network/interfaces で eth1 の設定については

auto eth1
iface eth1 inet manual
up /etc/network/configure_sibling_eth1

として、
/etc/network/configure_sibling_eth1 に適当に上記の内容をシェルスクリプトにして書いておきます。

本当は

down /etc/network/deconfigure_sibling_eth1

として、設定をもとに戻すのを書いておくべきなんだけど、そこは適当に。