Teste de velocidade simultâneo em vários modems LTE

Durante a quarentena, fui convidado a participar do desenvolvimento de um dispositivo para medir a velocidade de modems LTE para várias operadoras de telefonia móvel.

Teste de velocidade simultâneo em vários modems LTE

O cliente queria avaliar a velocidade de várias operadoras de telecomunicações em diferentes localidades, para entender qual operadora seria a mais adequada ao instalar equipamentos que utilizam conexão LTE, como para transmissões de vídeo. A tarefa precisava ser resolvida da forma mais simples e econômica possível, sem equipamentos caros.

De imediato, preciso dizer que a tarefa não é a mais simples e é intensiva em pesquisa. Vou narrar quais problemas encontrei e como os resolvi. Então, vamos lá.

Nota

Medir a velocidade da conexão LTE é uma tarefa bastante complexa: é necessário escolher corretamente o equipamento e a metodologia de medição, além de ter uma boa compreensão da topologia e do funcionamento da rede celular. Além disso, a velocidade pode ser influenciada por vários fatores: o número de assinantes na torre, as condições climáticas, e até mesmo de torre para torre a velocidade pode variar drasticamente devido à topologia da rede. Em suma, é uma tarefa com uma infinidade de variáveis desconhecidas, e apenas uma operadora de telecomunicações pode resolver isso corretamente.

Inicialmente, o cliente queria apenas que um mensageiro fosse enviado com os telefones das operadoras, realizando medições diretamente no celular e anotando os resultados em um caderno. Minha solução para medir a velocidade das redes LTE, embora não seja perfeita, atende à demanda proposta.

Devido à falta de tempo, tomei decisões que priorizavam a velocidade de desenvolvimento em vez da conveniência ou da praticidade. Por exemplo, para acesso remoto, estabeleci um SSH reverso ao invés de um VPN mais prático, tudo isso para economizar tempo na configuração do servidor e de cada cliente individual.

Especificação técnica

Como mencionado no artigo Sem um documento de requisitos: por que o cliente não quer um: Não trabalhe sem um documento de requisitos! Nunca, em lugar algum!

O documento de requisitos era bastante simples, e eu o expandirei um pouco para facilitar a compreensão do usuário final. A escolha das soluções e dos equipamentos foi ditada pelo cliente. Portanto, o próprio documento de requisitos, após todas as aprovações:

Baseado em um computador de placa única vim2 fazer um testador de velocidade de conexão LTE através de modems Huawei e3372h — 153 de vários operadores de telecomunicações (de um a n). Também é necessário obter coordenadas de um receptor GPS conectado via UART. Medições de velocidade devem ser realizadas usando o serviço www.speedtest.net e organizá-las em uma tabela do tipo:

Teste de velocidade simultâneo em vários modems LTE

Tabela no formato csv. Depois, enviar por e-mail essa tabela a cada 6 horas. Em caso de erros, acender um LED conectado ao GPIO.

A especificação foi descrita de forma livre, após muitas discussões. Mas o propósito da tarefa já é visível. O prazo total foi de uma semana. Contudo, na realidade se estendeu por três semanas. Isso considerando que eu fiz isso apenas após o trabalho principal e nos finais de semana.

Aqui quero reiterar que o cliente havia previamente acordado o uso do serviço de medição de velocidade e do hardware, o que limitou bastante minhas possibilidades. O orçamento também foi restrito, então não foi possível adquirir mais equipamentos. Portanto, tive que jogar com as regras dadas.

Arquitetura e desenvolvimento

O esquema é simples e óbvio. Portanto, deixarei sem muitos comentários.

Teste de velocidade simultâneo em vários modems LTE

Decidi implementar todo o projeto em python, apesar de não ter experiência de desenvolvimento nessa linguagem. Escolhi-a porque havia muitos exemplos e soluções prontas que poderiam acelerar o desenvolvimento. Portanto, peço a todos os programadores profissionais que não critiquem meu primeiro projeto em python e estou sempre aberto a críticas construtivas, para melhorar minhas habilidades.

Durante o processo, descobri que python tem duas versões principais: 2 e 3, e acabei optando pela terceira.

Módulos de hardware

Placa única vim2

Como máquina principal, foi-me fornecida uma placa única vim2

Teste de velocidade simultâneo em vários modems LTE

Um excelente e poderoso mediacomponente para casas inteligentes e SMART-TV, mas incomumente inadequado para esta tarefa, ou melhor dizendo, pouco adequado. Por exemplo, seu sistema operacional principal é o Android, enquanto o Linux é um sistema operacional secundário, portanto, ninguém garante o funcionamento adequado de todos os componentes e drivers no Linux. Suspeito que parte dos problemas esteja relacionada aos drivers USB desta plataforma, o que fez com que os modems não funcionassem na placa como eu esperava. Também, possui uma documentação muito ruim e fragmentada, o que tornava cada operação demorada, devido à necessidade de pesquisar na documentação. Até mesmo uma tarefa simples com GPIO consumiu muito tempo. Por exemplo, para configurar o funcionamento de um LED, precisei de várias horas. Mas, sendo objetivo, não importava fundamentalmente qual era a placa, o principal era que funcionasse e tivesse portas USB.

Para começar, eu preciso instalar o Linux nesta placa. Para não ter que vasculhar toda a documentação, e também para aqueles que vão lidar com esta placa de um único chip, escrevo este capítulo.

Existem duas opções para instalar o Linux: em um cartão SD externo ou na MMC interna. Passei um tempo tentando com o cartão, mas não consegui entender como fazê-lo funcionar, então decidi instalar na MMC, embora não haja dúvida de que trabalhar com o cartão externo seria muito mais fácil.

Sobre o firmware é mal contado aqui. Estou traduzindo do estranho para o russo. Para poder atualizar a placa, preciso conectar a UART de hardware. Conectei-a da seguinte forma.

  • Tool Pin GND: Pino 17 do GPIO do VIM
  • Tool Pin TXD: Pino 18 do GPIO do VIM (Linux_Rx)
  • Tool Pin RXD: Pino 19 do GPIO do VIM (Linux_Tx)
  • Tool Pin VCC: Pino 20 do GPIO do VIM

Teste de velocidade simultâneo em vários modems LTE

Depois disso, baixei o firmware daqui. A versão específica do firmware VIM1_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.

Para carregar este firmware, eu preciso de algumas utilitários. Mais informações sobre isso estão disponíveis aqui. Não tentei atualizar a partir do Windows, mas preciso comentar um pouco sobre a atualização no Linux. Primeiro, vou instalar os utilitários de acordo com as instruções.

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

E… nada funciona. Passei algumas horas editando scripts de instalação para que tudo fosse instalado corretamente. O que eu fiz não lembro, mas foi um verdadeiro circo. Então, cuidem-se. Mas sem esses utilitários, não vale a pena continuar com o vim2. Melhor não se envolver com ele!

Depois de sete círculos de sofrimento, configuração de scripts e instalação, consegui um pacote de utilitários funcionais. Conectei a placa via USB ao meu computador Linux, e também conectei o UART conforme o esquema acima.
Configuro meu terminal favorito, o minicom, para a velocidade de 115200, sem controle de erro de hardware e software. E vamos começar.

Teste de velocidade simultâneo em vários modems LTE

Ao iniciar o VIM2 no terminal UART, pressiono qualquer tecla, como a barra de espaço, para interromper a inicialização. Depois que a linha aparecer,

kvim2# 

Digito o comando:

kvim2# run update

No host de onde estamos fazendo a inicialização, executo:

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

Pronto. Ufa. O dispositivo foi atualizado, agora tem Linux. Login/senha khadas:khadas.

Depois disso, algumas configurações iniciais. Para facilitar, desativo a senha do sudo (sim, não é seguro, mas é conveniente).

sudo visudo

Edite a linha para o seguinte formato e salve.

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

Depois disso, mudo o fuso horário atual para que a hora seja de Moscovo, caso contrário, será pelo horário de Greenwich.

sudo timedatectl set-timezone Europe/Moscow

ou

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

Se você achou isso complicado, então não use esta placa, melhor optar pelo Raspberry Pi. Honestamente.

Modem Huawei e3372h — 153

Este modem me deu bastante trabalho e, na verdade, tornou-se o ponto mais fraco de todo o projeto. Na verdade, o nome “modem” para esses dispositivos não reflete a natureza do seu funcionamento: é uma poderosa combinação, este equipamento contém um dispositivo composto que se apresenta como CD-ROM para instalar drivers e depois muda para o modo de placa de rede.

Arquitetonicamente, do ponto de vista do usuário Linux, após todas as configurações, parece assim: depois de conectar o modem, aparece uma interface de rede eth*, que recebe um endereço IP 192.168.8.100 via DHCP, e o gateway padrão 192.168.8.1.

E o ponto mais importante! Este modelo de modem não consegue operar no modo de modem controlado por comandos AT.Seria muito mais fácil criar conexões PPP para cada modem e trabalhar com elas. Mas, no meu caso, o próprio (ou melhor, o driver Linux conforme as regras do udev) cria a interface eth e atribui um endereço IP via DHCP.

Para evitar confusões, sugiro esquecer a palavra “modem” e chamar de placa de rede e gateway, pois na verdade isso é como conectar uma nova placa de rede com um gateway.
Quando há apenas um modem, isso não causa problemas especiais, mas quando há mais de um, ou seja, n dispositivos, o seguinte cenário de rede surge.

Teste de velocidade simultâneo em vários modems LTE

Ou seja, n placas de rede, com um único endereço IP, cada uma com o mesmo gateway por padrão. Mas, na prática, cada uma está conectada ao seu próprio operador.

Inicialmente, eu tinha uma solução simples: usar o comando ifconfig ou ip para desativar todas as interfaces e simplesmente ativar uma de cada vez para testá-las. A solução funcionava bem, exceto pelo fato de que, durante a comutação, eu não tinha como me conectar ao dispositivo. E como as comutações eram frequentes e rápidas, na verdade eu não conseguia me conectar de forma alguma.

Portanto, escolhi mudar os endereços IP dos modems "manualmente" e depois redirecionar o tráfego através das configurações de roteamento.

Teste de velocidade simultâneo em vários modems LTE

As minhas problemas com os modems não terminaram aí: em caso de problemas de alimentação, eles falhavam, sendo necessário uma fonte de energia USB estável. Resolvi esse problema soldando a alimentação diretamente ao hub. Outro problema que enfrentei, que comprometeu todo o projeto: após reiniciar ou fazer um cold start, nem todos os modems eram reconhecidos e nem sempre, e não consegui descobrir o motivo ou o algoritmo pelo qual isso acontecia. Mas vamos por partes.

Para o funcionamento correto do modem, instalei o pacote usb-modeswitch.

sudo apt update
sudo apt install -y usb-modeswitch

Depois disso, o modem será corretamente reconhecido e configurado pelo subsistema udev após a conexão. Verifico apenas conectando o modem e certificando-me de que a rede apareceu.
Mais um problema que não consegui resolver: como obter o nome do operador com o qual estamos trabalhando a partir deste modem? O nome do operador está no interface web do modem no endereço 192.168.8.1. É uma página web dinâmica que obtém os dados através de requisições ajax, então simplesmente fazer um wget na página e fazer o parsing do nome não é uma opção. Comecei a investigar como manipular a página web, etc., e percebi que estava me envolvendo em algo sem sentido. No final, desisti, e passei a obter o operador através da API do próprio Speedtest.

Muita coisa seria mais simples se o modem tivesse acesso via comandos AT. Poderíamos reconfigurá-lo, criar uma conexão ppp, atribuir IP, obter o operador de telecomunicações, etc. Mas, infelizmente, estou lidando com o que me foi dado.

GPS

O receptor GPS que me foi fornecido tinha interface UART e alimentação. Não era a melhor solução, mas era funcional e simples. O receptor tinha uma aparência semelhante a esta.

Teste de velocidade simultâneo em vários modems LTE

Sinceramente, trabalhei pela primeira vez com um receptor GPS, mas como já imaginava, tudo já havia sido pensado. Então, apenas utilizamos soluções prontas.

Para começar, ligo uart_AO_B (UART_RX_AO_B, UART_TX_AO_B) para conectar o GPS.

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

Depois, verifico se a operação foi bem-sucedida.

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

Este comando, segundo parece, edita o devtree em tempo real, o que é bastante conveniente.

Após o sucesso dessa operação, reiniciamos e instalamos o daemon GPS.

khadas@Khadas:~$ sudo reboot

Instalando o daemon GPS. Instalo tudo e o desligo imediatamente para configuração posterior.

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

/* Parar/desabilitar o daemon GPS */
sudo systemctl stop gpsd.socket
sudo systemctl disable gpsd.socket

Edito o arquivo de configurações.

sudo vim /etc/default/gpsd

Configuro o UART onde o GPS estará conectado.

DEVICES="/dev/ttyS4"

E então, ligamos tudo e iniciamos.

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

Depois disso, conecto o GPS.

Teste de velocidade simultâneo em vários modems LTE

Na mão, o cabo do GPS; sob os dedos, vejo os fios do depurador UART.

Reinicio e verifico o funcionamento do GPS com o programa gpsmon.

Teste de velocidade simultâneo em vários modems LTE

Nesta captura de tela, não se veem os satélites, mas é visível a comunicação com o receptor GPS, o que indica que tudo está bem.

Experimentei várias opções de funcionamento com esse daemon no Python, mas me decidi por uma que funcionava corretamente com o Python 3.

Instalo a biblioteca necessária.

sudo -H pip3 install gps3 

E vou elaborando o código de funcionamento.

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 ("Aguardando contador GPS = %d" % counter)
		if counter == 10:
			ErrorMessage("Erro no receptor GPS!!!")
			return "NA", "NA"
		time.sleep(1.0)
...
if __name__ == '__main__':
...
	#gps
	agps_thread = AGPS3mechanism()  # Instanciar mecanismos AGPS3
	agps_thread.stream_data()  # A partir do localhost (), ou outros hosts, por exemplo, (host='gps.ddns.net')
	agps_thread.run_thread()  # Tempo de espera após uma busca vazia, padrão '()' 0.2 dois décimos de segundo

Se eu precisar obter as coordenadas, isso é feito com a seguinte chamada:

longitude, latitude = getPositionData(agps_thread)

E em um intervalo de 1 a 10 segundos eu posso receber as coordenadas ou não. Sim, eu tive dez tentativas para obter as coordenadas. Não é ideal, é meio torto, mas funciona. Decidi fazer assim porque o GPS pode ter um sinal fraco e nem sempre obtém dados. Se eu esperasse pela obtenção dos dados, em um ambiente fechado, o programa travaria nesse ponto. Portanto, implementei essa solução não muito elegante.

Na verdade, se tivesse mais tempo, poderia receber os dados do GPS diretamente pelo UART, analisá-los em uma thread separada e trabalhar com eles. Mas não tive tempo, hence o código feio. E sim, não tenho vergonha disso.

LED

A conexão do LED foi simples e complicada ao mesmo tempo. A principal dificuldade é que o número do pino no sistema não corresponde ao número do pino na placa e porque a documentação foi feita de forma improvisada. Para mapear o número do pino físico e o número do pino no SO, é preciso executar o comando:

gpio readall

Uma tabela de mapeamento do pino no sistema e na placa será exibida. Depois disso, posso operar o pino no próprio SO. No meu caso, o LED está conectado ao GPIOH_5.

Teste de velocidade simultâneo em vários modems LTE

Colocando o pino GPIO em modo de saída.

gpio -g mode 421 out

Escrevendo zero.

gpio -g write 421 0

Escrevendo um.

gpio -g write 421 1

Teste de velocidade simultâneo em vários modems LTE
Tudo se acende após escrever "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)

Agora, em caso de erros, eu chamo error_blink() e o LED pisca de forma bonita.

Módulos de software

API Speedtest

É uma grande alegria que o serviço speedtest.net tenha sua própria API Python, que pode ser vista em Github.

O que é bom é que existem códigos fonte que também podem ser visualizados. Como trabalhar com esta API (exemplos simples) pode ser visto na seção correspondente.

Estou instalando a biblioteca Python com o seguinte comando.

sudo -H pip3 install speedtest-cli

Por exemplo, você pode instalar o speedtest no Ubuntu diretamente do repositório. É o mesmo aplicativo Python que pode ser executado diretamente do console.

sudo apt install speedtest-cli -y

E fazer medições da velocidade da sua internet.

speedtest-cli
Recuperando a configuração do speedtest.net...
Testando a partir de B***** (*.*.*.*)...
Recuperando a lista de servidores do speedtest.net...
Selecionando o melhor servidor baseado no ping...
Hospedado pela MTS (Moscovo) [0.12 km]: 11.8 ms
Teste de velocidade de download................................................................................
Download: 7.10 Mbit/s
Teste de velocidade de upload......................................................................................................
Upload: 3.86 Mbit/s

Como eu fiz isso. Tive que olhar nos códigos fonte desse speedtest para integrá-los mais plenamente ao meu projeto. Uma das tarefas mais importantes é obter também o nome do operador de telecomunicações, para inseri-lo na tabela.

import speedtest
from datetime import datetime
...
# Especificando um servidor específico para o teste
#6053) MaximaTelecom (Moscovo, Federação Russa)
servers = ["6053"]
# Se você quiser usar um teste de thread único
threads = None
s = speedtest.Speedtest()
# obtendo o nome da operadora de celular
opos = '%(isp)s' % s.config['client']
s.get_servers(servers)
# obtendo a string de texto com os parâmetros do servidor
testserver = '%(sponsor)s (%(name)s) [%(d)0.2f km]: %(latency)s ms' % s.results.server
# teste de download
s.download(threads=threads)
# teste de upload
s.upload(threads=threads)
# obtendo os resultados
s.results.share()

# Depois disso, forma-se a string para gravação em um arquivo csv.
# obtendo a posição do GPS
longitude, latitude = getPositionData(agps_thread)
# data e hora
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"
# aqui se grava no arquivo de logs

Aqui também não foi tudo tão simples, embora, à primeira vista, parecesse mais fácil. Inicialmente, o parâmetro servers estava definido como [], ou seja, escolha o melhor servidor. Como resultado, eu tinha servidores aleatórios e, como não é difícil imaginar, a velocidade flutuava. Este é um tema complexo; usar um servidor fixo, se sim, deve ser estático ou dinâmico, requer pesquisa. Mas aqui está um exemplo de gráficos de medições de velocidade do operador Beeline ao escolher um servidor de teste dinamicamente e um fixo estático.

Teste de velocidade simultâneo em vários modems LTE
Resultado da medição de velocidade ao escolher um servidor dinâmico.

Teste de velocidade simultâneo em vários modems LTE
Resultado do teste de velocidade, ao escolher rigorosamente um único servidor.

A "flutuação" durante os testes está presente tanto em um quanto em outro, e deve ser eliminada por métodos matemáticos. Mas com o servidor fixo, ela é um pouco menor e a amplitude é mais estável.
De fato, este é um campo de grandes pesquisas. E eu faria medições de velocidade para meu servidor usando a ferramenta iperf. Mas seguimos a especificação do projeto.

Envio de email e erros

Para enviar emails, tentei várias dezenas de opções diferentes, mas acabei me decidindo pela seguinte. Registrei uma conta de email no yandex e depois usei este exemplo de envio de e-mail. Verifiquei e implementei no programa. Neste exemplo, são discutidas várias opções, incluindo o envio com gmail e assim por diante. Eu não queria e não tinha tempo para configurar meu próprio servidor de e-mail, mas como se viu, foi um erro.

O envio de logs foi feito pelo agendador, quando havia conexão, a cada 6 horas: às 00 horas, 06 da manhã, 12 da tarde e 18 da noite. Eu enviava da seguinte forma.

from send_email import *
...
message_log = "Logs de teste da 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')
	сurtime = datetime.now().strftime('%H:%M:%S')
	try:
		for addr_to in EmailForSend:
			send_email(addr_to, message_log, "Logs de " + curdata + " " + сurtime, files)
	except:
		print("Problema de rede ao enviar o e-mail")
		return False
	return True

Os erros também eram enviados inicialmente. Para começar, eles eram acumulados em uma lista e depois enviados também com a ajuda do agendador, quando havia conexão. No entanto, depois surgiram problemas com o fato de que o yandex tem uma limitação no número de mensagens enviadas por dia (isso é uma dor, tristeza e humilhação). Como poderia haver uma quantidade enorme de erros em um minuto, foi necessário desistir do envio de erros por e-mail. Portanto, tenha em mente esse problema ao enviar automaticamente via os serviços do yandex.

Servidor de feedback

Para ter acesso ao hardware remoto e poder configurá-lo e reconfigurá-lo, eu precisei de um servidor externo. Na verdade, para ser justo, seria correto enviar todos os dados ao servidor e construir todos os gráficos bonitos na interface web. Mas nem tudo pode ser feito de uma vez.

Escolhi como VPS ruvds.com. Poderia ter escolhido o servidor mais simples. E, no geral, para meus objetivos isso seria mais do que suficiente. Mas como não paguei pelo servidor do meu bolso, decidi optar por um com um pequeno excedente, para ter o suficiente caso decidíssemos implementar uma interface web, nosso servidor SMTP, VPN, etc. Além disso, para poder configurar um bot do Telegram e evitar problemas com bloqueios. Então escolhi Amsterdam e as seguintes configurações.

Teste de velocidade simultâneo em vários modems LTE

Como método de conexão com o hardware vim2, escolhi uma conexão ssh reversa e, como a prática mostrou — não é a melhor opção. Ao desconectar, o servidor mantém a porta e não é possível conectar-se por algum tempo. Portanto, é melhor usar outros métodos de conexão, como VPN. No futuro, eu queria migrar para VPN, mas não tive tempo.

Não entrarei em detalhes sobre a configuração do firewall, restrições de permissões, desativação da conexão SSH root e outras verdades básicas sobre a configuração de VPS. Espero que você já saiba de tudo isso. Para a conexão remota, crio um novo usuário no servidor.

adduser vimssh

No nosso servidor, gero as chaves de conexão SSH.

ssh-keygen

E as copio para o nosso servidor.

ssh-copy-id vimssh@host.com

No nosso servidor, crio uma conexão automática SSH reversa a cada inicialização.

[Unit]
Descrição=Auto Reverse SSH
Requer=systemd-networkd-wait-online.service
Depois=systemd-networkd-wait-online.service
[Service]
Usuário=khadas
ExecStart=/usr/bin/ssh -NT -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 -CD 8080 -R 8083:localhost:22 vimssh@host.com
RestartSec=5
Reiniciar=sempre
[Install]
WantedBy=multi-user.target

Note o porto 8083: é ele que define através de qual porta a conexão via SSH reverso será realizada. Adicionamos na inicialização automática e iniciamos.

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

Você pode até verificar o status:

sudo systemctl status autossh.service

Agora, em nosso servidor VPS, se eu executar:

ssh -p 8083 khadas@localhost

Então eu chego no meu hardware de teste. E a partir do hardware também posso enviar logs e quaisquer dados via SSH para o meu servidor, o que é bastante conveniente.

Reunindo tudo

Teste de velocidade simultâneo em vários modems LTE
Ativação, vamos começar o desenvolvimento e depuração

Uf, acho que descrevi todos os nós. Agora é hora de juntar tudo isso em um só lugar. O código pode ser visto aqui.

Um ponto importante sobre o código: este projeto pode não ser executado assim, pois foi ajustado para uma tarefa específica de uma arquitetura específica. Embora eu forneça o código-fonte, ainda assim, o mais valioso eu explicarei aqui, diretamente no texto, caso contrário, não fará sentido.

No início, faço a inicialização do GPS, GPIO e inicio uma thread separada para o planejador.

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

O planejador é bastante simples: ele verifica se chegou a hora de enviar mensagens e qual é o status de erros atual. Se houver uma flag de erro, piscamos o 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)

O momento mais difícil deste projeto é manter a conexão SSH reversa em cada teste. Em cada teste, a configuração do gateway padrão e do servidor DNS é feita novamente. Como ninguém lê, saiba que o trem não anda sobre trilhos de madeira. Quem encontrar a surpresa ganhará um docinho.

Para isso, crio uma tabela de roteamento separada — set-mark 0x2 e uma regra para redirecionar o tráfego.

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")

Para mais detalhes sobre como isso funciona, você pode ler neste artigo..

Depois, entro em um loop infinito, onde a cada vez recebo a lista de modems conectados (para saber se a configuração da rede mudou).

network_list = getNetworklist()

Obter a lista de interfaces de rede é bastante simples.

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

Após obter a lista, atribuo endereços IP a todas as interfaces, como mencionei na imagem do capítulo sobre o modem.

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")

Em seguida, simplesmente percorro cada interface em um loop. E configuro cada interface.

	for iface in network_list:
		ConfigNetwork(iface)

def ConfigNetwork(iface):
#resetando todas as configurações
		cmd_run("sudo ip route flush all")
#Atribuindo o gateway padrão
		cmd_run("sudo route add default gw 192.168.8.1 " + iface)
#definindo o servidor DNS (isto é necessário para o speedtest)
		cmd_run ("sudo bash -c 'echo nameserver 8.8.8.8 > \/etc\/resolv.conf'")

Verifico a interface quanto à funcionalidade; se não houver rede, formulo erros. Se a rede estiver presente, é hora de agir!

Aqui estou configurando o roteamento ssh para esta interface (caso ainda não tenha sido feito), envio erros para o servidor, se chegou a hora, envio logs e por fim realizo o speedtest e salvo os logs em um arquivo csv.

if not NetworkAvalible():
....
#Aqui formulamos erros
....
else: #Rede disponível, viva, vamos trabalhar!
#Se tivermos uma interface problemática, onde ssh está em execução, mudamos ela
  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
#já que a rede está funcionando, vamos enviar tudo urgentemente!!!
    if ready_to_send:
      print ("**** Pronto para enviar!!!")
        if sendLogs():
          ready_to_send = False
        if error_status:
          SendErrors()
#e em seguida testamos a velocidade e salvamos os logs. 

Vale a pena mencionar a função de configuração do ssh reverso.

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")

E claro, é necessário adicionar toda esta beleza ao autoload. Para isso, crio um arquivo:

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

E escrevo nele:

[Unit]
Descrição=Teste de Velocidade do Modem
Requer=systemd-networkd-wait-online.service
Depois=systemd-networkd-wait-online.service
[Service]
Usuário=khadas
ExecStart=/usr/bin/python3.6 /home/khadas/modems_speedtest/networks.py
RestartSec=5
Reiniciar=sempre
[Install]
WantedBy=multi-user.target

Ativo o autoload e inicio!

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

Agora posso ver os logs do que está acontecendo com o comando:

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

Resultados

Agora, a parte mais importante: o que conseguimos como resultado? Apresento alguns gráficos que consegui registrar durante o desenvolvimento e depuração. Os gráficos foram construídos com o auxílio do gnuplot usando o seguinte 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"

A primeira experiência foi com o operador Tele2, que conduzi por alguns dias.

Teste de velocidade simultâneo em vários modems LTE

Aqui utilizei um servidor de medição dinâmico. As medições de velocidade funcionam, mas variam bastante; no entanto, uma média pode ser observada e obtida filtrando os dados, por exemplo, através da média móvel.

Mais tarde, construí uma série de gráficos para outros operadores de telecomunicações. O servidor de testes nesse caso já era único, e os resultados também foram muito interessantes.

Teste de velocidade simultâneo em vários modems LTE

Teste de velocidade simultâneo em vários modems LTE

Teste de velocidade simultâneo em vários modems LTE

Teste de velocidade simultâneo em vários modems LTE

Como pode ser visto, o tema é bastante amplo para pesquisas e processamento desses dados, e claramente não se limita a algumas semanas de trabalho. Mas...

Resultado do trabalho

O trabalho foi abruptamente encerrado devido a circunstâncias que fogem ao meu controle. Uma das fraquezas deste projeto, na minha opinião subjetiva, foi o modem, que não funcionava bem ao mesmo tempo que outros modems, e a cada inicialização apresentava essas dificuldades. Para esses fins, existe uma enorme quantidade de outros modelos de modems, que geralmente já têm o formato Mini PCI-e e são instalados dentro do dispositivo, sendo muito mais fáceis de configurar. Mas essa é uma história completamente diferente. O projeto foi interessante e fiquei muito contente por ter conseguido participar dele.

Teste de velocidade simultâneo em vários modems LTE

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster