2009年6月23日火曜日

veth に ping

lxc で使っている veth は OpenVZ 由来だそうだ。何かちょっと不思議に思って veth 作って ping 投げてみた。
# ip link add type veth
# ip link ls veth0
11: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 9a:87:c9:92:6b:91 brd ff:ff:ff:ff:ff:ff
# ip link ls veth1
12: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 42:01:93:00:97:d9 brd ff:ff:ff:ff:ff:ff
# ip link set veth0 up
# ip link set veth1 up
# ip addr add 192.168.1.10/24 dev veth0
# ip addr add 192.168.1.11/24 dev veth1
# ping -c 4 192.168.1.10
PING 192.168.1.10 (192.168.1.10) 56(84) bytes of data.
64 bytes from 192.168.1.10: icmp_seq=1 ttl=64 time=0.074 ms
64 bytes from 192.168.1.10: icmp_seq=2 ttl=64 time=0.073 ms
64 bytes from 192.168.1.10: icmp_seq=3 ttl=64 time=0.070 ms
64 bytes from 192.168.1.10: icmp_seq=4 ttl=64 time=0.072 ms

--- 192.168.1.10 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.070/0.072/0.074/0.006 ms
# ping -c 4 192.168.1.11
PING 192.168.1.11 (192.168.1.11) 56(84) bytes of data.
64 bytes from 192.168.1.11: icmp_seq=1 ttl=64 time=0.094 ms
64 bytes from 192.168.1.11: icmp_seq=2 ttl=64 time=0.026 ms
64 bytes from 192.168.1.11: icmp_seq=3 ttl=64 time=0.078 ms
64 bytes from 192.168.1.11: icmp_seq=4 ttl=64 time=0.069 ms

--- 192.168.1.11 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.026/0.066/0.094/0.027 ms
まぁ loopback みたいな感じ。で veth0 から veth1 - 192.168.1.11 に ping 投げてみると
# ping -I veth0 192.168.1.11
PING 192.168.1.11 (192.168.1.11) from 192.168.1.10 veth0: 56(84) bytes of data.
From 192.168.1.10 icmp_seq=2 Destination Host Unreachable
From 192.168.1.10 icmp_seq=3 Destination Host Unreachable
From 192.168.1.10 icmp_seq=4 Destination Host Unreachable
音沙汰なしっ。tcpdump で眺めてみると
# tcpdump -ntei veth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth0, link-type EN10MB (Ethernet), capture size 96 bytes
9a:87:c9:92:6b:91 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: arp who-has 192.168.1.11 tell 192.168.1.10
9a:87:c9:92:6b:91 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: arp who-has 192.168.1.11 tell 192.168.1.10
9a:87:c9:92:6b:91 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: arp who-has 192.168.1.11 tell 192.168.1.10
^C
3 packets captured
3 packets received by filter
0 packets dropped by kernel
# tcpdump -ntei veth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth1, link-type EN10MB (Ethernet), capture size 96 bytes
9a:87:c9:92:6b:91 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: arp who-has 192.168.1.11 tell 192.168.1.10
9a:87:c9:92:6b:91 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: arp who-has 192.168.1.11 tell 192.168.1.10
9a:87:c9:92:6b:91 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: arp who-has 192.168.1.11 tell 192.168.1.10
9a:87:c9:92:6b:91 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: arp who-has 192.168.1.11 tell 192.168.1.10
^C
4 packets captured
4 packets received by filter
0 packets dropped by kernel
lxc 追って調べてみるのは面倒だなぁ。と Google 先生に相談したところ lxc の前、ns_exec なるソースを見つけた。既に昔のものになっているらしく
  • ここから持ってきたけど無くなりそうなので
  • ちょっと変更して
    --- ns_exec.c.orig 2009-06-21 23:02:41.000000000 +0900
    +++ ns_exec.c 2009-06-21 23:03:08.000000000 +0900
    @@ -12,7 +12,7 @@
    #include <sys/wait.h>
    #include <sys/mount.h>

    -#include "clone.h"
    +#include <linux/sched.h>

    extern pid_t getpgid(pid_t pid);
    extern pid_t getsid(pid_t pid);
  • ローカルコピー
コンパイルして起動してみる
# cc -o ns_exec ns_exec.c
# echo $$
30530
# ./ns_exec -c -n /bin/bash
about to clone with 40000000
# echo $$
30549
# ip link ls
28: lo: <LOOPBACK> mtu 16436 qdisc noop state DOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
29: gre0: <NOARP> mtu 1476 qdisc noop state DOWN
link/gre 0.0.0.0 brd 0.0.0.0

で PID 30549 に veth1 を渡してあげる
(って言い回しが正しいかわからないけど - 別ターミナルから)
# ip link set veth1 netns 30549
ns_exec したターミナルに戻ってみると
# ip link ls
28: lo: <LOOPBACK> mtu 16436 qdisc noop state DOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
29: gre0: <NOARP> mtu 1476 qdisc noop state DOWN
link/gre 0.0.0.0 brd 0.0.0.0
31: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 1e:cf:fa:8f:a4:4b brd ff:ff:ff:ff:ff:ff
おぉ、わたってる。リンク上げたりアドレス設定すると期待通り
# ip link set veth1 up
# ip addr ls
28: lo: <LOOPBACK> mtu 16436 qdisc noop state DOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
29: gre0: <NOARP> mtu 1476 qdisc noop state DOWN
link/gre 0.0.0.0 brd 0.0.0.0
31: veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 1e:cf:fa:8f:a4:4b brd ff:ff:ff:ff:ff:ff
inet6 fe80::1ccf:faff:fe8f:a44b/64 scope link
valid_lft forever preferred_lft forever
# ip addr add 192.168.1.11/24 dev veth1
# ping -I veth1 192.168.1.10
PING 192.168.1.10 (192.168.1.10) from 192.168.1.11 veth1: 56(84) bytes of data.
64 bytes from 192.168.1.10: icmp_seq=1 ttl=64 time=3.72 ms
64 bytes from 192.168.1.10: icmp_seq=2 ttl=64 time=0.131 ms
64 bytes from 192.168.1.10: icmp_seq=3 ttl=64 time=0.108 ms
64 bytes from 192.168.1.10: icmp_seq=4 ttl=64 time=0.111 ms
^C
--- 192.168.1.10 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.108/1.019/3.727/1.563 ms

なぜ?

例のごとく深く追ってないけど....ARP については
veth_xmit()::driver/net/veth.c
netif_rx()::net/core/dev.c
net_rx_action()::net/core/dev.c - softirq
process_backlog()::net/core/dev.c - dev->poll()
netif_receive_skb()::net/core/dev.c
arp_rcv()::net/ipv4/arp.c
arp_process()::net/ipv4/arp.c
arp_ignore()::net/ipv4/arp.c
inet_confirm_addr()::net/ipv4/devinet.c
confirm_addr_indev()::net/ipv4/devinet.c
この内 inet_confir_addr() から引用
struct net *net;
....
net = dev_net(in_dev->dev);
....
for_each_netdev(net, dev) {
if ((in_dev = __in_dev_get_rcu(dev))) {
addr = confirm_addr_indev(in_dev, dst, local, scope);
struct net は include/net/net_namespace.h で定義されている。上記はネットワークの「名前空間毎に」 net_device / in dev を保持していて、これを加味した上で指定された IP アドレスがローカルか否か判断しているらしい。

ローカルだよ (って表現も上手くないと思うけど) って判断が下り通常は arp_process() にて ARP に応答しない。ns_exec で CLONE_NEWNET してあると、ローカルと判断しない... ``らしい'' ばかりでごめんなさい。

0 件のコメント: