🔎

vethの対向インターフェイス名を知る

2022/06/29に公開

はじめに

このあたりの実験をしているときに気になったことがあります。
https://zenn.dev/takai404/articles/70c554c4a0de45
https://zenn.dev/takai404/articles/eec415ccbb13d4

veth pairをこんな感じで作ると、

ip link add access1_e0 type veth peer name access2_e0
ip link add access1_e2 type veth peer name eth0 netns pc1

ip linkコマンドの結果はこうなります。

# ip link show access1_e0
24: access1_e0@access2_e0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqu
eue master access1 state UP mode DEFAULT group default qlen 1000
    link/ether 52:65:55:a4:d6:45 brd ff:ff:ff:ff:ff:ff
# ip link show access1_e2
27: access1_e2@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue mas
ter access1 state UP mode DEFAULT group default qlen 1000
    link/ether 32:c8:70:0d:8a:30 brd ff:ff:ff:ff:ff:ff link-netns pc1

veth peerを同じ名前空間に作った場合は「access1_e0@access2_e0」というように表示され、「access1_e0」の対向は「access2_e0」なんだな、というのが直感的に理解できます。

ただ、peerを別の名前空間に飛ばした場合の「if4」って何?と疑問に思いました。

結論

以下のワンライナーを打つと

(ip -o link show type veth; ip -a netns exec ip -o link show type veth) | awk ' BEGIN { ns="-"; } /^netns:/ { ns=$2; } /link-netns/ { ifindex=$1; sub(/:$/, "", ifindex); ifname=$2; sub(/@.*/, "", ifname); peer_ifname=$2; sub(/.*@/, "", peer_ifname); sub(/:$/, "", peer_ifname); if(match($0, /link-netns [^ ]*/)){ peer_ns=substr($0, RSTART, RLENGTH); sub(/[^ ]* /, "", peer_ns); } else if(match($0, /link-netnsid /)){ peer_ns="-"; } ifnamelist[ns, ifindex]=ifname; sub(/if/, "", peer_ifname); peerlist[ns, ifindex]=peer_ns SUBSEP peer_ifname; } END { for (i in ifnamelist) { ns=i; sub(SUBSEP".*", "", ns); ifindex=i; sub(".*"SUBSEP, "", ifindex); peer_ns=peerlist[i]; sub(SUBSEP".*", "", peer_ns); OFS="\t"; print ns, ifnamelist[i], peer_ns, ifnamelist[peerlist[i]]; } } ' | sort

こんな感じで名前空間をまたがるveth pairの名前空間、デバイス名、対向名前空間、対向デバイス名が一覧化できます。

-       access1_e2      pc1     eth0
-       access2_e2      pc2     eth0
-       access3_e2      pc3     eth0
-       access4_e2      pc4     eth0
pc1     eth0    -       access1_e2
pc2     eth0    -       access2_e2
pc3     eth0    -       access3_e2
pc4     eth0    -       access4_e2

すぐに分かること

こんな感じで同名の「if4」というのが複数回出てきます。そのためif4だけでは対向を一意に特定できないです。

# ip link show access1_e2
27: access1_e2@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue mas
ter access1 state UP mode DEFAULT group default qlen 1000
    link/ether 32:c8:70:0d:8a:30 brd ff:ff:ff:ff:ff:ff link-netns pc1
# ip link show access2_e2
28: access2_e2@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue mas
ter access2 state UP mode DEFAULT group default qlen 1000
    link/ether 3e:cc:33:fc:df:10 brd ff:ff:ff:ff:ff:ff link-netns pc2

上の結果には「link-netns pc1」とかが入っていて、対向が「pc1」名前空間にあるのでは?と思わせます。

別の名前空間でのip link

pc1名前空間でip linkコマンドを打ちます。

# ip -n pc1 link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
 group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default
 qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default
qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
4: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
mode DEFAULT group default qlen 1000
    link/ether 06:3b:88:6b:b8:35 brd ff:ff:ff:ff:ff:ff link-netnsid 0

今度は「eth0@if27」とか「link-netnsid 0」とか出てきます。if27って何?とかlink-netnsとlink-netnsidの違いは?とか疑問が出てきます。

「if4」は「別の名前空間のinterfaceの4番目」でしょうね。
実際、pc1名前空間の4番目のインターフェイスがeth0です。

デフォルト名前空間の27番目のインターフェイスがaccess1_e2なので「if27」も「別の名前空間のinterfaceの27番目」であっているでしょう。

マニュアル

man ip-netnsで名前空間のマニュアルが読めます。

       ip netns set NETNSNAME NETNSID

       NETNSID := auto | POSITIVE-INT
        (中略)       
       ip netns set NAME NETNSID - assign an id to a peer network namespace

              This command assigns a id to a peer network namespace. This id is
              valid only in the current network namespace.  If the keyword "auto" is
              specified an available nsid will be chosen.  This id will be used by
              the kernel in some netlink messages. If no id is assigned when the
              kernel needs it, it will be automatically assigned by the kernel.
              Once it is assigned, it's not possible to change it.

(意訳)ネットワーク名前空間にIDを割り当てます。IDは現在の名前空間でのみ有効です。ID
が割り当てられていない場合は必要に応じてカーネルが割り当てます。割り当てられた後は変更不可です。

「現在の名前空間でのみ有効」というのはちょっとよく分からない。

調査

こんな構成を作ってidの変化を見てみました。いったん作った後、Bを消してB2を作り直すことにします。Graphviz

# ip netns
# ip netns list-id
# ip -a netns exec ip netns
# ip -a netns exec ip netns list-id
# ip link show type veth
# ip -a netns exec ip link show type veth

ip netnsはネットワーク名前空間の一覧
ip netns list-idはそのネットワーク名前空間の中で見えているネットワーク名前空間IDの一覧
ip -a netns exec~は全ネットワーク名前空間でコマンド「~」を実行
ip link show type vethはvethの一覧

最初はなにも作っていないので全て結果は空です。

# ip netns add A
# ip netns
A
# ip netns list-id
# ip -a netns exec ip netns

netns: A
A
# ip -a netns exec ip netns list-id

netns: A

ネットワーク名前空間Aを作成

ip netnsはAしか出力しない。これは想定通り。
ip netns list-idしてもID(正の整数)が何も表示されない。これは自分で設定もしていないし、カーネルが(この時点では)必要としていないから?

# ip netns add B
# ip netns
B
A
# ip netns list-id
# ip -a netns exec ip netns

netns: B
B
A

netns: A
B
A
# ip -a netns exec ip netns list-id

netns: B

netns: A
# ip netns add C
# ip netns
C
B
A
# ip netns list-id
# ip -a netns exec ip netns

netns: C
C
B
A

netns: B
C
B
A

netns: A
C
B
A
# ip -a netns exec ip netns list-id

netns: C

netns: B

netns: A

ネットワーク名前空間B、Cを作成。Aを作成したときと同じなので想定通り。
vethはまだ一本も作っていない。

# ip link add test1 type veth peer name test2 netns A
# ip link show type veth
100: test1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:bc:21:3f:86:c5 brd ff:ff:ff:ff:ff:ff link-netns A
# ip -a netns exec ip link show type veth

netns: C

netns: B

netns: A
2: test2@if100: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 32:13:a3:57:5d:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0

veth pairをデフォルト名前空間とAにまたがって1本作成。

  • デフォルト名前空間ではvethが見えて、対向がlink-netns A
    • このAっていうのはIDあるのかな? あるとしたら何番?
  • A名前空間ではvethが見えて、対向がlink-netnsid 0
    • これは想定通り。自動的に割り当てられるIDはなんなんだろうという疑問があったんですが、0が割り振られるんですね…
    • 0? ゼロ? ゼロは正の整数(POSITIVE-INT)じゃないのでは? まぁLinux作っているのは数学者でも学校教育者でもないので細かいことは気にしたら負けかもしれません。
# ip netns
C
B
A (id: 0)
# ip netns list-id
nsid 0 (iproute2 netns name: A)
# ip -a netns exec ip netns

netns: C
C
B
A

netns: B
C
B
A

netns: A
C
B
A
# ip -a netns exec ip netns list-id

netns: C

netns: B

netns: A
nsid 0

さっきの「このAっていうのはIDあるのかな?」という疑問の答えがありました。

  • デフォルト名前空間のip netns
    • A, B, Cすべて出力され、Aの後に括弧書きで(id: 0)と補足される。
    • さっきの疑問の答えは0でした。
    • A名前空間から見たデフォルト名前空間のIDも0なので、マニュアルに書いてあった「現在の名前空間でのみ有効」というのは、名前空間が違うとIDが被ることがある、ということですね。
  • デフォルト名前空間のip netns list-id
    • nsid 0だけが出力
    • こっちはID一覧出力のコマンドなので括弧書きで(iproute2 netns name: A)と補足される。
    • たぶん名前空間B, Cは使ってないから(デフォルト名前空間では)番号割り当てされていないんでしょう。
  • A名前空間のip netns
    • A, B, Cすべて出力されるが括弧書きの補足はなし。
    • そもそもip netnsコマンド自体、デフォルト名前空間は出力されないですね。
    • A名前空間から見たA名前空間は自分自身だからID付ける必要なし?(ちょっと自信なし)
    • A名前空間から見たB, C名前空間はまだ使っていないからID付ける必要なし(たぶん)
  • A名前空間のip netns list-id
    • nsid 0って出力されました。
    • これはA名前空間からみたデフォルト名前空間だと思う
    • ip linkの「2: test2 (中略) link-netnsid 0」というのとも一致しますね。
# ip link add test3 netns A type veth peer name test4 netns B
# ip link show type veth
100: test1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:bc:21:3f:86:c5 brd ff:ff:ff:ff:ff:ff link-netns A
# ip -a netns exec ip link show type veth

netns: C

netns: B
2: test4@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 66:83:fa:a2:34:87 brd ff:ff:ff:ff:ff:ff link-netns A

netns: A
2: test2@if100: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 32:13:a3:57:5d:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0
3: test3@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9a:6c:12:2d:0e:33 brd ff:ff:ff:ff:ff:ff link-netns B
# ip netns
C
B
A (id: 0)
# ip netns list-id
nsid 0 (iproute2 netns name: A)
# ip -a netns exec ip netns

netns: C
C
B
A

netns: B
C
B
A (id: 0)

netns: A
C
B (id: 1)
A
# ip -a netns exec ip netns list-id

netns: C

netns: B
nsid 0 (iproute2 netns name: A)

netns: A
nsid 0
nsid 1 (iproute2 netns name: B)

AとBの間にvethを作りました。

  • B名前空間から見たID一覧
    • nsid 0 (iproute2 netns name: A)
    • Bは初めて他の名前空間とつながったのでAにID 0を割り当てたんですね。
  • A名前空間から見たID一覧
    • nsid 0
    • nsid 1 (iproute2 netns name: B)
    • デフォルト名前空間に使われていた0に加えてBにID 1を割り当てたようです。
# ip link add test5 netns C type veth peer name test6 netns B
# ip link show type veth
100: test1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:bc:21:3f:86:c5 brd ff:ff:ff:ff:ff:ff link-netns A
# ip -a netns exec ip link show type veth

netns: C
2: test5@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 22:75:0a:d0:b3:05 brd ff:ff:ff:ff:ff:ff link-netns B

netns: B
2: test4@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 66:83:fa:a2:34:87 brd ff:ff:ff:ff:ff:ff link-netns A
3: test6@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether e2:ef:cc:49:ed:4a brd ff:ff:ff:ff:ff:ff link-netns C

netns: A
2: test2@if100: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 32:13:a3:57:5d:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0
3: test3@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9a:6c:12:2d:0e:33 brd ff:ff:ff:ff:ff:ff link-netns B
# ip netns
C
B
A (id: 0)
# ip netns list-id
nsid 0 (iproute2 netns name: A)
# ip -a netns exec ip netns

netns: C
C
B (id: 0)
A

netns: B
C (id: 1)
B
A (id: 0)

netns: A
C
B (id: 1)
A
# ip -a netns exec ip netns list-id

netns: C
nsid 0 (iproute2 netns name: B)

netns: B
nsid 0 (iproute2 netns name: A)
nsid 1 (iproute2 netns name: C)

netns: A
nsid 0
nsid 1 (iproute2 netns name: B)
# ip link add test7 type veth peer name test8 netns C
# ip link show type veth
100: test1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:bc:21:3f:86:c5 brd ff:ff:ff:ff:ff:ff link-netns A
101: test7@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9e:8f:e2:17:d2:c9 brd ff:ff:ff:ff:ff:ff link-netns C
# ip -a netns exec ip link show type veth

netns: C
2: test5@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 22:75:0a:d0:b3:05 brd ff:ff:ff:ff:ff:ff link-netns B
3: test8@if101: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether fa:e2:b3:3d:a2:fe brd ff:ff:ff:ff:ff:ff link-netnsid 1

netns: B
2: test4@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 66:83:fa:a2:34:87 brd ff:ff:ff:ff:ff:ff link-netns A
3: test6@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether e2:ef:cc:49:ed:4a brd ff:ff:ff:ff:ff:ff link-netns C

netns: A
2: test2@if100: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 32:13:a3:57:5d:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0
3: test3@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9a:6c:12:2d:0e:33 brd ff:ff:ff:ff:ff:ff link-netns B
# ip netns
C (id: 1)
B
A (id: 0)
# ip netns list-id
nsid 0 (iproute2 netns name: A)
nsid 1 (iproute2 netns name: C)
# ip -a netns exec ip netns

netns: C
C
B (id: 0)
A

netns: B
C (id: 1)
B
A (id: 0)

netns: A
C
B (id: 1)
A
# ip -a netns exec ip netns list-id

netns: C
nsid 0 (iproute2 netns name: B)
nsid 1

netns: B
nsid 0 (iproute2 netns name: A)
nsid 1 (iproute2 netns name: C)

netns: A
nsid 0
nsid 1 (iproute2 netns name: B)

B, Cの間、C, デフォルト名前空間の間にそれぞれvethを作りました。

だいたい法則性が見えてきました。

  • ip netnsコマンドはデフォルト名前空間以外の名前空間を一覧
    • コマンド実行した名前空間内で、IDが割り振られていればそれも括弧書きで補足
  • ip netns list-idコマンドはその名前空間内で割り振られているIDを一覧
    • 使われていない(つながっていない名前空間)は出力されない
    • 括弧書きで名前空間の名前も補足
    • デフォルト名前空間は名前がない[1]のでなにも補足がない
    • IDを自動付与する場合は0から昇順
# ip -n C link del test5
# ip link show type veth
100: test1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:bc:21:3f:86:c5 brd ff:ff:ff:ff:ff:ff link-netns A
101: test7@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9e:8f:e2:17:d2:c9 brd ff:ff:ff:ff:ff:ff link-netns C
# ip -a netns exec ip link show type veth

netns: C
3: test8@if101: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether fa:e2:b3:3d:a2:fe brd ff:ff:ff:ff:ff:ff link-netnsid 1

netns: B
2: test4@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 66:83:fa:a2:34:87 brd ff:ff:ff:ff:ff:ff link-netns A

netns: A
2: test2@if100: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 32:13:a3:57:5d:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0
3: test3@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9a:6c:12:2d:0e:33 brd ff:ff:ff:ff:ff:ff link-netns B
# ip netns
C (id: 1)
B
A (id: 0)
# ip netns list-id
nsid 0 (iproute2 netns name: A)
nsid 1 (iproute2 netns name: C)
# ip -a netns exec ip netns

netns: C
C
B (id: 0)
A

netns: B
C (id: 1)
B
A (id: 0)

netns: A
C
B (id: 1)
A
# ip -a netns exec ip netns list-id

netns: C
nsid 0 (iproute2 netns name: B)
nsid 1

netns: B
nsid 0 (iproute2 netns name: A)
nsid 1 (iproute2 netns name: C)

netns: A
nsid 0
nsid 1 (iproute2 netns name: B)

BとCの間のvethを削除しました。

ip netns, ip netns list-idの結果には変化がないです。
マニュアルには一度割り当てられると変更不可と書いてあったので、名前空間が存在している以上、ID割り振りは解除しないほうが自然ですね。

# ip netns del B
# ip link show type veth
100: test1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:bc:21:3f:86:c5 brd ff:ff:ff:ff:ff:ff link-netns A
101: test7@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9e:8f:e2:17:d2:c9 brd ff:ff:ff:ff:ff:ff link-netns C
# ip -a netns exec ip link show type veth

netns: C
3: test8@if101: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether fa:e2:b3:3d:a2:fe brd ff:ff:ff:ff:ff:ff link-netnsid 1

netns: A
2: test2@if100: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 32:13:a3:57:5d:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0
3: test3@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9a:6c:12:2d:0e:33 brd ff:ff:ff:ff:ff:ff link-netnsid 1
# ip netns
C (id: 1)
A (id: 0)
# ip netns list-id
nsid 0 (iproute2 netns name: A)
nsid 1 (iproute2 netns name: C)
# ip -a netns exec ip netns

netns: C
C
A

netns: A
C
A
# ip -a netns exec ip netns list-id

netns: C
nsid 0
nsid 1

netns: A
nsid 0
nsid 1

B名前空間を消してみました。(Bにつながっているveth(test3-test4)も自動的に消えます)

  • A名前空間から見たID一覧
    • B削除前
      • nsid 0
      • nsid 1 (iproute2 netns name: B)
    • B削除後
      • nsid 0
      • nsid 1
    • IDの割り振りは消えない? Bとの関連付けは消えてるみたい。

Cも同じような出力でした。

# ip netns add B2
# ip link show type veth
100: test1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:bc:21:3f:86:c5 brd ff:ff:ff:ff:ff:ff link-netns A
101: test7@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9e:8f:e2:17:d2:c9 brd ff:ff:ff:ff:ff:ff link-netns C
# ip -a netns exec ip link show type veth

netns: B2

netns: C
3: test8@if101: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether fa:e2:b3:3d:a2:fe brd ff:ff:ff:ff:ff:ff link-netnsid 1

netns: A
2: test2@if100: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 32:13:a3:57:5d:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0
3: test3@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9a:6c:12:2d:0e:33 brd ff:ff:ff:ff:ff:ff link-netnsid 1
# ip netns
B2
C (id: 1)
A (id: 0)
# ip netns list-id
nsid 0 (iproute2 netns name: A)
nsid 1 (iproute2 netns name: C)
# ip -a netns exec ip netns

netns: B2
B2
C
A

netns: C
B2
C
A

netns: A
B2
C
A
# ip -a netns exec ip netns list-id

netns: B2

netns: C
nsid 1

netns: A
nsid 0

B2という名前空間を作ってみました。名前は似ていますがBとの関係性はない完全新規の名前空間です。

  • A名前空間から見たID一覧
    • nsid 0(デフォルト名前空間)が残っているのは当たり前として、nsid 1(元々Bを指していた)が消えましたね。
    • B2を作った影響なのか? 時間が経過して消えたのか? 理由は不明です。

Cも同じような出力でした。

# ip link add test5 netns C type veth peer name test6 netns B2
# ip link show type veth
100: test1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:bc:21:3f:86:c5 brd ff:ff:ff:ff:ff:ff link-netns A
101: test7@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9e:8f:e2:17:d2:c9 brd ff:ff:ff:ff:ff:ff link-netns C
# ip -a netns exec ip link show type veth

netns: B2
2: test6@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 3e:96:0a:81:99:54 brd ff:ff:ff:ff:ff:ff link-netns C

netns: C
3: test8@if101: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether fa:e2:b3:3d:a2:fe brd ff:ff:ff:ff:ff:ff link-netnsid 1
4: test5@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 06:dc:8d:15:15:b2 brd ff:ff:ff:ff:ff:ff link-netns B2

netns: A
2: test2@if100: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 32:13:a3:57:5d:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0
3: test3@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9a:6c:12:2d:0e:33 brd ff:ff:ff:ff:ff:ff link-netnsid unknown
# ip netns
B2
C (id: 1)
A (id: 0)
# ip netns list-id
nsid 0 (iproute2 netns name: A)
nsid 1 (iproute2 netns name: C)
# ip -a netns exec ip netns

netns: B2
B2
C (id: 0)
A

netns: C
B2 (id: 0)
C
A

netns: A
B2
C
A
# ip -a netns exec ip netns list-id

netns: B2
nsid 0 (iproute2 netns name: C)

netns: C
nsid 0 (iproute2 netns name: B2)
nsid 1

netns: A
nsid 0

CとB2の間にvethを作りました。test5-test6という名前でさっき消したものと同じ名前ですが、前回のオブジェクトとの関連性はなく新規のvethです。

ip netns list-idコマンドで新規名前空間であるB2でCに0を割り当てたのは想定内。
CではB2に「nsid 0 (iproute2 netns name: B2)」という割り当てをしました。削除したIDは再利用されるんですね。

名前空間IDの法則

  • ip netnsコマンドはデフォルト名前空間以外の名前空間を一覧
    • コマンド実行した名前空間内で、IDが割り振られていればそれも括弧書きで補足
    • デフォルト名前空間は表示されない
  • ip netns list-idコマンドはその名前空間内で割り振られているIDを一覧
    • 使われていない(つながっていない名前空間)は出力されない
    • 括弧書きで名前空間の名前も補足
    • デフォルト名前空間は名前がないので括弧書きの補足がない、というか括弧書きの補足がないものがデフォルト名前空間のID
    • IDを自動付与する場合は0から昇順
    • 名前空間が異なれば同じID番号が存在しうる
    • 削除したIDは新規の名前空間用に再利用される

veth対向インターフェイスの見つけ方

これまで調べたことを踏まえたip linkコマンドの結果を見てvethの対向インターフェイスを見つける方法です。

  • 対向が同じ名前空間の場合
    • 名前が「veth名@対向veth名」という直感的な表示なのですぐわかる
  • 対向が別の名前空間の場合
    • 名前が「veth名@ifNNN」(※NNNは数値)で、出力に「link-netns NS名」が付く
      • 「ip -n NS名 ip link」で対向名前空間のインターフェイス一覧を出し、インターフェイスインデックスがNNNであるものが対向インターフェイス
    • 名前が「veth名@ifNNN」(※NNNは数値)で、出力に「link-netnsid 数値」が付く
      • 数値が何番であろうと関係ない。
      • 「ip link」でデフォルト名前空間のインターフェイス一覧を出し、インターフェイスインデックスがNNNであるものが対向インターフェイス

冒頭で例示したインターフェイスも上記法則に従っています。

# ip link show access1_e2
27: access1_e2@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue mas
ter access1 state UP mode DEFAULT group default qlen 1000
    link/ether 32:c8:70:0d:8a:30 brd ff:ff:ff:ff:ff:ff link-netns pc1
# ip -n pc1 link
  (中略)
4: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
mode DEFAULT group default qlen 1000
    link/ether 06:3b:88:6b:b8:35 brd ff:ff:ff:ff:ff:ff link-netnsid 0

名前空間またがりのveth一覧

以下が一覧を出力するスクリプトです。このスクリプトから改行とかスペースとかを消しまくったワンライナーが「結論」のところに書いたものです。

get_veth_pairs.sh
#!/bin/sh -ue

(ip -o link show type veth; ip -a netns exec ip -o link show type veth) | awk '
        BEGIN {
                ns="-";
        }
        /^netns:/ {
                ns=$2;
        }
        /link-netns/ {
                ifindex=$1;
                sub(/:$/, "", ifindex);

                ifname=$2;
                sub(/@.*/, "", ifname);

                peer_ifname=$2;
                sub(/.*@/, "", peer_ifname);
                sub(/:$/, "", peer_ifname);

                if(match($0, /link-netns [^ ]*/)){
                        peer_ns=substr($0, RSTART, RLENGTH);
                        sub(/[^ ]* /, "", peer_ns);

                } else if(match($0, /link-netnsid /)){
                        peer_ns="-";
                }
                ifnamelist[ns, ifindex]=ifname;
                sub(/if/, "", peer_ifname);
                peerlist[ns, ifindex]=peer_ns SUBSEP peer_ifname;
        }
        END {
                for (i in ifnamelist) {
                        ns=i;
                        sub(SUBSEP".*", "", ns);
                        ifindex=i;
                        sub(".*"SUBSEP, "", ifindex);
                        peer_ns=peerlist[i];
                        sub(SUBSEP".*", "", peer_ns);
                        OFS="\t";
                        print ns, ifnamelist[i], peer_ns, ifnamelist[peerlist[i]];
                }
        }
' | sort

実行結果

# ./get_veth_pairs.sh
-       access1_e2      pc1     eth0
-       access2_e2      pc2     eth0
-       access3_e2      pc3     eth0
-       access4_e2      pc4     eth0
pc1     eth0    -       access1_e2
pc2     eth0    -       access2_e2
pc3     eth0    -       access3_e2
pc4     eth0    -       access4_e2

注意点としては出力で「-」としているのはデフォルト名前空間を意味しています。これはこのスクリプトだけの表現方法で、別にLinuxのなにがしかのコマンドでデフォルト名前空間が「-」と表現されているわけではないです。
デフォルト名前空間の名前は「default」とか「DEFAULT」、「0」、「1」、「-」[2]等ではなくて『名前がない』というのがより適切な言い方です。そういう意味では空文字列のほうがいいかもしれないのですが、上記のスクリプトの結果をパイプで別のコマンドに渡すこととかを考えると何か文字を出した方が便利かなと思ってそうしているだけです。[3]

脚注
  1. 便宜上「デフォルト名前空間」と呼んできましたが、「default」という名前がついているわけではないです。無名名前空間の方が適切かもしれないです。 ↩︎

  2. 実際、これらの名前でネットワーク名前空間を作成可能です。 ↩︎

  3. 空文字列にしてカンマ区切りにするとかでもいいのですがそうすると今度はぱっと見た感じ見づらいんですよね。 ↩︎

Discussion