AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 441876
Accepted
TheDiveO
TheDiveO
Asked: 2018-05-05 12:41:43 +0800 CST2018-05-05 12:41:43 +0800 CST 2018-05-05 12:41:43 +0800 CST

Como encontrar o namespace de rede de um ifindex veth peer?

  • 772

Tarefa

Eu preciso de forma inequívoca e sem suposições "holísticas" encontrar a interface de rede peer de um veth final em outro namespace de rede.

Teoria ./. Realidade

Embora muita documentação e também respostas aqui no SO assumam que os índices ifindex de interfaces de rede são globalmente exclusivos por host em namespaces de rede, isso não ocorre em muitos casos : ifindex/iflink são ambíguos . Até o loopback já mostra o contrário, tendo um ifindex de 1 em qualquer namespace de rede. Além disso, dependendo do ambiente do contêiner, os ifindexnúmeros são reutilizados em diferentes namespaces . O que torna o rastreamento da fiação veth um pesadelo, especialmente com muitos contêineres e uma ponte de host com veth peers, todos terminando em @if3 ou algo assim ...

Exemplo: link-netnsidé0

Gire uma instância de contêiner do Docker, apenas para obter um novo vethpar conectando-se do namespace da rede do host ao novo namespace da rede do contêiner...

$ sudo docker run -it debian /bin/bash

Agora, no namespace da rede do host, liste as interfaces de rede (deixei de fora as interfaces que não interessam a esta pergunta):

$ show de link ip
1: lo: mtu 65536 qdisc noqueue estado DESCONHECIDO modo DEFAULT padrão do grupo qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
...
4: docker0: mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/éter 02:42:34:23:81:f0 brd ff:ff:ff:ff:ff:ff
...
16: vethfc8d91e@if15: mtu 1500 qdisc noqueue master docker0 estado UP mode DEFAULT group default
    link/éter da:4c:f7:50:09:e2 brd ff:ff:ff:ff:ff:ff link-netnsid 0

Como você pode ver, embora o iflinkseja inequívoco, mas o link-netnsidé 0, apesar da extremidade do par estar em um namespace de rede diferente.

Para referência, verifique o netnsid no namespace de rede sem nome do contêiner:

$ sudo lsns -t rede
        NS TIPO NPROCS PID COMANDO DO USUÁRIO
...
...
4026532469 net 1 29616 root /bin/bash

$ sudo nsenter -t 29616 -n show de link ip
1: lo: mtu 65536 qdisc noqueue estado DESCONHECIDO modo DEFAULT padrão do grupo qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
15: eth0@if16: mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0

Portanto, para ambas as extremidades veth ip link show(e RTNETLINK fwif) nos diz que eles estão no mesmo namespace de rede com netnsid 0. O que está errado ou correto sob as suposições de que os netnsids de link são locais em oposição a globais. Não consegui encontrar nenhuma documentação que tornasse explícito qual escopo o link-netnsids deveria ter.

/sys/class/net/...NÃO para o resgate?

Procurei em /sys/class/net/ if /... mas só consigo encontrar os elementos ifindex e iflink; estes estão bem documentados. "ip link show" também parece mostrar apenas o par ifindex na forma da (in)famosa notação "@if#". Ou eu perdi algum elemento de namespace de rede adicional?

Conclusão/Pergunta

Existem syscalls que permitem recuperar as informações de namespace de rede ausentes para o ponto final de um par veth?

networking network-namespaces
  • 3 3 respostas
  • 14182 Views

3 respostas

  • Voted
  1. A.B
    2018-05-05T17:21:59+08:002018-05-05T17:21:59+08:00

    Aqui está o método que segui para descobrir como entender esse problema. As ferramentas disponíveis parecem utilizáveis ​​(com alguma convolução) para a parte do namespace e (ATUALIZADA) usando /sys/ pode obter facilmente o índice do par. Portanto, é bastante longo, tenha paciência comigo. Está em duas partes (que não estão na ordem lógica, mas primeiro o namespace ajuda a explicar a nomenclatura do índice), usando ferramentas comuns, não qualquer programa personalizado:

    • Espaço de nomes de rede
    • índice de interface

    Espaço de nomes de rede

    Essas informações estão disponíveis com a propriedade link-netnsidna saída de ip linke podem ser combinadas com o id na saída de ip netns. É possível "associar" o namespace de rede de um container com ip netns, usando assim ip netnscomo uma ferramenta especializada. Claro que fazer um programa específico para isso seria melhor (algumas informações sobre syscalls no final de cada parte).

    Sobre a descrição do nsid, eis o que man ip netnsdiz (grifo meu):

    ip netns set NAME NETNSID - atribui um id a um namespace de rede peer

    Este comando atribui um id a um namespace de rede peer. Este id é válido apenas no namespace da rede atual. Este id será usado pelo kernel em algumas mensagens netlink . Se nenhum id for atribuído quando o kernel precisar, ele será atribuído automaticamente pelo kernel. Uma vez atribuído, não é possível alterá-lo.

    Embora a criação de um namespace com ip netnsnão crie imediatamente um netnsid, ele será criado (no namespace atual, provavelmente o "host") sempre que um veth half for definido para outro namespace. Portanto, é sempre definido para um contêiner típico.

    Aqui está um exemplo usando um contêiner LXC:

    # lxc-start -n stretch-amd64
    

    Um novo link veth veth9RPX4Mapareceu (isso pode ser rastreado com ip monitor link). Aqui estão as informações detalhadas:

    # ip -o link show veth9RPX4M
    44: veth9RPX4M@if43: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master lxcbr0 state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether fe:25:13:8a:00:f8 brd ff:ff:ff:ff:ff:ff link-netnsid 4
    

    Este link tem a propriedade link-netnsid 4, informando que o outro lado está no namespace da rede com nsid 4. Como verificar se é o contêiner LXC? A maneira mais fácil de obter essas informações é ip netnsacreditar que ele criou o namespace de rede do contêiner, fazendo as operações sugeridas na página de manual .

    # mkdir -p /var/run/netns
    # touch /var/run/netns/stretch-amd64
    # mount -o bind /proc/$(lxc-info -H -p -n stretch-amd64)/ns/net /var/run/netns/stretch-amd64
    

    ATUALIZAÇÃO3 : Não entendi que encontrar o nome global era um problema. Aqui está:

    # ls -l /proc/$(lxc-info -H -p -n stretch-amd64)/ns/net
    lrwxrwxrwx. 1 root root 0 mai    5 20:40 /proc/17855/ns/net -> net:[4026532831]
    
    # stat -c %i /var/run/netns/stretch-amd64 
    4026532831
    

    Agora a informação é recuperada com:

    # ip netns | grep stretch-amd64
    stretch-amd64 (id: 4)
    

    Ele confirma que o par do veth está no namespace da rede com o mesmo nsid = 4 = link-netnsid.

    O contêiner/ ip netns"associação" pode ser removido (sem remover o namespace, desde que o contêiner esteja em execução):

    # ip netns del stretch-amd64
    

    Observação: a nomenclatura nsid é por namespace de rede, geralmente começa com 0 para o primeiro contêiner e o valor mais baixo disponível é reciclado com novos namespaces.

    Sobre o uso de syscalls, aqui estão as informações adivinhadas do strace:

    • para a parte do link: requer um AF_NETLINKsocket (aberto com socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)), pedindo ( sendmsg()) as informações do link com um tipo de mensagem RTM_GETLINKe recuperando ( recvmsg()) a resposta com um tipo de mensagem RTM_NEWLINK.

    • para a parte netns nsid: mesmo método, a mensagem de consulta é digitada com tipo RTM_GETNSIDde resposta RTM_NEWNSID.

    Acho que as bibliotecas de nível um pouco mais alto para lidar com isso estão lá: libnl . De qualquer forma, é um tópico para SO .

    índice de interface

    Agora será mais fácil entender por que o índice parece ter comportamentos aleatórios. Vamos fazer um experimento:

    Primeiro insira um novo espaço de nomes de rede para ter uma lista limpa (índice):

    # ip netns add test
    # ip netns exec test bash
    # ip netns id
    test
    # ip -o link 
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    

    Como observou OP, lo começa com o índice 1.

    Vamos adicionar 5 net namespaces, criar pares veth e colocar um veth end neles:

    # for i in {0..4}; do ip netns add test$i; ip link add type veth peer netns test$i ; done
    # ip -o link|sed 's/^/    /'
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    2: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether e2:83:4f:60:5a:30 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    3: veth1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 22:a7:75:8e:3c:95 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    4: veth2@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 72:94:6e:e4:2c:fc brd ff:ff:ff:ff:ff:ff link-netnsid 2
    5: veth3@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether ee:b5:96:63:62:de brd ff:ff:ff:ff:ff:ff link-netnsid 3
    6: veth4@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether e2:7d:e2:9a:3f:6d brd ff:ff:ff:ff:ff:ff link-netnsid 4
    

    Quando está exibindo @if2 para cada um deles, fica bem claro que é o índice da interface de namespace do peer e o índice não é global, mas por namespace. Quando está exibindo um nome de interface real, é uma relação com uma interface no mesmo espaço de nome (seja peer, bridge, bond ...). Então, por que veth0 não tem um par exibido? Acredito que seja um ip linkbug quando o índice é igual a ele mesmo. Apenas mover duas vezes o link do par "resolve" aqui, porque forçou uma mudança de índice. Também tenho certeza que às vezes ip linkfaço outras confusões e, em vez de exibir @ifXX, exibe uma interface no namespace atual com o mesmo índice.

    # ip -n test0 link set veth0 name veth0b netns test
    # ip link set veth0b netns test0
    # ip -o link
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    2: veth0@if7: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether e2:83:4f:60:5a:30 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    3: veth1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 22:a7:75:8e:3c:95 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    4: veth2@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 72:94:6e:e4:2c:fc brd ff:ff:ff:ff:ff:ff link-netnsid 2
    5: veth3@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether ee:b5:96:63:62:de brd ff:ff:ff:ff:ff:ff link-netnsid 3
    6: veth4@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether e2:7d:e2:9a:3f:6d brd ff:ff:ff:ff:ff:ff link-netnsid 4
    

    ATUALIZAÇÃO : lendo novamente as informações na pergunta do OP, o índice do par (mas não o nsid) está disponível de maneira fácil e inequívoca com .cat /sys/class/net/ interface /iflink

    ATUALIZAÇÃO2 :

    Todos esses iflink 2 podem parecer ambíguos, mas o que é único é a combinação de nsid e iflink, não apenas iflink. Para o exemplo acima, isto é:

    interface    nsid:iflink
    veth0        0:7
    veth1        1:2
    veth2        2:2
    veth3        3:2
    veth4        4:2
    

    Neste namespace (ou seja, namespace test), nunca haverá dois mesmos nsid:pair .

    Se alguém procurasse em cada rede de pares as informações opostas:

    namespace    interface    nsid:iflink
    test0        veth0        0:2
    test1        veth0        0:3
    test2        veth0        0:4
    test3        veth0        0:5
    test4        veth0        0:6
    

    Mas tenha em mente que tudo o 0:que existe para cada um é um 0 separado, que mapeia para o mesmo namespace de mesmo nível (a saber: namespace test, nem mesmo o host). Eles não podem ser comparados diretamente porque estão vinculados ao seu namespace. Portanto, todas as informações comparáveis ​​e exclusivas devem ser:

    test0:0:2
    test1:0:3
    test2:0:4
    test3:0:5
    test4:0:6
    

    Uma vez confirmado que "test0:0" == "test1:0" etc. (verdadeiro neste exemplo, todos são mapeados para o namespace net chamado testpor ip netns), eles podem ser realmente comparados.

    Sobre syscalls, ainda olhando para os resultados do strace, as informações são recuperadas como acima de RTM_GETLINK. Agora deve haver todas as informações disponíveis:

    local: índice de interface com SIOCGIFINDEX/ peer: nsid e índice de interface com .if_nametoindex
    RTM_GETLINK

    Tudo isso provavelmente deve ser usado com libnl .

    • 9
  2. Best Answer
    TheDiveO
    2018-05-06T09:26:35+08:002018-05-06T09:26:35+08:00

    Muito obrigado a @AB que preencheu algumas lacunas para mim, especialmente no que diz respeito à semântica de netnsids. Seu PoC é muito instrutivo. No entanto, a peça crucial que falta em seu PoC é como correlacionar um local netnsidao seu número de inode de namespace de rede globalmente exclusivo, porque somente assim podemos conectar inequivocamente os vethpares correspondentes corretos.

    Para resumir e dar um pequeno exemplo Python de como reunir as informações programaticamente sem ter que confiar ip netnse montar coisas: RTNETLINK na verdade retorna o netnsid ao consultar interfaces de rede. É o IFLA_LINK_NETNSIDatributo, que só aparece nas informações de um link quando necessário. Se não estiver lá, então não é necessário -- e devemos assumir que o índice de peer refere-se a uma interface de rede local de namespace.

    A lição importante para levar para casa é que um netnsid/ IFLA_LINK_NETSIDsó é definido localmente dentro do namespace da rede onde você o obteve ao solicitar informações de link ao RTNETLINK. Um netnsidcom o mesmo valor obtido em um namespace de rede diferente pode identificar um namespace de peer diferente, portanto, tome cuidado para não usar o netnsidfora de seu namespace. inodeMas qual namespace ( número) de rede identificável exclusivamente mapeia para qual netnsid?

    Como se vê, uma versão muito recente lsnsde março de 2018 é bem capaz de mostrar o correto netnsidao lado de seu número de inode de namespace de rede! Portanto, existe uma maneira de mapear netnsids locais para inodes de namespace, mas na verdade é inverso! E é mais um oráculo (com um ell minúsculo) do que uma pesquisa: RTM_GETNSID precisa de um identificador de namespace de rede como um PID ou FD (para o namespace de rede) e então retorna o arquivo netnsid. Consulte https://stackoverflow.com/questions/50196902/retrieving-the-netnsid-of-a-network-namespace-in-python para obter um exemplo de como perguntar ao oráculo de namespace da rede Linux.

    Em conseqüência, você precisa enumerar os namespaces de rede disponíveis (via /proce/ou /var/run/netns), então, para uma determinada vethinterface de rede anexar ao namespace de rede onde você o encontrou, peça os netnsids de todos os namespaces de rede que você enumerou no início (porque você nunca sabe de antemão qual é qual) e, finalmente, mapeie o netnsiddo vethpeer para o número de inode do namespace de acordo com o mapa local que você criou na etapa 3 após anexar ao vethnamespace do 's.

    import psutil
    import os
    import pyroute2
    from pyroute2.netlink import rtnl, NLM_F_REQUEST
    from pyroute2.netlink.rtnl import nsidmsg
    from nsenter import Namespace
    
    # phase I: gather network namespaces from /proc/[0-9]*/ns/net
    netns = dict()
    for proc in psutil.process_iter():
        netnsref= '/proc/{}/ns/net'.format(proc.pid)
        netnsid = os.stat(netnsref).st_ino
        if netnsid not in netns:
            netns[netnsid] = netnsref
    
    # phase II: ask kernel "oracle" about the local IDs for the
    # network namespaces we've discovered in phase I, doing this
    # from all discovered network namespaces
    for id, ref in netns.items():
        with Namespace(ref, 'net'):
            print('inside net:[{}]...'.format(id))
            ipr = pyroute2.IPRoute()
            for netnsid, netnsref in netns.items():
                with open(netnsref, 'r') as netnsf:
                    req = nsidmsg.nsidmsg()
                    req['attrs'] = [('NETNSA_FD', netnsf.fileno())]
                    resp = ipr.nlm_request(req, rtnl.RTM_GETNSID, NLM_F_REQUEST)
                    local_nsid = dict(resp[0]['attrs'])['NETNSA_NSID']
                if local_nsid != 2**32-1:
                    print('  net:[{}] <--> nsid {}'.format(netnsid, local_nsid))
    
    • 7
  3. Sam Stoelinga
    2019-12-31T15:24:23+08:002019-12-31T15:24:23+08:00

    Criei um script simples que lista todos os contêineres com a interface veth associada: https://github.com/samos123/docker-veth/blob/master/docker-veth.sh

    Deixe-me explicar como funciona:

    1. Encontre o PID do contêiner
    pid=$(docker inspect --format '{{.State.Pid}}' $containerID)
    
    1. Insira o namespace da rede usandonsenter
    nsenter -t $pid -n ip a
    

    Você notará que há uma eth0@ifXinterface dentro do namespace da rede do contêiner. O X informa o índice da interface na rede do host. Este índice pode então ser usado para descobrir qual veth pertence ao contêiner.

    Execute os seguintes comandos para localizar a interface veth:

    ifindex=$(nsenter -t $pid -n ip link | sed -n -e 's/.*eth0@if\([0-9]*\):.*/\1/p')
    veth=$(ip -o link | grep ^$ifindex | sed -n -e 's/.*\(veth[[:alnum:]]*@if[[:digit:]]*\).*/\1/p')
    echo $veth
    

    Postagem no blog com mais detalhes: http://samos-it.com/posts/enter-namespace-of-other-containers-from-a-pod.html

    • 2

relate perguntas

  • Encontrar threads/scripts associados a uma porta?

  • Pergunta sobre arquivos montados em rede

  • Um endereço IP pode terminar em 255 e não ser um endereço IP de transmissão?

  • Incapaz de identificar qual saída de endereço MAC do comando arp ou comando ip está correta

  • Roteador estranho funciona com centos 6 [fechado]

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve