Created
April 7, 2021 22:43
-
-
Save atoonk/98bb2ec5f4c9eb188c19da3422883de3 to your computer and use it in GitHub Desktop.
VPP DPDK interface stats
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import subprocess | |
import time | |
import signal | |
import sys, os | |
def get_stats(interface): | |
command=["vppctl", "show", "hardware-interfaces", interface] | |
cmd_output = subprocess.Popen( | |
command, | |
stdout=subprocess.PIPE, | |
stderr=subprocess.STDOUT, | |
universal_newlines=True, | |
) | |
stdout, stdr = cmd_output.communicate() | |
if cmd_output.returncode != 0: | |
print(f"error>>> command: {command}") | |
print(f"error>>> error code: {cmd_output.returncode}") | |
for line in stdout.splitlines(): | |
print(f"error >>> {line}") | |
return False | |
else: | |
return stdout.splitlines() | |
def parse(stats): | |
found = False | |
results = { | |
"rx_frames":0, | |
"tx_frames":0, | |
"rx_bytes":0, | |
"tx_bytes":0, | |
} | |
for line in stats: | |
line = line.strip() | |
if line.startswith("rx bytes ok"): | |
values = line.split() | |
results['rx_bytes']=int(values[-1]) | |
found = True | |
if line.startswith("tx bytes ok"): | |
values = line.split() | |
results['tx_bytes']=int(values[-1]) | |
found = True | |
if line.startswith("rx frames ok"): | |
values = line.split() | |
results['rx_frames']=int(values[-1]) | |
found = True | |
if line.startswith("tx frames ok"): | |
values = line.split() | |
results['tx_frames']=int(values[-1]) | |
found = True | |
if not found: | |
print(f"No stats found for {interface}. Are you sure this interface exists?") | |
sys.exit(1) | |
return results | |
def pretty_number(value): | |
if value < 1 * 1024: | |
return [value,""] | |
if value < 1 * 1024 * 1024: | |
return [value/1024,"K"] | |
if value < 1 * 1024 * 1024 * 1024: | |
return [value/(1024*1024),"M"] | |
if value < 1 * 1024 * 1024 * 1024 * 1024: | |
return [value/(1024*1024*1024),"G"] | |
def print_stats(counters_old, counters_new,interval): | |
stats_to_print = {} | |
for counter in counters_old: | |
diff = counters_new[counter] - counters_old[counter] | |
stats_to_print[counter] = diff / interval | |
in_bps = f"bps_in %3.2f {pretty_number(stats_to_print['rx_bytes']*8)[1]}" % pretty_number(stats_to_print['rx_bytes']*8)[0] | |
out_bps = f"bps_out %3.2f {pretty_number(stats_to_print['tx_bytes']*8)[1]}" % pretty_number(stats_to_print['tx_bytes']*8)[0] | |
in_pps = f"pps_in %3.2f {pretty_number(stats_to_print['rx_frames'])[1]}" % pretty_number(stats_to_print['rx_frames'])[0] | |
out_pps = f"pps_out %3.2f {pretty_number(stats_to_print['tx_frames'])[1]}" % pretty_number(stats_to_print['tx_frames'])[0] | |
print(f'|{in_bps:16} |{out_bps:16} |{in_pps:16} |{out_pps:16} |') | |
# capture CTRL + C or other signal here | |
def goodbye(signal, frame): | |
print('CTRL-C detected. Goodbye') | |
sys.exit(0) | |
if __name__ == "__main__": | |
# Handel interrupt from keyboard (CTRL + C) and call goodbye() | |
signal.signal(signal.SIGINT, goodbye) | |
#First paramater is interface name, if second that will be interval | |
try: | |
interface = sys.argv[1] | |
except IndexError: | |
print(f"Usage: {sys.argv[0]} interface_name(string) [interval(int)]") | |
sys.exit(1) | |
try: | |
interval = int(sys.argv[2]) | |
except IndexError: | |
interval = 1 | |
counters = {} | |
while True: | |
stats = get_stats(interface) | |
counters_new = parse(stats) | |
if not counters: | |
# This should happen the first loop only. | |
# means we have no stats from the previous run, so nothing to print | |
pass | |
else: | |
print_stats(counters, counters_new,interval) | |
counters = counters_new | |
time.sleep(interval) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To be used on a VPP machine