Эта статья является дополнением моей предыдущий публикации о настройке домашнего роутера / файл-сервера. Здесь речь пойдет о проблеме автоматического переподключения к интернету при зависании 4G USB модема. На оригинальность идеи не претендую, просто хочу поделиться с читателями своим решением.
В процессе постоянной работы, примерно раз в месяц, случалось так, что USB модем зависал. Это доставляло мне определенные неудобства: невозможность удаленно попасть на домашний компьютер, заранее поставить на закачку фильмы. Удаленно эту проблему устранить было невозможно, помогала только перезагрузка модема по питанию. Выход был единственным написать сценарий, который в определенное время проверяет доступность узла в интернете и при необходимости перезагружает модем.
В интернете я нашел несколько реализаций, но не одна из них у меня нормально не заработала. Поэтому я решил написать свой сторожевой таймер с преферансом и барышнями. За основу был взят скрипт из этой темы. Переписан, насколько мне позволяет моя квалификация, и дополнен новыми возможностями такими как внешние опции.
yum install usb_modeswitch usb_modeswitch-data
Подключить модем и посмотреть как он определяется в системе.
dmesg
ip a
Далее необходимо настроить интерфейс 4G модема.
vim /etc/sysconfig/network-scripts/ifcfg-wwp6s0u1i1
DEVICE="wwp6s0u1i1"
NAME="wwp6s0u1i1"
TYPE="Ethernet"
ONBOOT="yes"
BOOTPROTO="dhcp"
HWADDR="XX:XX:XX:XX:XX:XX"
NM_CONTROLLED="no"
DNS1=127.0.0.1
DNS2=127.0.0.1
DNS3=127.0.0.1
NOZEROCONF="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="no"
ZONE="external"
Создаем скрипты для активации и де активации интернета при включении или отключении интерфейса.
vim /sbin/ifup-pre-local
#!/bin/bash
#
PREUP="/etc/sysconfig/network-scripts/pre-up-${1:6}"
if [ -x $PREUP ]; then
exec $PREUP
fi
vim /sbin/ifdown-pre-local
#!/bin/bash
#
PREDOWN="/etc/sysconfig/network-scripts/pre-down-$1"
if [ -x $PREDOWN ]; then
exec $PREDOWN
fi
vim /etc/sysconfig/network-scripts/pre-up-wwp6s0u1i1
#!/bin/bash
#
echo -en 'AT^NDISDUP=1,1,"internet.yota"rn' > /dev/ttyUSB0
vim /etc/sysconfig/network-scripts/pre-down-wwp6s0u1i1
#!/bin/bash
#
echo -en 'AT^NDISDUP=1,0,"internet.yota"rn' > /dev/ttyUSB0
Здесь ttyUSB0 это порт модема.
Поднимаем интерфейс и проверяем соединение.
ifup wwp6s0u1i1
ip a
#!/bin/bash
SN="$(basename "$0")"
function print_help() {
printf "n"
printf "Использование: %s options...n" "$SN"
printf "Параметры:n"
printf " -s Проверяемый ресурс.n"
printf " -i Имя сетевого интерфейса.n"
printf " -d Шина и порт модема lsusb -t.n"
printf " -n Число ошибочных пингов.n"
printf " -m Маркер модема, из команды lsusb.n"
printf " -h Справка.n"
printf "n"
}
# Если скрипт запущен без аргументов, открываем справку.
if [[ $# = 0 ]]; then
print_help && exit 1
fi
while getopts ":s:i:d:n:m:h" opt ;
do
case $opt in
s) SITE=$OPTARG;
;;
i) IF=$OPTARG;
;;
d) DEV=$OPTARG;
;;
n) EP=$OPTARG;
;;
m) MM=$OPTARG;
;;
h) print_help
exit 1
;;
*) printf "Неправильный параметрn";
printf "Для вызова справки запустите %s -hn" "$SN";
exit 1
;;
esac
done
if [[ "$SITE" == "" ]] || [[ "$IF" == "" ]] || [[ "$DEV" == "" ]] || [[ "$EP" == "" ]] || [[ "$MM" == "" ]] ; then
printf "n"
printf "Одна или несколько опций не указаны.n"
printf "Для справки наберите: %s -hn" "$SN"
printf "n"
exit 1
fi
M="$(lsusb | grep -w "$MM")" #строка модема из lsusb
if [[ "$M" != "" ]]; then #если модем выбран, можно проверять пинги
if grep -w -q "$IF" /proc/net/dev; then #проверяем наличие сетевого интерфейса
printf "n"
printf "Проверка доступности %s через интерфейс %sn" "$SITE" "$IF"
printf "n"
if [[ "$EP" -ge 6 ]]; then
printf "Число ошибочных пингов должно быть меньше или равно 5n"
exit 1
else
printf "Делаем пинги...n"
flag="0"
for i in {1..5}; do #делаем 5 пингов до сервера
timeout -k 2 -s TERM 16 ping -w 14 -s 8 -c 1 -I "$IF" "$SITE" || flag=$((flag+1)) && printf "пинг:%s/5 (ошибок:%s)n" "$i" "$flag" #пинг не прошел - инкрементируем счетчик
if (("$flag" >= "$EP")); then
break
else
read -r -t 1 > /dev/null
fi
done
printf "потерь пакетов: %s из %sn" "$flag" "$i"
printf "n"
if (("$flag" >= "$EP")); then #если потерь пакетов больше 2х
M="$(lsusb | grep "$MM")" #на всякий случай снова глянем - вдруг модем выдернули
printf "Будет сброшен модем:n"
printf "%sn" "$M" | cut -c 34-
if ! [[ -d /sys/bus/usb/drivers/usb/"$DEV" ]]; then
printf "Неверно указаны Bus и Port модема.n"
exit 1
else
ifdown "$IF" #деактивируем интерфейс
printf "%s" "$DEV" > "/sys/bus/usb/drivers/usb/unbind" && printf "%s" "$DEV" > "/sys/bus/usb/drivers/usb/bind" #перезегрузка модема
# read -r -t 1 > /dev/null
ifup "$IF" #активируем интерфейс
fi
fi
fi
else
printf "n"
printf "Интерфейс %s не существуетn" "$IF"
printf "n"
exit 1
fi
else
printf "Модем %s не найден.n" "$MM"
fi
Скрипт располагается в /usr/local/bin/.
Чтобы скрипт запускался автоматически, раз в пять минут, добавим задание в cron.
crontab -e
*/5 * * * * /usr/local/bin/watchdog -m Huawei -s ya.ru -i wwp6s0u2i1 -n 3 -d 1-1 > /dev/null 2>&1
Это вывод dmesg, на нем виден сброс модема при выполнении скрипта.
[181709.595498] option1 ttyUSB0: GSM modem (1-port) converter now disconnected from ttyUSB0
[181709.595568] option 1-1:1.0: device disconnected
[181709.595798] huawei_cdc_ncm 1-1:1.1 wwp6s0u2i1: unregister 'huawei_cdc_ncm' usb-0000:06:00.0-1, Huawei CDC NCM device
[181709.615005] option 1-1:1.0: GSM modem (1-port) converter detected
[181709.616597] usb 1-1: GSM modem (1-port) converter now attached to ttyUSB0
[181709.623449] usb 1-1: MAC-Address: 0c:5b:8f:27:9a:64
[181709.623958] huawei_cdc_ncm 1-1:1.1: cdc-wdm0: USB WDM device
[181709.624341] huawei_cdc_ncm 1-1:1.1 wwan0: register 'huawei_cdc_ncm' at usb-0000:06:00.0-1, Huawei CDC NCM device, 0c:5b:8f:27:9a:64
Сразу скажу, скрипт очень далек от идеала, поэтому с радостью приму советы и обоснованную критику в свой адрес.
Отдельно хочу поблагодарить пользователя с Toster.ru под ником @AlekseyNemiro, за оказанную помощь в оптимизации скрипта.
Автор: wmlex