12

i have 2 containers by docker, and bridge like this:

# docker ps
CONTAINER ID        IMAGE                                         COMMAND                CREATED             STATUS              PORTS                      NAMES
ef99087167cb        images.docker.sae.sina.com.cn/ubuntu:latest   /bin/bash -c /home/c   2 days ago          Up 21 minutes       0.0.0.0:49240->22223/tcp   night_leve3         
c8a7b18ec20d        images.docker.sae.sina.com.cn/ubuntu:latest   /bin/bash -c /home/c   2 days ago          Up 54 minutes       0.0.0.0:49239->22223/tcp   night_leve2 

#brctl show cbr0
bridge name bridge id       STP enabled interfaces
docker0     8000.72b675c52895   no      vethRQOy1I
                                        vethjKYWka

How can i get which container match veth* ?

ef99 => vethRQOy1I or ef99 => vethjKYWka

//----------------------------------------------------------

I know it works by ethtool, but is there any better way?

Nick
  • 1,882
  • 11
  • 16
user3300984
  • 121
  • 1
  • 1
  • 3
  • how to do this by ethtool? – Jiri Feb 13 '14 at 05:07
  • 3
    the pipe interface index seems sequential, ex: vethXXX is 19 then the container eth index must be 18, ethtool -S vethXXX, you can get the index, and you can log into container to check the exactly index or guess the pair – user3300984 Feb 14 '14 at 05:58

9 Answers9

16

Here's a variation on the ethtool trick mentioned above, without actually using ethtool:

function veth_interface_for_container() {
  # Get the process ID for the container named ${1}:
  local pid=$(docker inspect -f '{{.State.Pid}}' "${1}")

  # Make the container's network namespace available to the ip-netns command:
  mkdir -p /var/run/netns
  ln -sf /proc/$pid/ns/net "/var/run/netns/${1}"

  # Get the interface index of the container's eth0:
  local index=$(ip netns exec "${1}" ip link show eth0 | head -n1 | sed s/:.*//)
  # Increment the index to determine the veth index, which we assume is
  # always one greater than the container's index:
  let index=index+1

  # Write the name of the veth interface to stdout:
  ip link show | grep "^${index}:" | sed "s/${index}: \(.*\):.*/\1/"

  # Clean up the netns symlink, since we don't need it anymore
  rm -f "/var/run/netns/${1}"
}
Joel Dice
  • 226
  • 3
  • 2
  • 3
    I don't seem to have enough reputation to comment on the "lxc.network.veth.pair" answer, but I'll note that recent versions of Docker use libcontainer instead of LXC by default, in which case any options passed via --lxc-conf are silently ignored. – Joel Dice Feb 19 '15 at 21:58
  • This answer definitely not working for GKE in 2020 :-D . Going to post another one – Nick Jun 04 '20 at 12:19
6

There are multiple "hackish" ways to do it:

  • scan kernel logs, as mentioned by Jiri (but you have to do it right after starting the container, otherwise it gets messy);
  • check the interface counters (sent/received packets/bytes) in the container, then compare with the interfaces in the host, and find the pair that matches exactly (but with sent and receive directions flipped);
  • use an iptables LOG rule.

The last option is, IMHO, the more reliable one (and the easiest to use), but it's still very hackish. The idea is very simple:

  1. Add an iptables rule to log e.g. ICMP traffic arriving on the Docker bridge:

    sudo iptables -I INPUT -i docker0 -p icmp -j LOG

  2. Send a ping to the container you want to identify:

    IPADDR=$(docker inspect -format='{{.NetworkSettings.IPAddress}}' 0c33)

    ping -c 1 $IPADDR

  3. Check kernel logs:

    dmesg | grep $IPADDR

    You will see a line looking like this:

    […] IN=docker0 OUT= PHYSIN=vethv94jPK MAC=fe:2c:7f:2c:ab:3f:42:83:95:74:0b:8f:08:00 SRC=172.17.0.79 …

    If you want to be fancy, just extract PHYSIN=… with awk or sed.

  4. Remove the iptables logging rule (unless you want to leave it there because you will regularly ping containers to identify them).

If you need a bullet-proof version, you can install ulogd and use the ULOG target. Instead of just writing packet headers to the kernel log, it will send them through a netlink socket, and a userland program can then process them properly.

jpetazzo
  • 14,874
  • 3
  • 43
  • 45
3

Try this script:

get_network_mode() {
    docker inspect --format='{{.HostConfig.NetworkMode}}' "$1"
}


created_by_kubelet() {
    [[ $(docker inspect --format='{{.Name}}' "$1") =~ ^/k8s_ ]]
}


for container_id in $(docker ps -q); do
    network_mode=$(get_network_mode "${container_id}")
    # skip the containers whose network_mode is 'host' or 'none',
    # but do NOT skip the container created by kubelet.
    if [[ "${network_mode}" == "host" || \
          $(! created_by_kubelet "${container_id}") && "${network_mode}" == "none" ]]; then
        echo "${container_id} => ${network_mode}"
        continue
    fi

    # if one container's network_mode is 'other container',
    # then get its root parent container's network_mode.
    while grep container <<< "${network_mode}" -q; do
        network_mode=$(get_network_mode "${network_mode/container:/}")
        # skip the containers whose network_mode is 'host' or 'none',
        # but do NOT skip the container created by kubelet.
        if [[ "${network_mode}" == "host" || \
              $(! created_by_kubelet "${container_id}") && "${network_mode}" == "none" ]]; then
            echo "${container_id} => ${network_mode}"
            continue 2
        fi
    done

    # get current container's 'container_id'.
    pid=$(docker inspect --format='{{.State.Pid}}' "${container_id}")

    # get the 'id' of veth device in the container.
    veth_id=$(nsenter -t "${pid}" -n ip link show eth0 |grep -oP '(?<=eth0@if)\d+(?=:)')

    # get the 'name' of veth device in the 'docker0' bridge (or other name),
    # which is the peer of veth device in the container.
    veth_name=$(ip link show |sed -nr "s/^${veth_id}: *([^ ]*)@if.*/\1/p")

    echo "${container_id} => ${veth_name}"
done

Explains:

  • avoid to execute commands in container.
  • avoid to create temporary folders and files.
  • MOST importantly, avoid to get incorrect answers for containers whose NetworkMode is host, none, or container:<name|id> (share network stack with another container's. For example: user's containers in one pod in kubernetes share the network stack with the pause pod container's network stack)
Weike
  • 1,232
  • 12
  • 15
1

If anyone is still interested in this. I found this on the docker mailing list: http://permalink.gmane.org/gmane.comp.sysutils.docker.user/3182

You can define the name of the veth yourself by passing the lxc-conf parameter "lxc.network.veth.pair". E.g.:

docker run -rm -i -t --lxc-conf="lxc.network.veth.pair=foobar" ubuntu /bin/bash

Creates a container with a veth interface named "foobar".

See this page for more handy lxc-conf parameters: http://manpages.ubuntu.com/manpages/precise/man5/lxc.conf.5.html

Community
  • 1
  • 1
whiskeysierra
  • 5,030
  • 1
  • 29
  • 40
1

As far as I get it you need the virtual net device associated with a container?

You can get it by:

1:

docker exec -it <container> cat /sys/class/net/<physical-device>/iflink
# the output looks like this -> 20  

then

2:

# ip ad | grep <the output, like 20>:
 ip ad | grep 20:
# the output looks, like this:
# 20: vetha5531eb@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-0595ab5d7c95 state UP group default qlen 1000
# where vetha5531eb is what I think you're looking for.
gai-jin
  • 653
  • 2
  • 10
  • 24
0

I don't know how to get it properly, but you use a hack: you can scan the syslog for added interfaces after you run your container:

#!/bin/sh

JOB=$(sudo docker run -d ...)
sleep 1s
INTERFACE=$(grep "docker0: port" /var/log/syslog | tail -n 1 |  sed -r s/^.*\(veth[^\)]+\).*$/\\1/)
echo "job: $JOB interface: $INTERFACE"
Jiri
  • 16,425
  • 6
  • 52
  • 68
0
dmesg --clear
for i in $(docker inspect $(docker ps -a -q) | grep IPAddress | cut -d\" -f4); do ping -c 1 -w 1 $i >/dev/null; done
while read line
do
IPADDRESS=$(docker inspect $line | grep IPAddress | cut -d\" -f4)
NAME=$(docker inspect $line | grep Name | cut -d/ -f2 | cut -d\" -f1)
FOUND=$(dmesg | grep $IPADDRESS | grep -Po 'vet[A-Za-z0-9]+' | sort -u)
echo "GEVONDEN $IPADDRESS MET NAAM : $NAME en INTERFACE: $FOUND" | grep NAAM
done < <(docker ps -a -q)
kRiZ
  • 2,320
  • 4
  • 28
  • 39
0

This is just an update for the answer given by Joel Dice on "Feb 19 2015"

Original code (valid for 2015)

# Get the interface index of the container's eth0:
  local index=$(ip netns exec "${1}" ip link show eth0 | head -n1 | sed s/:.*//)
  # Increment the index to determine the veth index, which we assume is
  # always one greater than the container's index:
  let index=index+1

  # Write the name of the veth interface to stdout:
  ip link show | grep "^${index}:" | sed "s/${index}: \(.*\):.*/\1/"

results in:

$ index=$(sudo ip netns exec "ns-4012085" ip link show eth0 | head -n1 | sed s/:.*//)
$ echo $index
3

$ let index=index+1
$ echo $index
4

$ sudo ip link show | grep "^${index}:" | sed "s/${index}: \(.*\):.*/\1/"
cbr0

Whereas :

index=$(sudo ip netns exec "ns-4012085" ip link show type veth | grep eth0 | sed s/.*@if// | sed s/:.*// )
$ echo $index
14

$ ip link show | grep "^${index}:" | sed "s/${index}: \(.*\):.*/\1/"
veth240a8f81@if3

Hope that'll help someone. :)

P.S. I've got here from this thread.

Nick
  • 1,882
  • 11
  • 16
0

I made a tool for illustrating bridged veth pairs

https://github.com/t1anz0ng/iftree

output can be tree, table, image and graphviz dot language e.g:

sudo iftree

╭─  cni_bridge0    up
│  ╰─  /var/run/netns/123456
│     ╰─  veth57e09f05    eth13
├─  cni_br    up
│  ├─  /var/run/netns/321
│  │  ╰─  veth6328d76d    eth1
...                                       

sudo table --table


├───┬───────────────┬────────────────────────────────────┬──────────────┬───────────────────┤
│   │ BRIDGE        │ NETNS                              │ VETH         │ IFNAME(CONTAINER) │
├───┼───────────────┼────────────────────────────────────┼──────────────┼───────────────────┤
│ 1 │  cni_bridge0  │ /var/run/netns/123456              │ veth57e09f05 │ eth13             │
├───┼───────────────┼────────────────────────────────────┼──────────────┼───────────────────┤
│ 2 │  cni_br       │ /var/run/netns/123                 │ veth5e41415a │ eth1              │
├───┤               │                                    ├──────────────┼───────────────────┤
│ 3 │               │                                    │ veth90c9f5fa │ eth2              │
├───┤               │                                    ├──────────────┼───────────────────┤
│ 4 │               │                                    │ veth385ac3bb │ eth3              │
├───┤               ├────────────────────────────────────┼──────────────┼───────────────────┤
│ 5 │               │ /var/run/netns/321                 │ veth6328d76d │ eth1              │
├───┤               ├────────────────────────────────────┼──────────────┼───────────────────┤
│ 6 │               │ /var/run/docker/netns/415d70663520 │ veth319e1bda │ eth22             │
├───┼───────────────┼────────────────────────────────────┼──────────────┼───────────────────┤
│ 7 │  br0          │ /var/run/netns/netns0              │ veth0        │ ceth0             │

tianzong
  • 1
  • 1
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Aug 02 '22 at 06:25