共计 3854 个字符,预计需要花费 10 分钟才能阅读完成。
前言
近期升级了全屋网络:
- 入户宽带:联通政企,1000Mbps下行,250Mbps上行
- 软路由 AC:6口2.5G工控机,6305 CPU,4G内存,iStoresOS 系统
- 无线路由 AP:中兴晴天be5100Pro+ *2,中兴巡天be3600Pro青云 *1
然而基于openwrt下的流量或带宽监控软件的效果不如人意,我期望的是能够查询家中每个设备的历史带宽数据。
之前的站内文章介绍过:node_exporter 添加自定义指标,使用 node_exporter 实现路由器监控
现在只需一个小脚本制作导出器,将指标交由 node_exporter 采集,再绘制Grafana面板即可。
配置
准备工作:
# 安装nlbw
opkg update
opkg install nlbwmon
/etc/init.d/nlbwmon enable
/etc/init.d/nlbwmon start
编写脚本:脚本中较复杂的逻辑是为了获取hostname,ip和mac不能很好的识别到究竟是什么设备。
root@iStoreOS:~# cat /usr/sbin/network_stats.sh
#!/bin/sh
# 输出目录
TEXTFILE_DIR="/tmp/node_exporter"
mkdir -p $TEXTFILE_DIR
# 创建IP到主机名的映射
create_hostname_map() {
local map_file="/tmp/ip_hostname_map"
> "$map_file"
# 1. 从DHCP租约获取
while IFS=' ' read -r timestamp mac ip hostname clientid; do
[ -z "$timestamp" ] && continue
# 处理无效主机名
case "$hostname" in
""|"*"|"0.db")
echo "$ip:none" >> "$map_file"
;;
*)
echo "$ip:$hostname" >> "$map_file"
;;
esac
done < /tmp/dhcp.leases 2>/dev/null
# 2. 从UCI静态DHCP配置获取
for section in $(uci show dhcp 2>/dev/null | grep "=host" | cut -d. -f2 | cut -d= -f1); do
local name=$(uci get dhcp.$section.name 2>/dev/null)
local ip=$(uci get dhcp.$section.ip 2>/dev/null)
if [ -n "$name" ] && [ -n "$ip" ] && [ "$name" != "*" ]; then
echo "$ip:$name" >> "$map_file"
fi
done
# 去重,保留第一个找到的主机名
sort -u "$map_file" -o "$map_file"
}
# 根据IP获取主机名
get_hostname() {
local ip="$1"
local map_file="/tmp/ip_hostname_map"
if [ ! -f "$map_file" ]; then
create_hostname_map
fi
local hostname=$(grep "^$ip:" "$map_file" | cut -d: -f2 | head -1)
echo "${hostname:-none}"
}
# 清理主机名字符串
clean_hostname() {
local hostname="$1"
echo "$hostname" | sed 's/[^a-zA-Z0-9._-]/_/g'
}
# 获取接口总流量作为补充
get_interface_stats() {
local interface="br-lan"
if [ -f /proc/net/dev ]; then
awk -v iface="$interface:" '
$1 == iface {
rx_bytes = $2
tx_bytes = $10
print rx_bytes ":" tx_bytes
exit
}' /proc/net/dev
else
echo "0:0"
fi
}
# 重新创建主机名映射
create_hostname_map
# 生成Prometheus指标
{
echo "# HELP openwrt_device_rx_bytes Device received bytes"
echo "# TYPE openwrt_device_rx_bytes counter"
echo "# HELP openwrt_device_tx_bytes Device transmitted bytes"
echo "# TYPE openwrt_device_tx_bytes counter"
# 使用nlbw获取设备流量统计,只处理192.168.2.*的IP
nlbw -c csv -g ip | tail -n +2 | while IFS=$'\t' read -r ip conns rx_bytes rx_pkts tx_bytes tx_pkts; do
# 去除引号
ip=$(echo "$ip" | sed 's/"//g')
rx_bytes=$(echo "$rx_bytes" | sed 's/"//g')
tx_bytes=$(echo "$tx_bytes" | sed 's/"//g')
# 只处理192.168.2.*的IP
case "$ip" in
192.168.2.*)
# 从ARP表获取MAC地址
mac=$(awk -v target_ip="$ip" '$1 == target_ip && $4 != "00:00:00:00:00:00" {print $4; exit}' /proc/net/arp)
[ -z "$mac" ] && mac="unknown"
raw_hostname=$(get_hostname "$ip")
hostname=$(clean_hostname "$raw_hostname")
echo "openwrt_device_rx_bytes{ip=\"$ip\",hostname=\"$hostname\",mac=\"$mac\"} $rx_bytes"
echo "openwrt_device_tx_bytes{ip=\"$ip\",hostname=\"$hostname\",mac=\"$mac\"} $tx_bytes"
;;
esac
done
# 添加接口总流量作为参考
interface_stats=$(get_interface_stats)
interface_rx=$(echo "$interface_stats" | cut -d: -f1)
interface_tx=$(echo "$interface_stats" | cut -d: -f2)
echo "# HELP openwrt_interface_rx_bytes Interface received bytes"
echo "# TYPE openwrt_interface_rx_bytes counter"
echo "# HELP openwrt_interface_tx_bytes Interface transmitted bytes"
echo "# TYPE openwrt_interface_tx_bytes counter"
echo "openwrt_interface_rx_bytes{interface=\"br-lan\"} $interface_rx"
echo "openwrt_interface_tx_bytes{interface=\"br-lan\"} $interface_tx"
} > $TEXTFILE_DIR/network_stats.prom
配置计划任务:
* * * * * /bin/bash /usr/sbin/network_stats.sh 2>&1 >/dev/null
修改node_exporter的启动参数,定义获取自定义指标的路径:
root@iStoreOS:~# cat /etc/init.d/node_exporter
#!/bin/sh /etc/rc.common
START=99
STOP=10
USE_PROCD=1
start_service() {
procd_open_instance
procd_set_param command "/usr/sbin/node_exporter" \
"--collector.textfile.directory=/tmp/node_exporter"
procd_set_param respawn
procd_close_instance
}
stop_service() {
procd_send_signal TERM node_exporter
}
restart_service() {
stop_service "$@"
start_service "$@"
}
重启node_exporter
/etc/init.d/node_exporter restart
绘制Grafana面板:

Promql如下:
# 入带宽
sum by (hostname, ip, mac) (rate(openwrt_device_rx_bytes[1m]))
# 出带宽
sum by (hostname, ip, mac) (rate(openwrt_device_tx_bytes[1m]))
本文介绍了在iStoresOS或OpenWRT系统上实现带宽监控的方法。文章中详细描述了如何通过安装nlbwmon工具和编写定制脚本来采集各设备的网络流量数据,然后利用node_exporter将这些指标导出,最后通过Grafana生成监控面板,实现对家中每个设备历史带宽数据的监控。
引用链接
正文完