3

Running a Dell 5285 with WD15 Dock. Periodically, the eth0 stops transferring data (and the wireless doesn't automatically start transferring). In either dmesg or kern.log

"r8152 2-4.2:1.0 enx106530b73c5e: Tx status -71"

appears (r8152 is the module used for the Realtek Semiconductor Corp. RTL8153 Gigabit Ethernet Adapter -- enx106530b73c5e is what the eth0 connection is renamed to).

The following will reset the ethernet connection:

#!/bin/bash
#reset Ethernet device by ID
set -euo pipefail
IFS=$'\n\t'

VENDOR="0bda"
PRODUCT="8153"

for DIR in $(find /sys/bus/usb/devices/ -maxdepth 1 -type l); do
  if [[ -f $DIR/idVendor && -f $DIR/idProduct &&
        $(cat $DIR/idVendor) == $VENDOR && $(cat $DIR/idProduct) == $PRODUCT ]]; then
    echo 0 > $DIR/authorized
    sleep 3
    echo 1 > $DIR/authorized
  fi
done

How can I automatically check (at least once per minute) the dmesg or kern.log for that entry, and run the script if it exists?

I'm running KXStudio on Kubuntu 19.04, lowlatency kernel (same problems on generic).

3 Answers3

4

/sys usage

Note that a much easier way to find devices in /sys is to ask udev:

for DIR in $(udevadm trigger -v -n -s usb -a idVendor=0bda -a idProduct=8153)

for DIR in $(udevadm trigger -v -n -s usb -p ID_VENDOR_ID=0bda -p ID_MODEL_ID=8153)

Periodic actions

To do periodic actions, one normally uses cron. If you want to grep dmesg for your message once a minute, then just add a cron job that runs once a minute and greps dmesg for your message.

* * * * * if dmesg | tail -100 | grep -qs "r8152.*Tx status -71"; then /etc/kick-realtek.sh; fi

(The five asterisks are part of the crontab format and indicate the schedule time & date.)

One problem with that simple approach is it'll react to all such messages, even old ones logged before the last reset. You could avoid this by writing a marker line to dmesg (or even using an existing kernel message like "USB device detected" as the marker):

#!/usr/bin/env bash

if dmesg | tail -100 | awk '/r8152.*Tx status -71/ {x=1} /KICKED/ {x=0} END {exit(!x)}'; then
    /etc/kick-realtek.sh;
    echo "KICKED" > /dev/kmsg;
fi

Alternatively you could read and remember the last timestamp of such an error message, but that's much too complex in comparison.

Live monitoring

An even better option would be to use a program that continuously receives the log messages instead of having to do periodic checks. For example:

dmesg --follow | ...

journalctl --dmesg --lines=10000 --follow | ...

tail -n 10000 -f /var/log/kern.log | ...

Regardless of which one is used, pipe its output into a loop that checks each incoming line. Run the resulting script in background, ideally you could even turn it into a system service (/etc/systemd/system/*.service):

#!/usr/bin/env bash

... | while read -r line; do
    if [[ $line == *r8152*Tx\ status\ -71* ]]; then
        /etc/kick-realtek.sh
    fi
done

(You could use if echo "$line" | grep -qs ...; then or similar, it doesn't matter.)

Finally, many server systems already have a program that continuously receives all log messages, such as rsyslog or syslog-ng. (These programs are how dmesg gets copied to /var/log in the first place.) They can often filter the log messages and run programs:

grawity
  • 501,077
0

Sorry for not following up sooner. I realized that running a script to reset the ethernet connection wouldn't suffice. The ethernet device would, it appears, sometimes, be renumbered. And, occasionally, the system would show more than one dock.

Better, I think, to replace the dock at some point. Possibly with a Plugable USB-C Triple Display Docking Station. Though I might still have the same problem: https://plugable.com/2016/06/30/investigating-usb-c-problems-on-some-dell-xps-and-precision-laptops/

0

It's been a while... :) Hopefully your issue has received a proper fix by now. For anyone running into this question later, here's an idea for live monitoring!

Add the following to /etc/crontab or using crontab -e

*/1 * * * * /usr/bin/timeout 1m bash -c "dmesg -w | tail -f | grep -qsm 1 'r8152.*Tx status -71' && /root/yourscript.sh"

How this works?

Crontab runs the command every minute.

timeout 1m stops the process after running for 1 minute

bash -c executes the query contained within "", allowing us to use the pipe character in combination with timeout

dmesg -w prints dmesg history and follows live output

tail -f follows live input (skipping history)

grep matches only what we're interested in, returning success or failure depending on whether it was matched or not

grep -qsm 1 returns immediately after a single result was matched while not printing anything to console, preventing crontab from sending notification emails

Miscellaneous:
-s, --no-messages         suppress error messages
Output control:
-m, --max-count=NUM       stop after NUM matches
-q, --quiet, --silent     suppress all normal output

&& executes the following only if the previous command returned successfully

/root/yourscript.sh path to the script that should run on a match

Inny
  • 114