#!/bin/sh . /usr/share/libubox/jshn.sh HOSTNAME="${COLLECTD_HOSTNAME:-localhost}" INTERVAL="${COLLECTD_INTERVAL:-60}" handle_cake() { local ifc ifr tin i ifc="$1" ifr="${ifc//[!0-9A-Za-z]/_}" # Overall json_get_vars bytes packets drops backlog qlen # Options json_select options json_get_vars bandwidth diffserv json_select ".." echo "PUTVAL \"$HOSTNAME/sqm-$ifc/qdisc_bytes\" interval=$INTERVAL N:$bytes" echo "PUTVAL \"$HOSTNAME/sqm-$ifc/qdisc_drops\" interval=$INTERVAL N:$drops" echo "PUTVAL \"$HOSTNAME/sqm-$ifc/qdisc_backlog\" interval=$INTERVAL N:$backlog" # ash doesn't have arrays so prepare to get a little creative case "$diffserv" in diffserv3 | diffserv4) tns="BKBEVIVO" ;; *) tns="T0T1T2T3T4T5T6T7" ;; esac # Tins # Flows & delays indicate the state as of the last packet that flowed through, so they appear to get stuck. # Discard the results from a stuck tin. json_get_keys tins tins json_select tins i=0 for tin in $tins; do json_select "$tin" json_get_vars threshold_rate sent_bytes sent_packets backlog_bytes target_us peak_delay_us avg_delay_us base_delay_us drops ecn_mark ack_drops sparse_flows bulk_flows unresponsive_flows eval osp="\$osp${ifr}t${i}" if [ "$osp" ] && [ "$osp" -eq "$sent_packets" ] ; then peak_delay_us=0; avg_delay_us=0; base_delay_us=0 sparse_flows=0; bulk_flows=0; unresponsive_flows=0 else eval "osp${ifr}t${i}=$sent_packets" fi tn=${tns:$((i<<1)):2} echo "PUTVAL \"$HOSTNAME/sqmcake-$ifc/qdisct_bytes-$tn\" interval=$INTERVAL N:$sent_bytes" echo "PUTVAL \"$HOSTNAME/sqmcake-$ifc/qdisct_thres-$tn\" interval=$INTERVAL N:$threshold_rate" echo "PUTVAL \"$HOSTNAME/sqmcake-$ifc/qdisct_drops-$tn\" interval=$INTERVAL N:$drops:$ecn_mark:$ack_drops" echo "PUTVAL \"$HOSTNAME/sqmcake-$ifc/qdisct_backlog-$tn\" interval=$INTERVAL N:$backlog_bytes" echo "PUTVAL \"$HOSTNAME/sqmcake-$ifc/qdisct_flows-$tn\" interval=$INTERVAL N:$sparse_flows:$bulk_flows:$unresponsive_flows" echo "PUTVAL \"$HOSTNAME/sqmcake-$ifc/qdisct_latencyus-$tn\" interval=$INTERVAL N:$target_us:$peak_delay_us:$avg_delay_us:$base_delay_us" json_select .. i=$((i+1)) done json_select .. } handle_mq() { ifc="$1" # Overall json_get_vars bytes drops backlog echo "PUTVAL \"$HOSTNAME/sqm-$ifc/qdisc_bytes\" interval=$INTERVAL N:$bytes" echo "PUTVAL \"$HOSTNAME/sqm-$ifc/qdisc_drops\" interval=$INTERVAL N:$drops" echo "PUTVAL \"$HOSTNAME/sqm-$ifc/qdisc_backlog\" interval=$INTERVAL N:$backlog" } process_qdisc() { local ifc jsn ifc="$1" jsn=$(tc -s -j qdisc show dev "$ifc") || return # strip leading & trailing [] jsn="${jsn#[}" ; jsn="${jsn%]}" json_load "${jsn}" json_get_var qdisc kind case "$qdisc" in cake) handle_cake "$ifc" ;; mq) handle_mq "$ifc" ;; *) echo "Unknown qdisc type '$qdisc' on interface '$ifc'" 1>&2 ;; esac json_cleanup } # while not orphaned while [ $(awk '$1 ~ "^PPid:" {print $2;exit}' /proc/$$/status) -ne 1 ] ; do for ifc in "$@" ; do process_qdisc "$ifc" done sleep "${INTERVAL%%.*}" done