2
0
mirror of https://github.com/munin-monitoring/contrib.git synced 2018-11-08 00:59:34 +01:00

kvm_net: improve the network interface name parser and admit its limits

The network interface parser of this plugin was overly specific before.
It relied on a specific format of the arguments handed over to kvm while
starting the VM.  For example the following format was usable:

  ... -netdev tap,ifname=foo,...

But kvm/qemu support a variety of ways for configuring network
interfaces via the commandline.  E.g. libvirt does not use the "ifname"
parameter above.  Thus VMs running on a host controlled via libvirt
cannot be tracked with this plugin.

This limititation is now clearly documented in the header of the plugin.
This commit is contained in:
Lars Kruse 2018-06-10 21:53:39 +02:00
parent b6c6a02efe
commit e0df6aa788

View File

@ -6,6 +6,24 @@
kvm_net - Munin plugin to show the network I/O per VM
=head1 APPLICABLE SYSTEMS
Virtualization server with VMs based on KVM may be able to track the network
traffic of their VMs, if the KVM processes are started in a specific way.
Probably proxmox-based virtualization hosts fit into this category.
You can easily check if your KVM processes are started in the expected way, by
running the following command:
ps -ef | grep "netdev.*ifname="
The plugin can be used, if the above command outputs one line for every
currently running VM.
In all other cases you need to use other munin plugins instead, e.g. "libvirt".
=head1 CONFIGURATION
parsed environment variables:
@ -39,6 +57,7 @@ import sys
VM_NAME_REGEX = re.compile("^.*\x00-{arg_name}\x00(.+)\x00.*$")
KVM_INTERFACE_NAME_REGEX = re.compile("(?:^|,)ifname=([^,]+)(?:,|$)")
def config(vm_names):
@ -83,18 +102,35 @@ def fetch(vms):
@param dictionnary {kvm_pid: cleaned vm name}
"""
for pid in vms:
tap = get_vm_mac(pid)
try:
f = open("/proc/net/dev", "r")
for line in f.readlines():
if tap in line:
print("%s_in.value %s" % (vms[pid], line.split()[1]))
print("%s_out.value %s" % (vms[pid], line.split()[9]))
break
except Exception as inst:
print(inst)
continue
for pid, vm_data in vms.items():
vm_interface_names = get_vm_network_interface_names(pid)
sum_incoming = 0
sum_outgoing = 0
interface_found = False
with open("/proc/net/dev", "r") as net_file:
for line in net_file.readlines():
tokens = line.split()
current_interface_name = tokens[0].rstrip(":").strip()
if current_interface_name in vm_interface_names:
sum_incoming += int(tokens[1])
sum_outgoing += int(tokens[9])
interface_found = True
if not interface_found:
# we want to distinguish "no traffic" from "not found"
sum_incoming = "U"
sum_outgoing = "U"
print("%s_in.value %s" % (vm_data, sum_incoming))
print("%s_out.value %s" % (vm_data, sum_outgoing))
def get_vm_network_interface_names(pid):
""" return the MAC addresses configured for network interfacs of a PID """
result = set()
for netdev_description in _get_kvm_process_arguments(pid, "netdev"):
match = KVM_INTERFACE_NAME_REGEX.search(netdev_description)
if match:
result.add(match.groups()[0])
return result
def detect_kvm():
@ -139,17 +175,6 @@ def find_vm_names(pids):
return result
def get_vm_mac(pid):
"""Find and clean vm names from pids
@return the mac address for a specified pid
"""
cmdline = open("/proc/%s/cmdline" % pid, "r")
line = cmdline.readline()
mac = re.sub(r"^.*ifname=(tap[^,]+),.*$", r"\1", line)
return mac
def _get_kvm_process_arguments(pid, arg_name):
""" parse all value with the given name from the process identified by PID