mirror of
https://github.com/openwrt/packages.git
synced 2026-04-15 19:02:09 +00:00
mwan3: reimplement rpcd plugin using ucode
On my "test" router (5 wans, 2 tracking ips per wan), before any rework, prometheus-node-exporter-lua mwan3 average scraping time was 1230ms (scraping only the interfaces), after optimizing the shell version, average time was down to 485ms, with ucode we are now at 41ms. Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>
This commit is contained in:
committed by
Florian Eckert
parent
bfdbacca56
commit
6423781254
@@ -8,8 +8,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=mwan3
|
||||
PKG_VERSION:=2.11.19
|
||||
PKG_RELEASE:=5
|
||||
PKG_VERSION:=2.12.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_MAINTAINER:=Florian Eckert <fe@dev.tdt.de>, \
|
||||
Aaron Goodman <aaronjg@alumni.stanford.edu>
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
@@ -28,6 +28,7 @@ define Package/mwan3
|
||||
+IPV6:ip6tables \
|
||||
+iptables-mod-conntrack-extra \
|
||||
+iptables-mod-ipopt \
|
||||
+rpcd-mod-ucode \
|
||||
+jshn
|
||||
TITLE:=Multiwan hotplug script with connection tracking support
|
||||
MAINTAINER:=Florian Eckert <fe@dev.tdt.de>
|
||||
@@ -47,7 +48,7 @@ endef
|
||||
|
||||
define Package/mwan3/postinst
|
||||
#!/bin/sh
|
||||
if [ -z "$${IPKG_INSTROOT}" ] && [ -x /etc/init.d/rpcd ]; then
|
||||
if [ -z "$${IPKG_INSTROOT}" ]; then
|
||||
/etc/init.d/rpcd restart
|
||||
fi
|
||||
exit 0
|
||||
@@ -55,7 +56,7 @@ endef
|
||||
|
||||
define Package/mwan3/postrm
|
||||
#!/bin/sh
|
||||
if [ -z "$${IPKG_INSTROOT}" ] && [ -x /etc/init.d/rpcd ]; then
|
||||
if [ -z "$${IPKG_INSTROOT}" ]; then
|
||||
/etc/init.d/rpcd restart
|
||||
fi
|
||||
exit 0
|
||||
@@ -91,9 +92,9 @@ define Package/mwan3/install
|
||||
$(INSTALL_DATA) ./files/lib/mwan3/mwan3.sh \
|
||||
$(1)/lib/mwan3/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/libexec/rpcd
|
||||
$(INSTALL_BIN) ./files/usr/libexec/rpcd/mwan3 \
|
||||
$(1)/usr/libexec/rpcd/
|
||||
$(INSTALL_DIR) $(1)/usr/share/rpcd/ucode/
|
||||
$(INSTALL_BIN) ./files/usr/share/rpcd/ucode/mwan3 \
|
||||
$(1)/usr/share/rpcd/ucode/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) ./files/usr/sbin/mwan3 \
|
||||
|
||||
@@ -1,235 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /lib/functions.sh
|
||||
. /lib/functions/network.sh
|
||||
. /usr/share/libubox/jshn.sh
|
||||
. /lib/mwan3/common.sh
|
||||
|
||||
report_connected_v4() {
|
||||
local address
|
||||
|
||||
if [ -n "$($IPT4 -S mwan3_connected_ipv4 2> /dev/null)" ]; then
|
||||
for address in $($IPS -o save list mwan3_connected_ipv4 | grep add | cut -d " " -f 3); do
|
||||
json_add_string "" "${address}"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
report_connected_v6() {
|
||||
[ $NO_IPV6 -ne 0 ] && return
|
||||
local address
|
||||
|
||||
if [ -n "$($IPT6 -S mwan3_connected_ipv6 2> /dev/null)" ]; then
|
||||
for address in $($IPS -o save list mwan3_connected_ipv6 | grep add | cut -d " " -f 3); do
|
||||
json_add_string "" "${address}"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
report_policies() {
|
||||
local ipt="$1"
|
||||
local policy="$2"
|
||||
|
||||
local percent total_weight weight iface
|
||||
|
||||
total_weight=$($ipt -S $policy | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | head -1 | awk '{print $3}')
|
||||
|
||||
for iface in $($ipt -S $policy | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '{print $1}'); do
|
||||
weight=$($ipt -S $policy | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}')
|
||||
percent=$(($weight*100/$total_weight))
|
||||
json_add_object
|
||||
json_add_string interface "$iface"
|
||||
json_add_int percent "$percent"
|
||||
json_close_object
|
||||
done
|
||||
}
|
||||
|
||||
report_policies_v4() {
|
||||
local policy
|
||||
|
||||
for policy in $($IPT4 -S | awk '{print $2}' | grep mwan3_policy_ | sort -u); do
|
||||
json_add_array "${policy##*mwan3_policy_}"
|
||||
report_policies "$IPT4" "$policy"
|
||||
json_close_array
|
||||
done
|
||||
}
|
||||
|
||||
report_policies_v6() {
|
||||
[ $NO_IPV6 -ne 0 ] && return
|
||||
local policy
|
||||
|
||||
for policy in $($IPT6 -S | awk '{print $2}' | grep mwan3_policy_ | sort -u); do
|
||||
json_add_array "${policy##*mwan3_policy_}"
|
||||
report_policies "$IPT6" "$policy"
|
||||
json_close_array
|
||||
done
|
||||
}
|
||||
|
||||
get_age() {
|
||||
local time_p time_u
|
||||
iface="$2"
|
||||
readfile time_p "$MWAN3TRACK_STATUS_DIR/${iface}/TIME"
|
||||
[ -z "${time_p}" ] || {
|
||||
get_uptime time_n
|
||||
export -n "$1=$((time_n-time_p))"
|
||||
}
|
||||
}
|
||||
|
||||
get_offline_time() {
|
||||
local time_n time_d iface
|
||||
iface="$2"
|
||||
readfile time_d "$MWAN3TRACK_STATUS_DIR/${iface}/OFFLINE"
|
||||
[ -z "${time_d}" ] || [ "${time_d}" = "0" ] || {
|
||||
get_uptime time_n
|
||||
export -n "$1=$((time_n-time_d))"
|
||||
}
|
||||
}
|
||||
|
||||
get_mwan3_status() {
|
||||
local iface="${1}"
|
||||
local iface_select="${2}"
|
||||
local running="0"
|
||||
local age=0
|
||||
local online=0
|
||||
local offline=0
|
||||
local enabled time_p time_n time_u time_d status track_status up uptime temp
|
||||
|
||||
if [ "${iface}" != "${iface_select}" ] && [ "${iface_select}" != "" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
mwan3_get_mwan3track_status track_status "$1"
|
||||
[ "$track_status" = "active" ] && running="1"
|
||||
get_age age "$iface"
|
||||
get_online_time online "$iface"
|
||||
get_offline_time offline "$iface"
|
||||
|
||||
config_get_bool enabled "$iface" enabled 0
|
||||
|
||||
if [ -f "$MWAN3TRACK_STATUS_DIR/${iface}/STATUS" ]; then
|
||||
network_get_uptime uptime "$iface"
|
||||
[ -n "$uptime" ] && up=1 || up=0
|
||||
readfile status "$MWAN3TRACK_STATUS_DIR/${iface}/STATUS"
|
||||
else
|
||||
uptime=0
|
||||
up=0
|
||||
status="unknown"
|
||||
fi
|
||||
|
||||
json_add_object "${iface}"
|
||||
json_add_int age "$age"
|
||||
json_add_int online "${online}"
|
||||
json_add_int offline "${offline}"
|
||||
json_add_int uptime "${uptime}"
|
||||
readfile temp "$MWAN3TRACK_STATUS_DIR/${iface}/SCORE"
|
||||
json_add_int "score" "$temp"
|
||||
readfile temp "$MWAN3TRACK_STATUS_DIR/${iface}/LOST"
|
||||
json_add_int "lost" "$temp"
|
||||
readfile temp "$MWAN3TRACK_STATUS_DIR/${iface}/TURN"
|
||||
json_add_int "turn" "$temp"
|
||||
json_add_string "status" "${status}"
|
||||
json_add_boolean "enabled" "${enabled}"
|
||||
json_add_boolean "running" "${running}"
|
||||
json_add_string "tracking" "${track_status}"
|
||||
json_add_boolean "up" "${up}"
|
||||
json_add_array "track_ip"
|
||||
for file in $MWAN3TRACK_STATUS_DIR/${iface}/TRACK_*; do
|
||||
[ -z "${file#*/TRACK_OUTPUT}" ] && continue
|
||||
[ -z "${file#*/TRACK_\*}" ] && continue
|
||||
track="${file#*/TRACK_}"
|
||||
json_add_object
|
||||
json_add_string ip "${track}"
|
||||
readfile temp "${file}"
|
||||
json_add_string status "$temp"
|
||||
readfile temp "$MWAN3TRACK_STATUS_DIR/${iface}/LATENCY_${track}"
|
||||
json_add_int latency "$temp"
|
||||
readfile temp "$MWAN3TRACK_STATUS_DIR/${iface}/LOSS_${track}"
|
||||
json_add_int packetloss "$temp"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_close_object
|
||||
}
|
||||
|
||||
main () {
|
||||
|
||||
case "$1" in
|
||||
list)
|
||||
json_init
|
||||
json_add_object "status"
|
||||
json_add_string "section" "x"
|
||||
json_add_string "interface" "x"
|
||||
json_add_string "policies" "x"
|
||||
json_close_object
|
||||
json_dump
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
status)
|
||||
local section iface
|
||||
read input;
|
||||
json_load "$input"
|
||||
json_get_var section section
|
||||
json_get_var iface interface
|
||||
|
||||
config_load mwan3
|
||||
json_init
|
||||
case "$section" in
|
||||
interfaces)
|
||||
json_add_object interfaces
|
||||
config_foreach get_mwan3_status interface "${iface}"
|
||||
json_close_object
|
||||
;;
|
||||
connected)
|
||||
json_add_object connected
|
||||
json_add_array ipv4
|
||||
report_connected_v4
|
||||
json_close_array
|
||||
json_add_array ipv6
|
||||
report_connected_v6
|
||||
json_close_array
|
||||
json_close_object
|
||||
;;
|
||||
policies)
|
||||
json_add_object policies
|
||||
json_add_object ipv4
|
||||
report_policies_v4
|
||||
json_close_object
|
||||
json_add_object ipv6
|
||||
report_policies_v6
|
||||
json_close_object
|
||||
json_close_object
|
||||
;;
|
||||
*)
|
||||
# interfaces
|
||||
json_add_object interfaces
|
||||
config_foreach get_mwan3_status interface
|
||||
json_close_object
|
||||
# connected
|
||||
json_add_object connected
|
||||
json_add_array ipv4
|
||||
report_connected_v4
|
||||
json_close_array
|
||||
json_add_array ipv6
|
||||
report_connected_v6
|
||||
json_close_array
|
||||
json_close_object
|
||||
# policies
|
||||
json_add_object policies
|
||||
json_add_object ipv4
|
||||
report_policies_v4
|
||||
json_close_object
|
||||
json_add_object ipv6
|
||||
report_policies_v6
|
||||
json_close_object
|
||||
json_close_object
|
||||
;;
|
||||
esac
|
||||
json_dump
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
202
net/mwan3/files/usr/share/rpcd/ucode/mwan3
Normal file
202
net/mwan3/files/usr/share/rpcd/ucode/mwan3
Normal file
@@ -0,0 +1,202 @@
|
||||
'use strict';
|
||||
|
||||
import { popen, readfile } from 'fs';
|
||||
import { cursor } from 'uci';
|
||||
|
||||
const ubus = require('ubus').connect();
|
||||
|
||||
function get_str_raw(iface, property) {
|
||||
return readfile(sprintf('/var/run/mwan3track/%s/%s', iface, property));
|
||||
}
|
||||
|
||||
function get_str(iface, property) {
|
||||
return rtrim(get_str_raw(iface, property), '\n');
|
||||
}
|
||||
|
||||
function get_int(iface, property) {
|
||||
return int(get_str(iface, property));
|
||||
}
|
||||
|
||||
function get_uptime() {
|
||||
return int(split(readfile('/proc/uptime'), '.', 2)[0]);
|
||||
}
|
||||
|
||||
function get_x_time(uptime, iface, property) {
|
||||
let t = get_int(iface, property);
|
||||
if (t > 0) {
|
||||
t = uptime - t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
function ucibool(val) {
|
||||
switch (val) {
|
||||
case 'yes':
|
||||
case 'on':
|
||||
case 'true':
|
||||
case 'enabled':
|
||||
return true;
|
||||
default:
|
||||
return !!int(val);
|
||||
}
|
||||
}
|
||||
|
||||
function get_mwan3track_status(iface, uci_track_ips, procd) {
|
||||
if (length(uci_track_ips) == 0) {
|
||||
return 'disabled';
|
||||
}
|
||||
if (procd?.[sprintf('track_%s', iface)]?.running) {
|
||||
const started = get_str(iface, 'STARTED');
|
||||
switch (started) {
|
||||
case '0':
|
||||
return 'paused';
|
||||
case '1':
|
||||
return 'active';
|
||||
default:
|
||||
return 'down';
|
||||
}
|
||||
}
|
||||
return 'down';
|
||||
}
|
||||
|
||||
const connected_check_cmd = {
|
||||
'4': 'iptables -t mangle -w -S mwan3_connected_ipv4',
|
||||
'6': 'ip6tables -t mangle -w -S mwan3_connected_ipv6',
|
||||
};
|
||||
const ipset_save_re = regexp('^add mwan3_connected_ipv[46] (.*)\n$');
|
||||
|
||||
function get_connected_ips(version) {
|
||||
const check = popen(connected_check_cmd[version], 'r');
|
||||
check.read('all');
|
||||
if (check.close() != 0) {
|
||||
return [];
|
||||
}
|
||||
const ipset = popen(sprintf('ipset -o save list mwan3_connected_ipv%s', version), 'r');
|
||||
const ips = [];
|
||||
for (let line = ipset.read('line'); length(line); line = ipset.read('line')) {
|
||||
const m = match(line, ipset_save_re);
|
||||
if (length(m) == 2) {
|
||||
push(ips, m[1]);
|
||||
}
|
||||
}
|
||||
ipset.close();
|
||||
return ips;
|
||||
}
|
||||
|
||||
const policies_cmd = {
|
||||
'4': 'iptables -t mangle -w -S',
|
||||
'6': 'ip6tables -t mangle -w -S'
|
||||
};
|
||||
const policies_re = regexp('^-A mwan3_policy_([^ ]+) .*?--comment "([^"]+)"');
|
||||
|
||||
function get_policies(version) {
|
||||
const ipt = popen(policies_cmd[version], 'r');
|
||||
const policies = {};
|
||||
for (let line = ipt.read('line'); length(line); line = ipt.read('line')) {
|
||||
const m = match(line, policies_re);
|
||||
if (m == null) {
|
||||
continue;
|
||||
}
|
||||
const policy = m[1];
|
||||
if (!exists(policies, policy)) {
|
||||
policies[policy] = [];
|
||||
}
|
||||
const intfw = split(m[2], ' ', 3);
|
||||
const weight = int(intfw[1]);
|
||||
const total = int(intfw[2]);
|
||||
if (weight >= 0 && total > 0) {
|
||||
push(policies[policy], {
|
||||
'interface': intfw[0],
|
||||
'percent': weight / total * 100,
|
||||
})
|
||||
}
|
||||
}
|
||||
ipt.close();
|
||||
return policies;
|
||||
}
|
||||
|
||||
function interfaces_status(request) {
|
||||
const uci = cursor();
|
||||
const procd = ubus.call('service', 'list', { 'name': 'mwan3' })?.mwan3?.instances;
|
||||
const interfaces = {};
|
||||
uci.foreach('mwan3', 'interface', intf => {
|
||||
const ifname = intf['.name'];
|
||||
if (request.args.interface != null && request.args.interface != ifname) {
|
||||
return;
|
||||
}
|
||||
const netstatus = ubus.call(sprintf('network.interface.%s', ifname), 'status', {});
|
||||
const uptime = get_uptime();
|
||||
const uci_track_ips = intf['track_ip'];
|
||||
const track_status = get_mwan3track_status(ifname, uci_track_ips, procd);
|
||||
const track_ips = [];
|
||||
for (let ip in uci_track_ips) {
|
||||
push(track_ips, {
|
||||
'ip': ip,
|
||||
'status': get_str(ifname, sprintf('TRACK_%s', ip)) || 'unknown',
|
||||
'latency': get_int(ifname, sprintf('LATENCY_%s', ip)),
|
||||
'packetloss': get_int(ifname, sprintf('LOSS_%s', ip)),
|
||||
});
|
||||
}
|
||||
interfaces[ifname] = {
|
||||
'age': get_x_time(uptime, ifname, 'TIME'),
|
||||
'online': get_x_time(uptime, ifname, 'ONLINE'),
|
||||
'offline': get_x_time(uptime, ifname, 'OFFLINE'),
|
||||
'uptime': netstatus.uptime || 0,
|
||||
'score': get_int(ifname, 'SCORE'),
|
||||
'lost': get_int(ifname, 'LOST'),
|
||||
'turn': get_int(ifname, 'TURN'),
|
||||
'status': get_str(ifname, 'STATUS') || 'unknown',
|
||||
'enabled': ucibool(intf['enabled']),
|
||||
'running': track_status == 'active',
|
||||
'tracking': track_status,
|
||||
'up': netstatus.up,
|
||||
'track_ip': track_ips,
|
||||
};
|
||||
});
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
const methods = {
|
||||
status: {
|
||||
args: {
|
||||
section: 'section',
|
||||
interface: 'interface'
|
||||
},
|
||||
call: function (request) {
|
||||
switch (request.args.section) {
|
||||
case 'connected':
|
||||
return {
|
||||
'connected': {
|
||||
'ipv4': get_connected_ips('4'),
|
||||
'ipv6': get_connected_ips('6'),
|
||||
},
|
||||
};
|
||||
case 'policies':
|
||||
return {
|
||||
'policies': {
|
||||
'ipv4': get_policies('4'),
|
||||
'ipv6': get_policies('6'),
|
||||
},
|
||||
};
|
||||
case 'interfaces':
|
||||
return {
|
||||
'interfaces': interfaces_status(request),
|
||||
};
|
||||
default:
|
||||
return {
|
||||
'interfaces': interfaces_status(request),
|
||||
'connected': {
|
||||
'ipv4': get_connected_ips('4'),
|
||||
'ipv6': get_connected_ips('6'),
|
||||
},
|
||||
'policies': {
|
||||
'ipv4': get_policies('4'),
|
||||
'ipv6': get_policies('6'),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return { 'mwan3': methods };
|
||||
Reference in New Issue
Block a user