Prueba de velocidad simultánea en varios módems LTE

Durante la cuarentena, se me propuso participar en el desarrollo de un dispositivo para medir la velocidad de los módems LTE para varios operadores de telefonía móvil.

Prueba de velocidad simultánea en varios módems LTE

El cliente quería evaluar la velocidad de diversos operadores en diferentes puntos geográficos, para entender cuál operador móvil sería el más óptimo para la instalación de equipos que utilizan conexión LTE, por ejemplo, para transmisiones de video. Además, la tarea debía resolverse de la manera más simple y económica, sin equipo costoso.

Debo decir que la tarea no es la más sencilla y es intensiva en ciencia, así que contaré sobre los problemas que encontré y cómo los resolví. Así que, ¡vamos allá!

Nota

Medir la velocidad de la conexión LTE es bastante complicado: es necesario elegir correctamente el equipo y la metodología de medición, además de tener una buena comprensión de la topología y el funcionamiento de la red móvil. Además, la velocidad puede verse afectada por varios factores: el número de abonados en la celda, las condiciones meteorológicas, incluso de una celda a otra la velocidad puede variar drásticamente debido a la topología de la red. En general, esta tarea tiene una gran cantidad de incógnitas, y solo el operador de telefonía puede resolverla correctamente.

Inicialmente, el cliente quería simplemente hacer que un mensajero probara los teléfonos de los operadores, realizando mediciones directamente en el teléfono y luego anotando los resultados de velocidad en una libreta. Mi solución para medir la velocidad de las redes LTE, aunque no es perfecta, aborda el problema planteado.

Debido a la falta de tiempo, tomé decisiones no en favor de la comodidad o la practicidad, sino en favor de la velocidad de desarrollo. Por ejemplo, para el acceso remoto, se levantó un SSH inverso, en lugar de un VPN más práctico, para ahorrar tiempo en la configuración del servidor y de cada cliente individual.

Especificaciones técnicas

Como se menciona en el artículo Sin especificaciones: por qué el cliente no quiere tenerlas: ¡No trabajes sin especificaciones! ¡Nunca, en ningún lugar!

Las especificaciones eran bastante simples, las ampliaré un poco para la comprensión del usuario final. La elección de soluciones técnicas y equipo fue dictada por el cliente. Así que, las propias especificaciones, después de todas las aprobaciones:

Basado en una computadora de una sola placa vim2 hacer un tester de velocidad de conexión LTE a través de módems Huawei e3372h — 153 varios operadores de telecomunicaciones (de uno a n). También es necesario obtener coordenadas de un receptor GPS conectado por UART. Las mediciones de velocidad se realizan utilizando el servicio www.speedtest.net y recopilarlas en una tabla del tipo:

Prueba de velocidad simultánea en varios módems LTE

Tabla en formato csv. Después, enviar este archivo por correo electrónico cada 6 horas. En caso de errores, parpadear con un LED conectado a GPIO.

He descrito el TDR de forma libre, después de múltiples aprobaciones. Pero el sentido de la tarea ya es evidente. El plazo para todo esto fue de una semana. Sin embargo, en la realidad se extendió a tres semanas. Esto teniendo en cuenta que solo trabajé en esto después del trabajo principal y los fines de semana.

Aquí quiero volver a enfatizar que el cliente había estipulado previamente el uso de un servicio de medición de velocidad y el hardware, lo que limitó significativamente mis posibilidades. También había un presupuesto limitado, así que no compré nada adicional. Por lo tanto, tuve que jugar con estas reglas.

Arquitectura y desarrollo

El esquema es simple y evidente. Por lo tanto, lo dejaré sin comentarios especiales.

Prueba de velocidad simultánea en varios módems LTE

Decidí implementar todo el proyecto en python, a pesar de no tener ninguna experiencia de desarrollo en este lenguaje. Lo elegí porque había un montón de ejemplos y soluciones listas que podrían acelerar el desarrollo. Por lo tanto, pido a todos los programadores profesionales que no critiquen mi primera experiencia de desarrollo en python, y siempre estoy dispuesto a recibir críticas constructivas para mejorar mis habilidades.

También descubrí en el proceso que python tiene dos versiones populares, 2 y 3, así que me detuve en la tercera.

Nodos de hardware

Placa única vim2

Como máquina principal, me dieron una placa única vim2

Prueba de velocidad simultánea en varios módems LTE

Un excelente y potente mediacomponente para el hogar inteligente y SMART-TV, pero raramente adecuado para esta tarea, o digamos, poco apropiado. Por ejemplo, su sistema operativo principal es Android, y Linux es un sistema operativo adicional, por lo que nadie garantiza el funcionamiento de todos los módulos y controladores en Linux. Y supongo que parte de los problemas estaban relacionados con los controladores USB de esta plataforma, por lo que los módems no funcionaron en esta placa como esperaba. Además, tiene una documentación muy deficiente y dispersa, por lo que cada operación requería mucho tiempo buscando en los documentos. Incluso el trabajo ordinario con GPIO fue un desafío. Por ejemplo, para configurar el funcionamiento con un LED, me llevó varias horas. Pero, siendo objetivos, no importaba tanto qué tipo de placa única era, lo principal era que funcionara y tuviera puertos USB.

Para empezar, necesito instalar Linux en esta placa. Para no perderme entre la densa documentación, y también para aquellos que estén tratando con esta placa única, escribo este capítulo.

Hay dos opciones para instalar Linux: en una tarjeta SD externa o en una MMC interna. Pasé una tarde intentando hacerlo con la tarjeta, pero no logré hacerla funcionar, por lo que decidí instalar en MMC, aunque sin duda trabajar con una tarjeta externa hubiera sido mucho más fácil.

Sobre el firmware se explica torcidamente aquí. Estoy traduciendo de un lenguaje extraño al ruso. Para poder grabar el firmware en la placa, necesito conectar el UART hardware. Lo conecté de la siguiente manera.

  • Pin de Herramienta GND: Pin17 de GPIO de VIM
  • Pin de Herramienta TXD: Pin18 de GPIO de VIM (Linux_Rx)
  • Pin de Herramienta RXD: Pin19 de GPIO de VIM (Linux_Tx)
  • Pin de Herramienta VCC: Pin20 de GPIO de VIM

Prueba de velocidad simultánea en varios módems LTE

Después de eso, descargué el firmware desde aquí. La versión específica del firmware VIM1_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.

Para poder cargar este firmware, necesito algunas herramientas. Se explica más detalladamente aquí. No intenté grabar con Windows, pero debo mencionar un par de palabras sobre el firmware en Linux. Primero instalaré las herramientas, según las instrucciones.

git clone https://github.com/khadas/utils
cd /path/to/utils
sudo ./INSTALL

Y… No funciona nada. Pasé un par de horas editando los scripts de instalación para que se instalaran correctamente. No recuerdo lo que hice, pero fue todo un circo. Así que tengan cuidado. Pero sin estas herramientas no tiene sentido seguir intentando con vim2. Mejor ni acercarse a él.

Después de siete círculos de hell, configuraciones de scripts e instalaciones, obtuve un paquete de utilidades funcionales. Conecté la placa por USB a mi computadora Linux, y también conecté el UART según el esquema de arriba.
Estoy configurando mi terminal favorito, minicom, a una velocidad de 115200, sin control de errores de hardware ni software. Empecemos.

Prueba de velocidad simultánea en varios módems LTE

Al iniciar VIM2 en el terminal UART, presiono cualquier tecla, por ejemplo, la barra espaciadora, para detener el inicio. Después de que aparezca la línea

kvim2# 

Escribo el comando:

kvim2# run update

En el host desde el que estamos cargando, ejecuto:

burn-tool -v aml -b VIM2 -i VIM2_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.img

Todo, uff. Flasheado, la placa tiene Linux. Usuario/contraseña khadas:khadas.

Después de esto, algunas configuraciones iniciales. Para continuar trabajando, desactivo la contraseña para sudo (sí, no es seguro, pero es conveniente).

sudo visudo

Edito la línea para que quede así y guardo.

# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) NOPASSWD: ALL

Después de eso, cambio la localización actual para que la hora esté según Moscú, de lo contrario será según Greenwich.

sudo timedatectl set-timezone Europe/Moscow

o

ln -s /usr/share/zoneinfo/Europe/Moscow /etc/localtime

Si te parece complicado, entonces no uses esta placa, mejor una Raspberry Pi. Honestamente.

Módem Huawei e3372h — 153

Este módem realmente me ha causado muchos problemas, y, de hecho, se convirtió en el eslabón más débil de todo el proyecto. En general, el nombre "módem" para estos dispositivos no refleja en absoluto su funcionamiento: es una poderosa herramienta multifuncional, este aparato tiene un dispositivo compuesto que se presenta como un CD-ROM para instalar los controladores, y luego cambia al modo de tarjeta de red.

Desde el punto de vista arquitectónico, para un usuario de Linux después de todas las configuraciones, se ve así: después de conectar el módem, aparece una interfaz de red eth*, que por DHCP recibe la dirección IP 192.168.8.100, y la puerta de enlace por defecto 192.168.8.1.

¡Y el punto más importante! Este modelo de módem no puede funcionar en modo de módem, que se controla por comandos AT.Todo sería mucho más fácil, crear conexiones PPP para cada módem y luego operarlos. Pero en mi caso, el mismo (más bien, el controlador de Linux según las reglas de udev), crea la interfaz eth y le asigna una dirección IP por DHCP.

Para no confundirnos más, sugiero olvidar la palabra "módem" y hablar de tarjeta de red y puerta de enlace, porque en esencia, es como conectar una nueva tarjeta de red con puerta de enlace.
Cuando hay un solo módem, esto no causa problemas especiales, pero cuando hay más de uno, es decir, n unidades, surge el siguiente escenario de red.

Prueba de velocidad simultánea en varios módems LTE

Es decir, n tarjetas de red, con una sola dirección IP, cada una con la misma puerta de enlace por defecto. Pero de hecho, cada una de ellas está conectada a su propio operador.

Inicialmente tenía una solución simple: mediante el comando ifconfig o ip, desactivar todas las interfaces y simplemente activar una a la vez para probarla. La solución funcionaba bien, excepto que en momentos de conmutación no tenía la oportunidad de conectarme al dispositivo. Y dado que las conmutaciones eran frecuentes y rápidas, en realidad no podía conectarme en absoluto.

Por ello, opté por cambiar "manualmente" las direcciones IP de los módems y luego dirigir el tráfico mediante la configuración de enrutamiento.

Prueba de velocidad simultánea en varios módems LTE

Mis problemas con los módems no terminaron ahí: en caso de problemas de alimentación, se desconectaban, se requería una buena alimentación estable del hub USB. Esta problemática la solucioné soldando directamente la alimentación al hub. Otro problema que enfrenté y que arruinó todo el proyecto: después de reiniciar o hacer un arranque en frío, no todos los módems se detectaban y no siempre, y no logré averiguar por qué sucedía esto ni qué algoritmo seguía. Pero vamos por partes.

Para el correcto funcionamiento del módem, instalé el paquete usb-modeswitch.

sudo apt update
sudo apt install -y usb-modeswitch

Después de esto, el módem, tras ser conectado, se detectará y configurará correctamente por el subsistema udev. Verifico, simplemente conectando el módem y asegurándome de que la red ha aparecido.
Otro problema que no pude resolver: ¿cómo obtener el nombre del operador con el que trabajamos desde este módem? El nombre del operador está en la interfaz web del módem en la dirección 192.168.8.1. Es una página web dinámica que obtiene datos mediante solicitudes ajax, por lo que no se puede simplemente descargar la página y extraer el nombre. Así que comencé a estudiar cómo funcionaba la página web, y me di cuenta de que estaba haciendo algo absurdo. Al final, decidí rendirme y obtuve el operador mediante la API de Speedtest.

Mucho sería más fácil si el módem tuviera acceso a través de comandos AT. Se podría reconfigurar, crear una conexión ppp, asignar IP, obtener el operador de telecomunicaciones, etc. Pero lamentablemente, trabajo con lo que me dieron.

GPS

El receptor GPS que me dieron tenía una interfaz UART y alimentación. No era la mejor solución, pero funcionaba y era simple. El receptor tenía un aspecto similar.

Prueba de velocidad simultánea en varios módems LTE

Honestamente, estaba trabajando con un receptor GPS por primera vez, pero como preveía, todo ya estaba pensado por nosotros. Así que simplemente utilizamos soluciones ya existentes.

Para empezar, activo uart_AO_B (UART_RX_AO_B, UART_TX_AO_B) para conectar el GPS.

khadas@Khadas:~$ sudo fdtput -t s /dtb.img /serial@c81004e0 status okay

Luego verifico el éxito de la operación.

khadas@Khadas:~$ fdtget /dtb.img /serial@c81004e0 status
okay

Este comando, aparentemente, edita el devtree sobre la marcha, lo cual es bastante conveniente.

Después del éxito de esta operación, reiniciamos e instalamos el demonio gps.

khadas@Khadas:~$ sudo reboot

Instalando el demonio gps. Instalo todo y lo apago de inmediato para configurarlo más tarde.

sudo apt install gpsd gpsd-clients -y
sudo killall gpsd

/* Detener/desactivar el demonio GPS */
sudo systemctl stop gpsd.socket
sudo systemctl disable gpsd.socket

Edito el archivo de configuración.

sudo vim /etc/default/gpsd

Configuro el UART en el que estará conectado el GPS.

DEVICES="/dev/ttyS4"

Y después de eso, lo encendemos y comenzamos.

/* GPS daemon enable/start */
sudo systemctl enable gpsd.socket
sudo systemctl start gpsd.socket

Tras lo cual, conecto el GPS.

Prueba de velocidad simultánea en varios módems LTE

En mis manos tengo el cable del GPS, y bajo mis dedos están los cables UART del depurador.

Reinicio y compruebo el funcionamiento del GPS con el programa gpsmon.

Prueba de velocidad simultánea en varios módems LTE

En esta captura de pantalla no se ven satélites, pero se observa la comunicación con el receptor GPS, lo cual indica que todo está bien.

Probé muchas formas de trabajar con este demonio en Python, pero me detuve en la que funcionaba correctamente con Python 3.

Instalo la biblioteca necesaria.

sudo -H pip3 install gps3 

Y genero el código de funcionamiento.

from gps3.agps3threaded import AGPS3mechanism
...
def getPositionData(agps_thread):
	counter = 0;
	while True:
		longitude = agps_thread.data_stream.lon
		latitude = agps_thread.data_stream.lat
		if latitude != 'n/a' and longitude != 'n/a':
			return '{}' .format(longitude), '{}' .format(latitude)
		counter = counter + 1
		print ("Esperando gps contador = %d" % counter)
		if counter == 10:
			ErrorMessage("¡Error en el receptor GPS!!!")
			return "NA", "NA"
		time.sleep(1.0)
...
f __name__ == '__main__':
...	#gps
	agps_thread = AGPS3mechanism()  # Instanciar mecanismos AGPS3
	agps_thread.stream_data()  # Desde localhost (), o otros hosts, por ejemplo, (host='gps.ddns.net')
	agps_thread.run_thread()  # Tiempo de regulación para dormir después de una búsqueda vacía, por defecto '()' 0.2 dos décimas de segundo

Si necesito obtener las coordenadas, se hace con la siguiente llamada:

longitude, latitude = getPositionData(agps_thread)

Y en un lapso de 1 a 10 segundos, o recibiré la coordenada o no. Sí, tuve diez intentos para obtener las coordenadas. No es óptimo, es torcido y torpe, pero funciona. Decidí hacerlo así porque el GPS puede recibir señal pobremente y no siempre obtener datos. Si espero a obtener los datos, en caso de trabajar en un lugar cerrado, el programa se congelará en ese punto. Por eso implementé esta opción poco elegante.

En principio, si hubiera tenido más tiempo, podría haber recibido datos del GPS directamente por UART, analizarlos en un hilo separado y trabajar con ellos. Pero no hubo tiempo en absoluto, de ahí el código desagradable. Y sí, no me da vergüenza.

Diodo

La conexión del diodo fue sencilla y complicada al mismo tiempo. La principal dificultad es que el número del pin en el sistema no corresponde al número del pin en la placa y porque la documentación está escrita de manera deficiente. Para correlacionar el número del pin de hardware y el número del pin en el SO, se debe ejecutar el comando:

gpio readall

Se mostrará una tabla de correspondencias entre el pin en el sistema y en la placa. Después de eso, ya puedo operar el pin en el mismo SO. En mi caso, el diodo está conectado a GPIOH_5.

Prueba de velocidad simultánea en varios módems LTE

Cambio el pin GPIO al modo de salida.

gpio -g mode 421 out

Escribo un cero.

gpio -g write 421 0

Escribo un uno.

gpio -g write 421 1

Prueba de velocidad simultánea en varios módems LTE
Todo se enciende después de escribir "1".

#gpio subsistem
def gpio_init():
	os.system("gpio -g mode 421 out")
	os.system("gpio -g write 421 1")

def gpio_set(val):
	os.system("gpio -g write 421 %d" % val)
	
def error_blink():
	gpio_set(0)
	time.sleep(0.1)
	gpio_set(1)
	time.sleep(0.1)
	gpio_set(0)
	time.sleep(0.1)
	gpio_set(1)
	time.sleep(0.1)
	gpio_set(0)
	time.sleep(1.0)
	gpio_set(1)

def good_blink():
	gpio_set(1)

Ahora, en caso de errores, llamo a error_blink() y el diodo parpadea de forma bonita.

Módulos de software

API de Speedtest

Es un gran alivio que el servicio speedtest.net tenga su propia API de Python, que se puede consultar en Github.

Lo bueno es que hay códigos fuente que también se pueden revisar. Cómo trabajar con esta API (ejemplos simples) se puede encontrar en la sección correspondiente.

Instalo la biblioteca de Python con el siguiente comando.

sudo -H pip3 install speedtest-cli

Por ejemplo, puedes instalar el speedtester en Ubuntu directamente desde el repositorio. Es la misma aplicación en Python, que luego se puede ejecutar directamente desde la consola.

sudo apt install speedtest-cli -y

Y realizar medidas de la velocidad de tu internet.

speedtest-cli
Recuperando la configuración de speedtest.net...
Probando desde B***** (*.*.*.*)...
Recuperando la lista de servidores de speedtest.net...
Seleccionando el mejor servidor basado en el ping...
Alojado por MTS (Moscú) [0.12 km]: 11.8 ms
Probando velocidad de descarga................................................................................
Descarga: 7.10 Mbit/s
Probando velocidad de subida......................................................................................................
Subida: 3.86 Mbit/s

Como resultado, así lo hice. Tuve que revisar los códigos fuente de este speedtest para implementarlos más plenamente en mi proyecto. Una de las tareas más importantes es obtener también el nombre del operador de red, para incluirlo en la tabla.

import speedtest
from datetime import datetime
...
# Especificamos el servidor concreto para la prueba
#6053) MaximaTelecom (Moscú, Federación Rusa)
servers = ["6053"]
# Si deseas utilizar una prueba de un solo hilo
threads = None
s = speedtest.Speedtest()
# Obtenemos el nombre del operador de telecomunicaciones
opos = '%(isp)s' % s.config['client']
s.get_servers(servers)
# Obtenemos la cadena de texto con los parámetros del servidor
testserver = '%(sponsor)s (%(name)s) [%(d)0.2f km]: %(latency)s ms' % s.results.server
# Prueba de descarga
s.download(threads=threads)
# Prueba de subida
s.upload(threads=threads)
# Obtenemos los resultados
s.results.share()

# Después se forma una cadena para registrar en el archivo csv.
# Obtenemos la posición GPS
longitude, latitude = getPositionData(agps_thread)
# Hora y fecha
curdata = datetime.now().strftime('%d.%m.%Y')
curtime = datetime.now().strftime('%H:%M:%S')
delimiter = ';'
result_string = opos + delimiter + str(curpos) + delimiter + 
	curdata + delimiter + curtime + delimiter + longitude + ', ' + latitude + delimiter + 
	str(s.results.download/1000.0/1000.0) + delimiter + str(s.results.upload / 1000.0 / 1000.0) + 
	delimiter + str(s.results.ping) + delimiter + testserver + "n"
# Aquí se graba en el archivo de logs

Aquí tampoco resultó ser tan sencillo, aunque, a primera vista, podría parecerlo. Inicialmente, el parámetro servers era igual a [], como de elegir el mejor servidor. Como resultado, tuve servidores aleatorios y, como es fácil adivinar, velocidad variable. Es un tema bastante complejo, usar un servidor fijo, si es así, si es estático o dinámico, requiere investigación. Pero aquí hay un ejemplo de gráficos de mediciones de velocidad del operador Beeline al elegir dinámicamente un servidor de prueba y uno estáticamente fijo.

Prueba de velocidad simultánea en varios módems LTE
Resultado de la medición de velocidad al elegir un servidor dinámico.

Prueba de velocidad simultánea en varios módems LTE
Resultado de la prueba de velocidad al elegir estrictamente un solo servidor.

La 'variabilidad' en la prueba está presente en ambos casos, y debe eliminarse mediante métodos matemáticos. Pero con un servidor fijo, hay un poco menos y la amplitud es más estable.
En general, este es un área de grandes investigaciones. Yo haría mediciones de velocidad hacia mi servidor, utilizando la herramienta iperf. Pero nos ajustamos a los requerimientos.

Envío de correos y errores

Para enviar correos probé varias decenas de opciones diferentes, pero al final me detuve en la siguiente. Registré una cuenta de correo en Yandex y luego tomé este ejemplo de envío de correos. Lo probé e implementé en el programa. En este ejemplo se analizan varias opciones, incluido el envío desde Gmail, etc. No quería perder tiempo levantando mi propio servidor de correos, y no tenía tiempo para ello, pero como resultó, también fue en vano.

El envío de los registros se realizaba a través del programador, cuando había conexión, cada 6 horas: a las 00:00, 06:00, 12:00 y 18:00. Se enviaban de la siguiente manera.

from send_email import *
...
message_log = "Registros de prueba de la placa Nº1"
EmailForSend = ["dlinyj@trololo.ru", "pupkin@trololo.ru"]
files = ["/home/khadas/modems_speedtest/csv"]
...
def sendLogs():
	global EmailForSend
	curdata = datetime.now().strftime('%d.%m.%Y')
	curtime = datetime.now().strftime('%H:%M:%S')
	try:
		for addr_to in EmailForSend:
			send_email(addr_to, message_log, "Registros de " + curdata + " " + curtime, files)
	except:
		print("Problema de red al enviar el correo")
		return False
	return True

Los errores también se enviaron inicialmente. Para empezar, se acumulaban en una lista, y luego se enviaban también mediante el programador, cuando había conexión. Sin embargo, luego surgieron problemas con el hecho de que Yandex tiene un límite en la cantidad de correos que se pueden enviar por día (es un dolor, tristeza y humillación). Dado que podían ocurrir muchos errores incluso en un minuto, se tuvo que desistir del envío de errores por correo. Así que ten en cuenta que al enviar automáticamente a través de los servicios de Yandex existe este problema.

Servidor de retroalimentación

Para tener acceso a la máquina remota y poder configurarla mejor, necesitaba un servidor externo. En realidad, sería justo enviar todos los datos a un servidor y construir en la interfaz web todas las gráficas bonitas. Pero no se puede hacer todo a la vez.

Como VPS elegí ruvds.com. Podría haber tomado el servidor más simple. En general, para mis propósitos eso hubiera sido más que suficiente. Pero dado que no pagaba el servidor de mi propio bolsillo, decidí optar por algo con un pequeño margen, por si acaso necesitábamos desplegar una interfaz web, un servidor SMTP, VPN, etc. Además de tener la posibilidad de configurar un bot de Telegram y no tener problemas con sus bloqueos. Así que elegí Ámsterdam y los siguientes parámetros.

Prueba de velocidad simultánea en varios módems LTE

Como método de conexión con la máquina vim2, elegí la conexión SSH inversa y, como mostró la práctica, no es la mejor opción. Cuando se corta la conexión, el servidor retiene el puerto y no es posible conectarse por un tiempo. Por lo tanto, aún es mejor utilizar otros métodos de conexión, como VPN. En el futuro, quería cambiar a VPN, pero no tuve tiempo.

No entraré en detalles sobre la configuración del firewall, las restricciones de permisos, la desactivación de la conexión SSH de root y otras verdades evidentes sobre la configuración de VPS. Espero que ya lo sepas todo. Para la conexión remota, creo un nuevo usuario en el servidor.

adduser vimssh

En nuestro hardware genero claves para la conexión SSH.

ssh-keygen

Y las copio en nuestro servidor.

ssh-copy-id vimssh@host.com

En nuestro hardware creo una conexión SSH inversa automática al arrancar cada vez.

[Unidad]
Descripción=Auto Reverse SSH
Requiere=systemd-networkd-wait-online.service
Después=systemd-networkd-wait-online.service
[Servicio]
Usuario=khadas
Ejecutar=\/usr\/bin\/ssh -NT -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 -CD 8080 -R 8083:localhost:22 vimssh@host.com
ReinicioSec=5
Reinicio=siempre
[Install]
DeseadoPor=multi-user.target

Toma en cuenta el puerto 8083: es el que define por qué puerto se realizará la conexión a través de SSH inverso. Lo añadimos al inicio automático y lo iniciamos.

sudo systemctl enable autossh.service
sudo systemctl start autossh.service

Incluso se puede ver el estado:

sudo systemctl status autossh.service

Ahora, en nuestro servidor VPS, si ejecuto:

ssh -p 8083 khadas@localhost

Accedo a mi hardware de prueba. Y desde el hardware también puedo enviar registros y cualquier dato a mi servidor a través de SSH, lo cual es muy conveniente.

Reuniendo todo en uno

Prueba de velocidad simultánea en varios módems LTE
Activación, empezamos a desarrollar y depurar

Uf, parece que ya he descrito todos los nodos. Ahora es el momento de reunir todo esto en un solo conjunto. Se puede ver el código aquí.

Un punto importante sobre el código: este proyecto no puede ejecutarse así de simples, ya que fue diseñado para una tarea específica y una arquitectura específica. Aunque ofrezco el código fuente, lo más valioso lo explicaré aquí, directamente en el texto, de lo contrario será completamente incomprensible.

Al principio, inicializo el GPS, GPIO y arranco un hilo separado para el programador.

#запуск потока планировщика
pShedulerThread = threading.Thread(target=ShedulerThread, args=(1,))
pShedulerThread.start()

El programador es bastante simple: verifica si ha llegado el momento de enviar mensajes y cuál es el estado de errores. Si hay una bandera de error, hacemos parpadear un LED.

#sheduler
def ShedulerThread(name):
	global ready_to_send
	while True:
		d = datetime.today()
		time_x = d.strftime('%H:%M')
		if time_x in time_send_csv:
			ready_to_send = True
		if error_status:
			error_blink()
		else:
			good_blink()
		time.sleep(1)

El momento más complicado en este proyecto es mantener la conexión SSH inversa en cada prueba. En cada prueba, la configuración del gateway por defecto y del servidor DNS se realiza de nuevo. Como nadie lee esto, sepan que el tren no circula sobre rieles de madera. Quien encuentre el easter egg, recibirá un dulce.

Para esto, creo una tabla de enrutamiento separada —set-mark 0x2 y una regla para redirigir el tráfico.

def InitRouteForSSH():
	cmd_run("sudo iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 22 -j MARK --set-mark 0x2")
	cmd_run("sudo ip rule add fwmark 0x2/0x2 lookup 102")

Más sobre cómo funciona esto se puede leer en este artículo.

Después paso a un ciclo infinito, donde cada vez obtengo una lista de los módems conectados (para saber si la configuración de la red ha cambiado).

network_list = getNetworklist()

Obtener la lista de interfaces de red es bastante sencillo.

def getNetworklist():
	full_networklist = os.listdir('/sys/class/net/')
	network_list = [x for x in full_networklist if "eth" in x and x != "eth0"]
	return network_list

Después de obtener la lista, asigno las direcciones IP a todas las interfaces, como mostré en la imagen en el capítulo sobre módem.

SetIpAllNetwork(network_list)

def SetIpAllNetwork(network_list):
	for iface in network_list:
		lastip = "%d" % (3 + network_list.index(iface))
		cmd_run ("sudo ifconfig " + iface + " 192.168.8." + lastip +" up")

A continuación, simplemente recorro cada interfaz en un ciclo. Y configuro cada interfaz.

	for iface in network_list:
		ConfigNetwork(iface)

def ConfigNetwork(iface):
#restablecemos todas las configuraciones
		cmd_run("sudo ip route flush all")
#Asignamos la puerta de enlace por defecto
		cmd_run("sudo route add default gw 192.168.8.1 " + iface)
#asignamos el servidor DNS (esto es necesario para el funcionamiento de speedtest)
		cmd_run ("sudo bash -c 'echo nameserver 8.8.8.8 > /etc/resolv.conf'")

Verifico la interfaz para ver si funciona, si no hay red, formo errores. Si hay red, ¡es hora de actuar!

Aquí configuro la ruta SSH en esta interfaz (si no se ha hecho), envío errores al servidor, si ha llegado el momento, envío los registros y, al final, realizo un speedtest y guardo los registros en un archivo csv.

if not NetworkAvalible():
....
#Aquí formamos errores
....
else: #¡Hay red, hurra, trabajemos!
#Si tenemos una interfaz problemática, en la que está ssh, la cambiamos
  if (sshint == lastbanint or sshint =="free"):
    print("********** Configurar SSH ********************")
    if sshint !="free":
      cmd_run("sudo ip route del default via 192.168.8.1 dev " + sshint +" table 102")
    SetupReverseSSH(iface)
    sshint = iface
#ya que la red está funcionando, ¡enviemos todo rápidamente!!!
    if ready_to_send:
      print ("**** ¡Listo para enviar!!!")
        if sendLogs():
          ready_to_send = False
        if error_status:
          SendErrors()
#y luego probamos la velocidad y guardamos los registros. 

Solo cabe mencionar la función para configurar el ssh inverso.

def SetupReverseSSH(iface):
	cmd_run("sudo systemctl stop autossh.service")
	cmd_run("sudo ip route add default via 192.168.8.1 dev " + iface +" table 102")
	cmd_run("sudo systemctl start autossh.service")

Y, por supuesto, es necesario agregar toda esta belleza al inicio automático. Para ello, creo un archivo:

sudo vim /etc/systemd/system/modems_speedtest.service

Y escribo en él:

[Unidad]
Descripción=Prueba de Velocidad del Módem
Requiere=systemd-networkd-wait-online.service
Después=systemd-networkd-wait-online.service
[Servicio]
Usuario=khadas
ExecStart=\/usr\/bin\/python3.6 \/home\/khadas\/modems_speedtest\/networks.py
ReinicioSec=5
Reinicio=siempre
[Install]
DeseadoPor=multi-user.target

¡Habilito el inicio automático y inicio!

sudo systemctl enable modems_speedtest.service
sudo systemctl start modems_speedtest.service

Ahora puedo ver los registros de lo que está sucediendo usando el comando:

journalctl -u modems_speedtest.service --no-pager -f

Resultados

Bueno, ahora lo más importante, ¿qué salió al final? A continuación, presentaré algunos gráficos que he podido capturar durante el proceso de desarrollo y depuración. Los gráficos se construyeron con gnuplot usando el siguiente script.

#! /usr/bin/gnuplot -persist
set terminal postscript eps enhanced color solid
set output "Rostelecom.ps"
 
#set terminal png size 1024, 768
#set output "Rostelecom.png"
 
set datafile separator ';'
set grid xtics ytics
set xdata time
set ylabel "Speed Mb/s"
set xlabel 'Time'
set timefmt '%d.%m.%Y;%H:%M:%S'
set title "Rostelecom Speed"

plot "Rostelecom.csv" using 3:6 with lines title "Download", '' using 3:7 with lines title "Upload"
 
set title "Rostelecom 2 Ping"
set ylabel "Ping ms"
plot "Rostelecom.csv" using 3:8 with lines title "Ping"

La primera experiencia fue con el operador Tele2, que realicé durante varios días.

Prueba de velocidad simultánea en varios módems LTE

Aquí utilicé un servidor de medición dinámico. Las mediciones de velocidad funcionan, pero fluctúan mucho, aunque aún se puede ver cierta media, y esta se puede obtener filtrando los datos, por ejemplo, usando un promedio móvil.

Más tarde construí otra serie de gráficos para otros operadores de telecomunicaciones. En este caso, el servidor de prueba ya era uno, y los resultados también son muy interesantes.

Prueba de velocidad simultánea en varios módems LTE

Prueba de velocidad simultánea en varios módems LTE

Prueba de velocidad simultánea en varios módems LTE

Prueba de velocidad simultánea en varios módems LTE

Como se puede ver, el tema es muy amplio para investigaciones y el procesamiento de estos datos, y claramente no se puede concluir en un par de semanas de trabajo. Pero…

Conclusión del trabajo

El trabajo se interrumpió abruptamente por circunstancias ajenas a mí. Una de las debilidades de este proyecto, en mi opinión subjetiva, fue el módem, que no quería trabajar muy bien al mismo tiempo que otros módems, y cada vez que se cargaba hacía tales travesuras. Para estos fines, existe una enorme cantidad de otros modelos de módems, que generalmente ya tienen formato Mini PCI-e y se instalan dentro del dispositivo, lo que facilita mucho su configuración. Pero esa es otra historia. El proyecto fue interesante y estaba muy contento de haber podido participar en él.

Prueba de velocidad simultánea en varios módems LTE

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster