ip a show
を実行すると、インターフェースを表示できることを知っています。ホストが表示できるインターフェイスのみが表示されますが、コンテナによって構成された仮想インターフェイスはこのリストに表示されません。 ip netns
も使用してみましたが、どちらも表示されません。 iproute2
の別のバージョンを再コンパイルする必要がありますか? /proc/net/fb_trie
では、転送データベースの用途として、のローカル/ブロードキャストアドレスを確認できます。
この情報、またはコンテナを含むすべてのインターフェイスを一覧表示するコマンドはどこにありますか?
これをテストするには、コンテナを起動します。私の場合、それはスナップ上のlxcコンテナーです。 ip a
またはip l
を実行します。ホストマシンのビューが表示されますが、コンテナ構成のインターフェースは表示されません。コンテナはcgroupedプロセスであるため、procfs
をgrepしていますが、fib_trie
とarpエントリ以外は取得しません。 netns名前空間の難読化が原因である可能性があると思いましたが、ip netns
も何も表示しません。
Lxdはパケットの転送を追跡する接続が必要なため、conntrack -L
を使用して、確立されたすべての着信接続と発信接続を表示できますが、システムで構成されているすべてのIPアドレスをリストします。 netstat
またはlsof
を使用して見分けることができます。
ある時点で、インターフェースは1つに属します ネットワーク名前空間 そして1つだけです。破棄されたネットワーク名前空間の物理インターフェイスを継承することを除いて、初期(初期)ネットワーク名前空間には他のネットワーク名前空間に対する特別な機能はありません。それらのインターフェイスを直接見ることはできません。 initのpidおよびmount名前空間にいる限り、/proc
から入手できるさまざまな情報を使用してネットワーク名前空間を検索し、最後にそれらのネットワーク名前空間を入力してインターフェイスを表示できます。
シェルで例を示します。
ネットワーク名前空間を列挙します
このためには、それらの名前空間がどのように存在するかを知る必要があります。リソースがそれらを維持している限り。ここでのリソースは、プロセス(実際にはプロセスのスレッド)、マウントポイント、またはオープンファイル記述子(fd)です。これらのリソースはすべて/proc/
で参照され、すべての名前空間を列挙するnsfs
疑似ファイルシステムの抽象疑似ファイルを指します。このファイルの唯一の意味のある情報は、ネットワークの名前空間を表すiノードですが、iノードを単独で操作することはできません。ファイルでなければなりません。そのため、後でiノード値(stat -c %i /proc/some/file
で指定)だけを保持することはできません。重複およびファイル名を削除できるようにiノードを保持します。 nsenter
後で使用できる参照を引き続き保持します。
プロセス(実際にはスレッド)
最も一般的なケース:通常のコンテナの場合。各スレッドのネットワーク名前空間は、参照/proc/pid/ns/net
を介して知ることができます。stat
だけで、すべての一意の名前空間を列挙します。 2>/dev/null
は、stat
が一時的なプロセスを見つけることができなくなったときに非表示にします。
find /proc/ -mindepth 1 -maxdepth 1 -name '[1-9]*' | while read -r procpid; do
stat -L -c '%20i %n' $procpid/ns/net
done 2>/dev/null
これは、名前空間を処理する特殊な lsns
コマンドを使用すると、より高速に実行できますが、プロセスのみを処理するように見えます(後で説明するようにマウントポイントやオープンfdは処理しません)。
lsns -n -u -t net -o NS,PATH
(後でlsns -n -u -t net -o NS,PATH | while read inode path; do printf '%20u %s\n' $inode "$path"; done
として再フォーマットする必要があります)
マウントポイント
これらは主にip netns add
コマンドによって使用されます。これは、それらをマウントすることによって永続的なネットワーク名前空間を作成します。これにより、プロセスやfdリソースがそれらを維持しない場合に表示されなくなり、ルーター、ファイアウォール、ブリッジなどを実行できるようになります。リンクされたプロセスのないネットワーク名前空間。
マウントされた名前空間(mountおよびおそらくpid名前空間の処理はおそらくもっと複雑ですが、とにかくネットワーク名前空間にのみ関心があります)は、ファイルシステムタイプがnsfs
の/proc/mounts
の他のマウントポイントと同じように表示されます。 Shellでは、ネットワーク名前空間を他のタイプの名前空間と簡単に区別する方法はありませんが、同じファイルシステム(ここではnsfs
)の2つの疑似ファイルは同じiノードを共有しないため、すべてを選択し、非ネットワーク名前空間参照をネットワーク名前空間として使用しようとするときに、インターフェイス手順の後半でエラーを無視します。申し訳ありませんが、スペースを含む特殊文字が含まれているマウントポイントは、/proc/mounts
の出力で既にエスケープされているため(他の言語では簡単です)、正しくマウントポイントを処理できません。 nullで終了する行を使用します。
awk '$3 == "nsfs" { print $2 }' /proc/mounts | while read -r mount; do
stat -c '%20i %n' "$mount"
done
ファイル記述子を開く
これらは、一時的に名前空間の作成時を除いて、マウントポイントよりもさらにまれである可能性がありますが、コンテナ化テクノロジなど、複数の名前空間を処理する特殊なアプリケーションによって保持および使用される場合があります。
すべての/proc/pid/fd/
で利用可能なすべてのfdを検索し、statを使用してnsfs
名前空間を指していることを確認し、それが本当にネットワーク名前空間であるかどうかを今のところ気にしないよりも良い方法を考案することはできませんでした。私はもっと最適化されたループがあると確信していますが、これは少なくともどこにでもさまよったり、プロセスの最大制限を想定したりすることはありません。
find /proc/ -mindepth 1 -maxdepth 1 -name '[1-9]*' | while read -r procpid; do
find $procpid/fd -mindepth 1 | while read -r procfd; do
if [ "$(stat -f -c %T $procfd)" = nsfs ]; then
stat -L -c '%20i %n' $procfd
fi
done
done 2>/dev/null
ここで、以前の結果から重複するネットワーク名前空間参照をすべて削除します。たとえば、前の3つの結果(特に、開いているファイル記述子の部分)を組み合わせた出力でこのフィルターを使用すると、次のようになります。
sort -k 1n | uniq -w 20
各名前空間でインターフェースを列挙します
これで、すべての既存のネットワーク名前空間(および無視するいくつかの非ネットワーク名前空間)への参照ができました。参照を使用してそれぞれに入力し、インターフェースを表示します。
前に説明したように、ネットワーク以外の名前空間によって引き起こされたエラーを無視しながら、前のコマンドの出力をこのループへの入力として取得して、インターフェイスを列挙します(OPの質問に従って、アドレスを表示することを選択します)。
while read -r inode reference; do
if nsenter --net="$reference" ip -br address show 2>/dev/null; then
printf 'end of network %d\n\n' $inode
fi
done
Initネットワークのiノードは、参照としてpid1を使用して印刷できます。
echo -n 'INIT NETWORK: ' ; stat -L -c %i /proc/1/ns/net
実行中のLXCコンテナを使用した(実際の編集済みの)出力の例、未接続のブリッジインターフェースを持つip netns add ...
で作成された空の「マウントされた」ネットワーク名前空間、他のdummy0
インターフェースを持つネットワーク名前空間、このネットワーク名前空間ではプロセスではないが、その上にオープンfdを保持します。
unshare --net sh -c 'ip link add dummy0 type dummy; ip address add dev dummy0 10.11.12.13/24; sleep 3' & sleep 1; sleep 999 < /proc/$!/ns/net &
および接続されていないネットワーク名前空間(それらすべてのlo
インターフェース)の「Webコンテンツ」スレッドのそれぞれを分離する実行中のFirefox:
lo UNKNOWN 127.0.0.1/8 :: 1/128 eth0 UP 192.0.2.2/24 2001:db8:0:1:bc5c:95c7:4ea6:f94f/64 fe80 :: b4f0 :7aff:fe76:76a8/64 wlan0 DOWN dummy0 UNKNOWN 198.51.100.2/24 fe80 :: 108a:83ff:fe05:e0da/64 lxcbr0 UP 10.0.3.1/ 24 2001:db8:0:4 :: 1/64 fe80 :: 216:3eff:fe00:0/64 virbr0 DOWN192.168.122.1/24 virbr0-nicDOWN vethSOEPSH @ if9 UP fe80 :: fc8e:ff:fe85:476f/64 ネットワークの終わり4026531992 lo DOWN ネットワークの終わり4026532418 lo DOWN end of network 4026532518 lo DOWN end of network 4026532618 lo DOWN ネットワークの終わり4026532718 lo UNKNOWN 127.0.0.1/8 :: 1/128 eth0 @ if10 UP 10.0.3.66/24 fe80 :: 216:3eff:fe6a:c1e9/64 end of network 4026532822 lo DOWN bridge0 UNKNOWN fe80: :b884:44ff:feaf:dca3/64 ネットワークの終わり4026532923 lo DOWN dummy0 DOWN10.11.12.13/24 endof networkネットワーク4026533021 INIT NETWORK:4026531992
_ip netns list
_は、ip-netns(8)
ユーティリティを介して構成されたネットワーク名前空間のみをリストします。
_util-linux
_パッケージのlsns(1)
プログラムは、_/proc/<pid>/ns/
_ファイルを介してアクセスできるネームスペースのみをリストし、バインドマウントまたは開いているファイル記述子によって保持されているネームスペースを省略します。
これは明らかに不十分です。次のデモスクリプトは、これを修正しようとします。_/proc/<pid>/mountinfo
_ファイルを介してバインドマウントを検索し、_/proc/<pid>/fd
_ファイルを介して開いているfdsを検索します。
名前空間ごとに、アクセス可能なパスを出力します。
_# Perl ./lsnsx.pl
...
mnt 3
4026531840 /proc/1/ns/mnt
4026531860 /proc/30/ns/mnt
4026532374 /proc/3119/ns/mnt
net 6
4026531992 /proc/1/ns/net
4026532376 /proc/25781/fd/9
4026532465 /proc/28373/fd/7
...
_
次に、そのパスをnsenter(1)
で使用できます。
_nsenter --net=/proc/28373/fd/7 ip link
_
スクリプトは、それ自体を実行するように簡単に変更したり、名前空間を使用するプロセスのリスト全体などの他の情報を表示したりできます。
パスにアクセスできない場合は、親/マウントIDと、パスが見つかった_/proc/<pid>/mountinfo
_ファイルが続きます。エスケープされた改行、タブ、スペースはそのままになります。
_net 9
...
4026532732 /v/net\040ns /proc/3119/mountinfo 60 41
_
_lsnsx.pl
_:
_#! /usr/bin/Perl
use strict;
my %nstype = (
# the CLONE_NEW* from sched.h
0x02000000 => "cgroup", 0x04000000 => "uts", 0x08000000 => "ipc",
0x10000000 => "user", 0x20000000 => "pid", 0x40000000 => "net",
0x00020000 => "mnt" # CLONE_NEWNS
);
my %ns;
sub unescape { $_[0] =~ s/\\([0-7]{3})/chr oct $1/ger }
sub devino { join ".", (stat unescape $_[0])[0, 1] }
my $nsfs_dev = (stat "/proc/self/ns/mnt")[0];
for(</proc/{[0-9]*/{ns/*,fd/*},[0-9]*/mountinfo}>){
if(my ($procpid) = m{^(.*)/mountinfo$}){
open my $h, $_ or next;
LOOP: while(<$h>){
next unless (my @s = split)[2] eq "0:$nsfs_dev";
if(my($t, $i) = $s[3] =~ /^(\w+):\[(\d+)\]$/){
next if exists $ns{$t}{$i};
for my $p ($s[4], "$procpid/root$s[4]"){
if(devino($p) eq "$nsfs_dev.$i"){
$ns{$t}{$i} = $p; next LOOP
}
}
$ns{$t}{$i} = "@s[4, 0, 1] $procpid/mountinfo"
}
}
}elsif(m{/ns/}){
$ns{$1}{$2} //= $_ if readlink =~ /^(\w+):\[(\d+)\]$/;
}else{
use constant NS_GET_NSTYPE => 0xb7 << 8 | 3;
next unless my ($dev, $ino) = stat $_;
next unless $dev == $nsfs_dev;
next unless open my $h, $_;
next unless my $t = ioctl $h, NS_GET_NSTYPE, 0;
$ns{$nstype{$t} // '???'}{$ino} //= $_;
}
}
for(sort keys %ns){
my $h = $ns{$_}; my @i = sort {$a<=>$b} keys %$h;
printf "%-8s %d\n", $_, scalar @i;
printf " %-11d %s\n", $_, $$h{$_} for @i;
}
_