Identifica se uma interface de rede é um 'veth' usando '/ sys / class / net'?

2

É possível identificar inequivocamente que uma determinada interface de rede, como eth1 , é na verdade uma interface de rede do tipo veth ? Observe que, em contêineres, os nomes de suas interfaces de rede geralmente começam com eth* em vez de veth* e não se pode ter certeza de que não existe um% realeth no conjunto. Isso pode ser detectado através de /sys/class/net ?

Tenho a impressão de que o elemento iflink em /sys/class/net/... não identifica inequivocamente veth interfaces de rede, mas também é usado em outras situações. Se não há como resolver minha pergunta usando o sistema de arquivos /sys/class/net/... , existe uma chamada de soquete que possa me fornecer essa informação, preferencialmente utilizável em Python?

    
por TheDiveO 04.05.2018 / 23:26

1 resposta

1

Depois de mais pesquisas, cheguei à conclusão de que minha meta não é alcançável usando /sys/class/net/... . Felizmente, é possível.

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))
    
por 05.05.2018 / 16:23