#!/usr/bin/env bash # shellcheck disable=SC1117 # cgroup-network-helper.sh # detect container and virtual machine interfaces # # (C) 2017 Costa Tsaousis # SPDX-License-Identifier: GPL-3.0-or-later # # This script is called as root (by cgroup-network), with either a pid, or a cgroup path. # It tries to find all the network interfaces that belong to the same cgroup. # # It supports several method for this detection: # # 1. cgroup-network (the binary father of this script) detects veth network interfaces, # by examining iflink and ifindex IDs and switching namespaces # (it also detects the interface name as it is used by the container). # # 2. this script, uses /proc/PID/fdinfo to find tun/tap network interfaces. # # 3. this script, calls virsh to find libvirt network interfaces. # # ----------------------------------------------------------------------------- # the system path is cleared by cgroup-network # shellcheck source=/dev/null [ -f /etc/profile ] && source /etc/profile export LC_ALL=C PROGRAM_NAME="$(basename "${0}")" logdate() { date "+%Y-%m-%d %H:%M:%S" } log() { local status="${1}" shift echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${*}" } warning() { log WARNING "${@}" } error() { log ERROR "${@}" } info() { log INFO "${@}" } fatal() { log FATAL "${@}" exit 1 } debug=${NETDATA_CGROUP_NETWORK_HELPER_DEBUG=0} debug() { [ "${debug}" = "1" ] && log DEBUG "${@}" } # ----------------------------------------------------------------------------- # check for BASH v4+ (required for associative arrays) [ $(( BASH_VERSINFO[0] )) -lt 4 ] && \ fatal "BASH version 4 or later is required (this is ${BASH_VERSION})." # ----------------------------------------------------------------------------- # parse the arguments pid= cgroup= while [ ! -z "${1}" ] do case "${1}" in --cgroup) cgroup="${2}"; shift 1;; --pid|-p) pid="${2}"; shift 1;; --debug|debug) debug=1;; *) fatal "Cannot understand argument '${1}'";; esac shift done if [ -z "${pid}" ] && [ -z "${cgroup}" ] then fatal "Either --pid or --cgroup is required" fi # ----------------------------------------------------------------------------- set_source() { [ ${debug} -eq 1 ] && echo "SRC ${*}" } # ----------------------------------------------------------------------------- # veth interfaces via cgroup # cgroup-network can detect veth interfaces by itself (written in C). # If you seek for a shell version of what it does, check this: # https://github.com/netdata/netdata/issues/474#issuecomment-317866709 # ----------------------------------------------------------------------------- # tun/tap interfaces via /proc/PID/fdinfo # find any tun/tap devices linked to a pid proc_pid_fdinfo_iff() { local p="${1}" # the pid debug "Searching for tun/tap interfaces for pid ${p}..." set_source "fdinfo" grep "^iff:.*" "${NETDATA_HOST_PREFIX}/proc/${p}/fdinfo"/* 2>/dev/null | cut -f 2 } find_tun_tap_interfaces_for_cgroup() { local c="${1}" # the cgroup path [ -d "${c}/emulator" ] && c="${c}/emulator" # check for 'emulator' subdirectory c="${c}/cgroup.procs" # make full path # for each pid of the cgroup # find any tun/tap devices linked to the pid if [ -f "${c}" ] then local p for p in $(< "${c}" ) do proc_pid_fdinfo_iff "${p}" done else debug "Cannot find file '${c}', not searching for tun/tap interfaces." fi } # ----------------------------------------------------------------------------- # virsh domain network interfaces virsh_cgroup_to_domain_name() { local c="${1}" # the cgroup path debug "extracting a possible virsh domain from cgroup ${c}..." # extract for the cgroup path sed -n -e "s|.*/machine-qemu\\\\x2d[0-9]\+\\\\x2d\(.*\)\.scope$|\1|p" \ -e "s|.*/machine/\(.*\)\.libvirt-qemu$|\1|p" \ <