web-dev-qa-db-ja.com

`/ sys / class / net`を使用して、ネットワークインターフェイスが` veth`であるかどうかを識別しますか?

eth1などの特定のネットワークインターフェイスが実際にはタイプvethネットワークインターフェイスであることを明確に識別することは可能ですか?コンテナでは、ネットワークインターフェイス名は通常eth*ではなくveth*で始まり、セットに実際のethがないことを確認できないことに注意してください。これは/sys/class/netで検出できますか?

/sys/class/net/...iflink要素はvethネットワークインターフェイスを明確に識別せず、代わりに他の状況でも使用されているという印象を受けています。 /sys/class/net/...ファイルシステムを使用して質問を解決する方法がない場合、この情報を提供できるソケット呼び出しはありますか?Pythonで使用できますか?

2
TheDiveO

さらに調査を重ねた結果、_/sys/class/net/..._を使用して目標を達成することはできないという結論に達しました。 幸いなことに、それは達成可能です。

正しく名前空間をマウントする_/sys/class/net_

おかげで 「ネットワーク名前空間に切り替えても/ sys/class/netは変更されませんか?」に対するDanila Kiverの回答 私がする必要があるのは、sysfsをどこかにマウントすることだけです。 sysfsとその_class/net/_ブランチに対する正しい(ネットワーク)名前空間のビューを取得します。

次のPythonの例では、ネットワーク名前空間をスキャンし、特定のネットワーク名前空間内のすべてのネットワークインターフェイスを一覧表示して、各物理ネットワークインターフェイスを_[PHY]_でマークします。このスクリプトにはroot /が必要であることに注意してください。特にマウントによる管理キャップ。

_import psutil
import nsenter
from ctypes import c_char_p, c_ulong
import ctypes.util
import os
import tempfile

# https://stackoverflow.com/a/29156997
libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
libc.mount.argtypes = (c_char_p, c_char_p, c_char_p, c_ulong, c_char_p)
libc.umount.argtypes = (c_char_p, )

netns_index = dict()
for process in psutil.process_iter():
    netns_ref = '/proc/%d/ns/net' % process.pid
    try:
        netns_id = os.stat(netns_ref).st_ino
        if netns_id not in netns_index:
            netns_index[netns_id] = netns_ref
    except PermissionError:
        pass

with tempfile.TemporaryDirectory() as temp_mnt:
    for netns_id, netns_ref in netns_index.items():
        with nsenter.Namespace(netns_ref, 'net'):
            print('net:[%d]' % netns_id)
            if libc.mount('sysfs'.encode('ascii'),
                          temp_mnt.encode('ascii'),
                          'sysfs'.encode('ascii'),
                          0,
                          ''.encode('ascii')) >= 0:
                for nif_name in sorted(os.listdir('%s/class/net' % temp_mnt)):
                    nif_path = os.readlink('%s/class/net/%s' % (temp_mnt, nif_name))
                    phys_nif = not nif_path.startswith('../../devices/virtual/')
                    print('  %s %s' % (nif_name, '[PHY]' if phys_nif else ''))
                libc.umount(temp_mnt.encode('ascii'))
_

_/sys/class/net_なしの回避策

ただし、LinuxカーネルへのNETLINKインターフェースは必要な情報を提供します。そうでない場合、_ip link_コマンドはインターフェースの種類を判別できません。

ここで重要なのは、カーネルにネットワークリンク(つまり、ネットワークインターフェイス)のリストを要求したときに返される_IFLA_LINKINFO_属性です。その中には_IFLA_INFO_KIND_と呼ばれる別の属性があり、vethネットワークインターフェースの場合はveth、Linuxカーネルブリッジの場合はbridgeです。

_IFLA_LINKINFO_はオプションの属性であることに注意してください。たとえば、ループバック、イーサネット、およびWi-Fiネットワークインターフェイスは_IFLA_LINKINFO_を提供しません。

この情報は、有名な pyroute2 ネットリンクライブラリを使用してPythonで簡単に取得できます。_pyroute2_はすべての厄介なNETLINKのものを扱い、_pip3_。この例では、現在のネットワーク名前空間に表示されているすべてのネットワークインターフェイスを単純に繰り返し、名前、インターフェイスインデックス、および_IFLA_LINKINFO_値(存在する場合)を指定します。

 frompyroute2 import IPRoute 
 
 netw = IPRoute()
 for link in netw.get_links():
 ifindex = link ['index' ] 
 ifname = link.get_attr( 'IFLA_IFNAME')
 linkinfo = link.get_attr( 'IFLA_LINKINFO')
 linkinfoがNoneでない場合:
 linktype = linkinfo .get_attr( 'IFLA_INFO_KIND')
 else:
 linktype = 'なし' 
 
 print( '{0}:#{1} {2}'。 format(ifname、ifindex、linktype))
1
TheDiveO