Depois de mais pesquisas, cheguei à conclusão de que minha meta não é alcançável usando Felizmente, é possível. /sys/class/net/...
.
Montando corretamente o namespace /sys/class/net
Agradecimentos a A resposta de Danila Kiver a "Mudar para um espaço de nomes de rede não muda / sys / class / net?" tudo o que preciso fazer é montar sysfs
em algum lugar para obter a exibição de namespace correta (rede) para sysfs
e sua class/net/
branch.
O seguinte exemplo do Python verifica os namespaces de rede e, em seguida, lista todas as interfaces de rede em um namespace de rede específico, marcando cada interface de rede física com [PHY]
. Por favor, note que este script precisa de root / admin cap, especialmente devido à montagem.
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'))
Solução alternativa sem /sys/class/net
No entanto, a interface NETLINK para o kernel do Linux fornece as informações necessárias, caso contrário, o comando ip link
não seria capaz de dizer o tipo de interface.
A chave aqui é o atributo IFLA_LINKINFO
que é retornado ao solicitar ao kernel uma lista de links de rede (isto é, interfaces de rede). Dentro dele está outro atributo chamado IFLA_INFO_KIND
, é veth
no caso de uma interface de rede veth
, ou bridge
no caso de uma ponte Kernel do Linux.
Por favor, note que IFLA_LINKINFO
é um atributo opcional; por exemplo, as interfaces de rede de loopback, ethernet e wifi não oferecem IFLA_LINKINFO
.
Essa informação pode ser facilmente obtida em Python usando a famosa pyroute2 biblioteca de netlink. pyroute2
lida com todas as coisas desagradáveis do NETLINK, instale-o facilmente via pip3
. Este exemplo simplesmente itera todas as interfaces de rede visíveis no namespace de rede atual, fornecendo seus nomes, índice de interface e o valor IFLA_LINKINFO
, se houver.
from pyroute2 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') if linkinfo is not None: linktype = linkinfo.get_attr('IFLA_INFO_KIND') else: linktype = 'None' print('{0}: #{1} {2}'.format(ifname, ifindex, linktype))