Skip to content

Instantly share code, notes, and snippets.

@stonerl
Created December 27, 2020 20:12
Show Gist options
  • Save stonerl/9b4213e4b0ca089cd9d78db90bc73073 to your computer and use it in GitHub Desktop.
Save stonerl/9b4213e4b0ca089cd9d78db90bc73073 to your computer and use it in GitHub Desktop.
set of scripts to collect Lantiq DSL line values via collectd-mod-exec
What:
This set of scripts collects DSL line values via a cronjob, brings them into collectd PUTVAL format in a temporary file,
and has collectd insert the data via a minimal script run by collectd-exec. It also includes an exec.lua file to create
output graphs.
The separation of value collecting and value entering is necessary because collectd-exec profoundly refuses to run scripts
as root. However, in order to collect DSL line values from the modem, root rights are absolutely necessary (the necessary
six-line stanza needs to kill a process and lock/access/unlock a pipe that is only accessible to root.)
How:
- Install collectd-mod-exec
- Place the files below in their respective location:
/usr/sbin/collectd-get-lantiqdsl-values
/usr/bin/stat-lantiqdsl
/usr/lib/lua/luci/statistics/rrdtool/definitions/exec.lua
- make the data collection script executable:
# chmod +x /usr/sbin/collectd-get-lantiqdsl-values
- have the data collection script run via cronjob every minute:
* * * * * /usr/sbin/collectd-get-lantiqdsl-values
- configure collectd-mod-exec to run the data entry script:
in LuCI: Statistics > Setup > General plugins > Exec
- Enable this plugin [x]
- Add a command:
Script: /usr/bin/stat-lantiqdsl
User: nobody
Group: nogroup
- (maybe) update LuCI's module cache:
# rm /tmp/luci-modulecache/* /tmp/luci-indexcache
Notes:
- The "line errors" and "line errored seconds" graphs are scaled by 86400 to bring them up to "per day" from the default
"per second" scale of the collectd DERIVE data type. Since values are displayed on a timeline, naturally they have to be
scaled "per some sort of timeframe", but "per second" only leads to decimal places which are practically useless to judge
anything. Scaled to "per day" the numbers show how high they would be if the current value would last througout the whole
day, and deliver a meaningful average.
- In the data collection shell script, the variable for collecting line values is named "$csg". This is because I
originally copied a line of code from dsl_lantiq.sh years ago (where it collected the g997 CSG value) and I never bothered
to rename the variable. ;)
#!/bin/sh
[ -f /lib/functions/lantiq_dsl.sh ] && . /lib/functions/lantiq_dsl.sh || exit 0
HOSTNAME=$(cat /proc/sys/kernel/hostname)
VALUESFILE=/tmp/collectd-lantiqdsl-values
dsl_val() {
echo $(expr "$1" : '.*'$2'=\([-\.[:alnum:]]*\).*')
}
output_statistics() {
local csg
# get line state
csg=$(dsl_cmd lsg)
local linestate_code=$(dsl_val "$csg" nLineState);
# create/clear and chown values file
> ${VALUESFILE}
# only get line values if line is up
if [ "$linestate_code" == "0x801" ]; then
local uptime=0
local datarate_down=0
local dataratemax_down=0
local snr_down=0
local datarate_up=0
local dataratemax_up=0
local snr_up=0
local errors_near_fecs=0
local errors_near_es=0
local errors_near_ses=0
local errors_near_hec=0
local errors_near_crc=0
local errors_near_crcp=0
local errors_far_fecs=0
local errors_far_es=0
local errors_far_ses=0
local errors_far_hec=0
local errors_far_crc=0
local errors_far_crcp=0
csg=$(dsl_cmd g997csg 0 1)
datarate_down=$(dsl_val "$csg" ActualDataRate)
csg=$(dsl_cmd g997lsg 1 1)
snr_down=$(dsl_val "$csg" SNR)
dataratemax_down=$(dsl_val "$csg" ATTNDR)
csg=$(dsl_cmd g997csg 0 0)
datarate_up=$(dsl_val "$csg" ActualDataRate)
csg=$(dsl_cmd g997lsg 0 1)
snr_up=$(dsl_val "$csg" LATN)
dataratemax_up=$(dsl_val "$csg" ATTNDR)
csg=$(dsl_cmd pmccsg 0 0 0)
uptime=$(dsl_val "$csg" nElapsedTime)
csg=$(dsl_cmd pmlsctg 0)
errors_near_fecs=$(dsl_val "$csg" nFECS)
errors_near_es=$(dsl_val "$csg" nES)
errors_near_ses=$(dsl_val "$csg" nSES)
csg=$(dsl_cmd pmdpctg 0 0)
errors_near_hec=$(dsl_val "$csg" nHEC)
errors_near_crc=$(dsl_val "$csg" nCRC_P)
errors_near_crcp=$(dsl_val "$csg" nCRCP_P)
csg=$(dsl_cmd pmlsctg 1)
errors_far_fecs=$(dsl_val "$csg" nFECS)
errors_far_es=$(dsl_val "$csg" nES)
errors_far_ses=$(dsl_val "$csg" nSES)
csg=$(dsl_cmd pmdpctg 0 1)
errors_far_hec=$(dsl_val "$csg" nHEC)
errors_far_crc=$(dsl_val "$csg" nCRC_P)
errors_far_crcp=$(dsl_val "$csg" nCRCP_P)
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/uptime\" N:$uptime" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/bitrate-downstream\" N:$datarate_down" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/bitrate-downstream_max\" N:$dataratemax_down" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/snr-downstream\" N:$snr_down" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/bitrate-upstream\" N:$datarate_up" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/bitrate-upstream_max\" N:$dataratemax_up" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/snr-upstream\" N:$snr_up" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-near_fecs\" N:$errors_near_fecs" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-near_es\" N:$errors_near_es" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-near_ses\" N:$errors_near_ses" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-near_hec\" N:$errors_near_hec" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-near_crc\" N:$errors_near_crc" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-near_crcp\" N:$errors_near_crcp" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-far_fecs\" N:$errors_far_fecs" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-far_es\" N:$errors_far_es" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-far_ses\" N:$errors_far_ses" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-far_hec\" N:$errors_far_hec" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-far_crc\" N:$errors_far_crc" >> ${VALUESFILE}
echo "PUTVAL \"$HOSTNAME/exec-lantiqdsl/errors-far_crcp\" N:$errors_far_crcp" >> ${VALUESFILE}
fi
}
output_statistics
#!/bin/sh
INTERVAL=30
while true; do
[ -f /tmp/collectd-lantiqdsl-values ] && cat /tmp/collectd-lantiqdsl-values
sleep $INTERVAL
done
module("luci.statistics.rrdtool.definitions.exec", package.seeall)
function item()
return luci.i18n.translate("DSL")
end
function rrdargs(graph, plugin, plugin_instance)
local uptime = {
title = "%H: DSL Line Uptime",
vlabel = "days",
y_min = 0,
data = {
types = { "uptime" },
options = {
uptime = {
title = "Uptime",
transform_rpn = "86400,/",
color = "009900"
}
}
}
}
local snr = {
title = "%H: DSL Line SNR",
vlabel = "dB",
y_min = 0,
data = {
instances = {
snr = {
"downstream",
"upstream"
}
},
options = {
snr_downstream = {
transform_rpn = "10,/",
title = "Downstream",
color = "009900",
noarea = true,
overlay = true
},
snr_upstream = {
transform_rpn = "10,/",
title = "Upstream",
color = "000099",
noarea = true,
overlay = true
}
}
}
}
local bitrate = {
title = "%H: DSL Line Datarates",
vlabel = "MBit/s",
y_min = 0,
data = {
instances = {
bitrate = {
"downstream",
"downstream_max",
"upstream",
"upstream_max"
}
},
options = {
bitrate_downstream = {
transform_rpn = "1000000,/",
title = "Downstream",
color = "009900",
overlay = true,
noarea = true
},
bitrate_downstream_max = {
transform_rpn = "1000000,/",
title = "Downstream (max.)",
color = "aaddaa",
overlay = true,
noarea = true
},
bitrate_upstream = {
transform_rpn = "1000000,/",
title = "Upstream",
color = "000099",
overlay = true,
noarea = true
},
bitrate_upstream_max = {
transform_rpn = "1000000,/",
title = "Upstream (max.)",
color = "aaaadd",
overlay = true,
noarea = true
}
}
}
}
local errors = {
title = "%H: DSL Line Errors",
vlabel = "errors (per day)",
y_min = 0,
data = {
instances = {
errors = {
"far_hec",
"far_crc",
"far_crcp",
"near_hec",
"near_crc",
"near_crcp"
}
},
options = {
errors_far_hec = {
title = "HEC (far)",
transform_rpn = "86400,*",
color = "990000"
},
errors_far_crc = {
title = "CRC (far)",
transform_rpn = "86400,*",
color = "660000"
},
errors_far_crcp = {
title = "CRC_P (far)",
transform_rpn = "86400,*",
color = "330000"
},
errors_near_hec = {
flip = true,
title = "HEC (near)",
transform_rpn = "86400,*",
color = "990000"
},
errors_near_crc = {
flip = true,
title = "CRC (near)",
transform_rpn = "86400,*",
color = "660000"
},
errors_near_crcp = {
flip = true,
title = "CRC_P (near)",
transform_rpn = "86400,*",
color = "330000"
}
}
}
}
local errorsecs = {
title = "%H: DSL Line Errored Seconds",
vlabel = "errored secs (per day)",
y_min = 0,
data = {
instances = {
errors = {
"far_fecs",
"far_es",
"far_ses",
"near_fecs",
"near_es",
"near_ses"
}
},
options = {
errors_far_fecs = {
title = "FECS: Forward Error Corrected Seconds (far)",
transform_rpn = "86400,*",
color = "ddaaaa",
overlay = true,
noarea = true
},
errors_far_es = {
title = "ES: Errored Seconds (far)",
transform_rpn = "86400,*",
color = "990000"
},
errors_far_ses = {
title = "SES: Severely Errored Seconds (far)",
transform_rpn = "86400,*",
color = "ff0000"
},
errors_near_fecs = {
flip = true,
title = "FECS: Forward Error Corrected Seconds (near)",
transform_rpn = "86400,*",
color = "ddaaaa",
overlay = true,
noarea = true
},
errors_near_es = {
flip = true,
title = "ES: Errored Seconds (near)",
transform_rpn = "86400,*",
color = "990000"
},
errors_near_ses = {
flip = true,
title = "SES: Severely Errored Seconds (near)",
transform_rpn = "86400,*",
color = "ff0000"
}
}
}
}
return { uptime, snr, bitrate, errors, errorsecs }
end
-- to update:
-- rm /tmp/luci-modulecache/* /tmp/luci-indexcache
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment