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

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







O cliente queria avaliar a velocidade de todos os tipos de operadoras de telecomunicações em diferentes localizações geográficas, para entender qual operadora de celular é a melhor para ele ao instalar equipamentos usando uma conexão LTE, por exemplo, para transmissões de vídeo. Ao mesmo tempo, a tarefa tinha que ser resolvida da maneira mais simples e barata possível, sem equipamentos caros.



Devo dizer imediatamente que a tarefa não é a mais simples e exige mais conhecimento; vou lhe dizer quais os problemas que encontrei e como os resolvi. Então vamos.



Nota



Medir a velocidade de uma conexão LTE é uma questão muito difícil: você precisa escolher o equipamento e o método de medição certos, além de ter uma boa idéia da topologia e operação da rede celular. Além disso, a velocidade pode ser influenciada por vários fatores: número de assinantes por célula, condições climáticas, mesmo de célula para célula, a velocidade pode ser notavelmente diferente devido à topologia da rede. Em geral, esse é um problema com um grande número de incógnitas e apenas um operador de telecomunicações pode resolvê-lo corretamente.



Inicialmente, o cliente só queria dirigir o correio com os telefones das operadoras, fazer medições diretamente no telefone e depois anotar os resultados da medição de velocidade em um notebook. Minha solução para medir a velocidade das redes lte, embora não seja o ideal, resolve o problema.



Por falta de tempo, tomei decisões não em favor da conveniência ou praticidade, mas em favor da velocidade do desenvolvimento. Por exemplo, para acesso remoto, o ssh reverso foi gerado, em vez da VPN mais prática, para economizar tempo na configuração do servidor e de cada cliente individual.



Tarefa técnica



Conforme declarado no artigo Sem TK: por que o cliente não deseja : Não trabalhe sem TK! Nunca, em lugar nenhum!



A tarefa técnica foi bastante simples, vou expandi-la um pouco para entender o usuário final. A escolha de soluções e equipamentos técnicos foi ditada pelo cliente. Então, o próprio TK, depois de todas as aprovações:



vim2 lte- Huawei e3372h — 153 ( n). GPS-, UART. www.speedtest.net :







csv. - 6 . , GPIO.


Descrevi o TK de forma livre, após várias aprovações. Mas o significado da tarefa já é visível. O prazo para tudo foi dado uma semana. Mas, na realidade, durou três semanas. Isso se deve ao fato de que o fiz somente após o trabalho principal e nos finais de semana.



Aqui, gostaria de chamar sua atenção para o fato de que o cliente concordou com antecedência em usar o serviço e o hardware de medição de velocidade, o que limitou bastante minhas capacidades. O orçamento também era limitado, então nada foi comprado além disso. Então eu tive que jogar de acordo com essas regras.



Arquitetura e desenvolvimento



O esquema é simples e direto. Portanto, deixarei sem comentários especiais.







Decidi implementar todo o projeto em python, apesar de não ter nenhuma experiência em desenvolvimento nessa linguagem. Eu o escolhi porque havia vários exemplos e soluções prontos que poderiam acelerar o desenvolvimento. Portanto, peço a todos os programadores profissionais que não repreendam minha primeira experiência no desenvolvimento de python, e sempre fico feliz em ouvir críticas construtivas para melhorar minhas habilidades.



Também no processo, descobri que o python tem duas versões em execução 2 e 3; como resultado, parei na terceira.



Nós de hardware



Placa única vim2



Como máquina principal, recebi um vim2 de placa única







Uma mídia excelente e poderosa se combina para uma casa inteligente e a SMART-TV, mas extremamente inadequada para essa tarefa ou, digamos, pouco adequada. Por exemplo, seu sistema operacional principal é o Android e o Linux é um sistema operacional de passagem e, portanto, ninguém garante a operação de alta qualidade de todos os nós e drivers no Linux. E suponho que alguns dos problemas estejam relacionados aos drivers USB desta plataforma, portanto os modems não funcionaram conforme o esperado nesta placa. Ele também tem uma documentação muito pobre e dispersa; portanto, cada operação demorava muito tempo cavando nas docas. Mesmo o trabalho comum com o GPIO bebia muito sangue. Por exemplo, levei várias horas para configurar o trabalho com o LED. Mas, para ser objetivo, não era fundamentalmente importante que tipo de dispositivo de placa única, o principal é que ele deveria funcionar e ter portas USB.



Primeiro, preciso instalar o Linux nesta placa. Para não vasculhar a selva de documentação para todos, assim como para quem lida com esse dispositivo de placa única, estou escrevendo este capítulo.



Existem duas opções para instalar o Linux: em um cartão SD externo ou em um MMC interno. Lutei com o cartão à noite e não sabia como fazê-lo funcionar, então decidi instalá-lo no MMC, embora sem dúvida fosse muito mais fácil trabalhar com um cartão externo.



O firmware é descrito de forma distorcida aqui . Estou traduzindo de estranho para russo. Para exibir a placa, preciso conectar o UART do hardware. Eu o conectei da seguinte maneira.



  • Pino de ferramenta GND: <—> Pin17 do GPIO do VIMs
  • Pin de ferramenta TXD: <—> Pin18 do GPIO do VIMs (Linux_Rx)
  • Pino de ferramenta RXD: <—> Pin19 do GPIO do VIMs (Linux_Tx)
  • Pin de ferramenta VCC: <—> Pin20 do GPIO do VIMs






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



Para fazer upload deste firmware, preciso de certos utilitários. Leia mais sobre isso aqui . Não tentei fazer a atualização no Windows, mas preciso dizer algumas palavras sobre o firmware do Linux. Primeiro, instalarei os utilitários de acordo com as instruções.



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


Iii ... nada funciona. Passei algumas horas editando os scripts de instalação para que tudo estivesse corretamente instalado para mim. Não me lembro do que fiz lá, mas também daquele circo com cavalos. Por isso tem cuidado. Mas sem esses utilitários, não há motivo para torturar ainda mais o vim2. Melhor não mexer com ele!



Após sete círculos do inferno, configuração e instalação de scripts, recebi um pacote de utilitários em funcionamento. Conectei a placa via USB ao meu computador Linux e o UART também está conectado de acordo com o diagrama acima.

Estou configurando meu terminal minicom favorito como 115200, sem controle de erro de hardware ou software. E vamos começar.







Ao inicializar o VIM2 no terminal UART, pressione qualquer tecla, por exemplo, barra de espaço, para interromper a inicialização. Depois que a linha aparecer



kvim2# 


Eu insiro o comando:



kvim2# run update


No host de onde baixamos, eu executo:



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


Todo mundo, ufa. Eu perguntei, há Linux no quadro. Login / senha khadas: khadas.



Depois disso, pequenas configurações iniciais. Para mais trabalho, desabilito a senha do sudo (sim, não é seguro, mas é conveniente).



sudo visudo


Eu edito a linha na visualização e salvo



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


Depois, altero o local atual para que o horário seja em Moscou, caso contrário, será no GMT.



sudo timedatectl set-timezone Europe/Moscow


ou



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


Se você achar difícil, não use esta placa, pois o Raspberry Pi é melhor. Justo.



Modem Huawei e3372h - 153



Esse modem bebeu bem meu sangue e, de fato, tornou-se o gargalo de todo o projeto. Em geral, o nome “modem” para esses dispositivos não reflete a essência do trabalho: é uma combinação poderosa, esse hardware possui um dispositivo composto que finge ser um CD-ROM para instalar drivers e depois entra no modo de placa de rede.



Arquiteturalmente, do ponto de vista de um usuário Linux, depois de todas as configurações, fica assim: depois de conectar o modem, tenho a interface de rede eth *, que recebe o 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 sabe trabalhar no modo modem, que é controlado pelos comandos AT. Tudo seria muito mais fácil, criar conexões ppp para cada modem e depois operar com eles. Mas no meu caso "eu mesmo" (mais precisamente um mergulhador Linux de acordo com as regras do udev) cria uma interface eth e atribui um endereço IP a ele via dhcp.



Para não ficar mais confuso, proponho esquecer a palavra "modem" e dizer uma placa de rede e um gateway, porque na verdade é como conectar uma nova placa de rede a um gateway.

Quando há um modem, isso não causa problemas especiais, mas quando há mais de um modem, ou seja, n-pieces, a seguinte imagem da rede é exibida.







Ou seja, n placas de rede, com o mesmo endereço IP, cada uma com o mesmo gateway padrão. Mas, de fato, cada um deles está conectado ao seu próprio operador.



Inicialmente, eu tinha uma solução simples: usar o comando ifconfig ou ip para extinguir todas as interfaces e apenas ativar uma por vez e testá-la. A solução foi boa para todos, exceto que durante os momentos de troca, eu não consegui conectar ao dispositivo. E como a troca é frequente e rápida, na verdade não tive a oportunidade de me conectar.



Portanto, escolhi a maneira de alterar "manualmente" os endereços IP dos modems e continuar a direcionar o tráfego usando as configurações de roteamento.







Esse não foi o fim dos meus problemas com os modems: no caso de problemas de energia, eles caíam, era necessária uma boa fonte de alimentação estável para o hub USB. Esse problema foi resolvido soldando com força a fonte de alimentação diretamente no hub. Outro problema que enfrentei e que arruinou todo o projeto: após uma reinicialização ou uma inicialização a frio do dispositivo, nem todos os modems foram detectados e nem sempre, e por que isso aconteceu e por qual algoritmo eu não consegui instalar. Mas as primeiras coisas primeiro.



Para o modem funcionar corretamente, instalei o pacote usb-modeswitch.



sudo apt update
sudo apt install -y usb-modeswitch


Depois disso, o modem após a conexão será corretamente detectado e configurado pelo subsistema udev. Verifico simplesmente conectando o modem e certificando-me de que a rede esteja ativa.

Outro problema que não consegui resolver: como obter desse nome o nome do operador com o qual trabalhamos? O nome do operador está contido na interface da web do modem em 192.168.8.1. Esta é uma página da web dinâmica que recebe dados por meio de solicitações de ajax, portanto, você não pode apenas wget a página e analisar o nome. Então comecei a estudar como elaborar uma página da web etc., e percebi que estava fazendo algum tipo de besteira. Como resultado, ele cuspiu e começou a receber o operador usando a API do próprio Speedtest.



Muitas coisas seriam mais fáceis se o modem pudesse ser acessado através dos comandos AT. Seria possível reconfigurá-lo, criar uma conexão ppp, atribuir um IP, obter uma operadora, etc. Mas, infelizmente, trabalho com o que dei.



GPS



O receptor de GPS que recebi tinha interface e energia UART. Não era a melhor solução, mas, no entanto, era simples e funcional. O receptor era algo assim.







Para ser sincero, essa foi a primeira vez que trabalhei com um receptor GPS, mas como esperado, tudo foi inventado para nós há muito tempo. Então, apenas usamos soluções prontas.



Primeiro, ligo o 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


Então eu verifico o sucesso da operação.



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


Aparentemente, esse comando edita o devtree rapidamente, o que é muito conveniente.



Após o sucesso desta operação, reinicie e instale o daemon gps.



khadas@Khadas:~$ sudo reboot


Instalando o daemon gps. Eu instalo tudo e corro-o imediatamente para mais configurações.



sudo apt install gpsd gpsd-clients -y
sudo killall gpsd
 
/* GPS daemon stop/disable */
sudo systemctl stop gpsd.socket
sudo systemctl disable gpsd.socket


Editando o arquivo de configurações.



sudo vim /etc/default/gpsd


Eu instalo o UART no qual o GPS travará.



DEVICES="/dev/ttyS4"


E então ligamos tudo e começamos.



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


Depois disso, conecto o GPS.







O fio do GPS está nas mãos, os fios UART do depurador são visíveis sob os dedos.



Eu reinicio e verifico o GPS usando o programa gpsmon.







Nesta captura de tela, você não pode ver os satélites, mas a comunicação com o receptor GPS, e isso diz que está tudo bem.



No python, tentei muitas opções para trabalhar com esse daemon, mas decidi pelo que funcionava corretamente com o python 3.



Instale a biblioteca necessária.



sudo -H pip3 install gps3 


E esculpo o código do trabalho.



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 ("Wait gps counter = %d" % counter)
		if counter == 10:
			ErrorMessage(" GPS !!!")
			return "NA", "NA"
		time.sleep(1.0)
...
f __name__ == '__main__':
...
	#gps
	agps_thread = AGPS3mechanism()  # Instantiate AGPS3 Mechanisms
	agps_thread.stream_data()  # From localhost (), or other hosts, by example, (host='gps.ddns.net')
	agps_thread.run_thread()  # Throttle time to sleep after an empty lookup, default '()' 0.2 two tenths of a second


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



longitude, latitude = getPositionData(agps_thread)


E dentro de 1 a 10 segundos, receberei a coordenada ou não. Sim, tive dez tentativas para obter as coordenadas. Não é o ideal, torto e torto, mas funciona. Eu decidi fazer isso, porque o GPS pode pegar mal e nem sempre receber dados. Se você esperar que os dados sejam recebidos, se trabalhar em uma sala remota, o programa congelará neste local. Portanto, implementei uma opção não elegante.



Em princípio, haveria mais tempo, seria possível receber dados do GPS diretamente via UART, analisá-los em um fluxo separado e trabalhar com eles. Mas não havia tempo, daí o código feroz e feio. E sim, eu não tenho vergonha.



Diodo emissor de luz



A conexão do LED era 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 é escrita com o calcanhar esquerdo. Para combinar o número do pino de hardware e o número do pino no sistema operacional, você precisa executar o comando:



gpio readall


Uma tabela de correspondência de pinos no sistema e no quadro será exibida. Depois disso, já posso operar o pino no próprio sistema operacional. No meu caso, o LED está conectado ao GPIOH_5 .







Transfiro o pino GPIO para o modo de saída.



gpio -g mode 421 out


Eu escrevo zero.



gpio -g write 421 0


Eu escrevo um.



gpio -g write 421 1




Tudo está ligado, depois de gravar "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, chamo error_blink () e o LED pisca muito bem para nós.



Nós de software



API Speedtest



É uma grande alegria que o serviço speedtest.net tenha sua própria API python, você pode vê-lo no Github .



A boa notícia é que existem códigos-fonte que também podem ser visualizados. Como trabalhar com esta API (os exemplos mais simples) podem ser encontrados na seção correspondente .



Instale a biblioteca python com o seguinte comando.



sudo -H pip3 install speedtest-cli


Por exemplo, você pode até instalar o testador de velocidade no Ubuntu diretamente do representante. Este é o mesmo aplicativo python que você pode executar diretamente no console.



sudo apt install speedtest-cli -y


E meça a velocidade da sua Internet. Como resultado, como eu fiz. Eu tive que cavar os códigos-fonte deste speedtest para implementá-los mais completamente no meu projeto. Uma das tarefas mais importantes é obter o nome do operador de telecomunicações para substituí-lo na placa.



speedtest-cli

Retrieving speedtest.net configuration...

Testing from B***** (*.*.*.*)...

Retrieving speedtest.net server list...

Selecting best server based on ping...

Hosted by MTS (Moscow) [0.12 km]: 11.8 ms

Testing download speed................................................................................

Download: 7.10 Mbit/s

Testing upload speed......................................................................................................

Upload: 3.86 Mbit/s








import speedtest
from datetime import datetime
...
#    
#6053) MaximaTelecom (Moscow, Russian Federation)
servers = ["6053"]
# If you want to use a single threaded test
threads = None
s = speedtest.Speedtest()
#    
opos = '%(isp)s' % s.config['client']
s.get_servers(servers)
#     
testserver = '%(sponsor)s (%(name)s) [%(d)0.2f km]: %(latency)s ms' % s.results.server
# 
s.download(threads=threads)
# 
s.upload(threads=threads)
# 
s.results.share()

#       csv-.
#  GPS
longitude, latitude = getPositionData(agps_thread)
#  
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, também, tudo acabou não sendo tão simples, embora, ao que parece, muito mais fácil. Inicialmente, o parâmetro de servidores era igual a [] , dizem eles, escolhem o melhor servidor. Como resultado, eu tinha servidores aleatórios e, como você pode imaginar, velocidade flutuante. Este é um tópico bastante complexo, usando um servidor fixo, se sim, então estático ou dinâmico, requer pesquisa. Mas aqui está um exemplo de gráficos para medir a velocidade do operador Beeline com uma seleção dinâmica de um servidor de teste e um estaticamente fixo.





O resultado da medição da velocidade ao escolher um servidor dinâmico.





Resultado do teste de velocidade, com um servidor estritamente selecionado.



"Lã" durante o teste está lá e ali, e deve ser removido por métodos matemáticos. Mas com um servidor fixo, é um pouco menos e a amplitude é mais estável.

Em geral, este é um local de ótimas pesquisas. E eu mediria a velocidade do meu servidor usando o utilitário iperf. Mas mantemos o TK.



Enviando e-mails e erros



Tentei várias dezenas de opções diferentes para enviar e-mails, mas, como resultado, decidi o seguinte. Registrei uma caixa de correio no yandex e, em seguida, peguei este exemplo de envio de email . Eu verifiquei e implementei no programa. Este exemplo explora várias opções, incluindo o envio do gmail, etc. Eu não queria me preocupar em aumentar meu servidor de correio e não tinha tempo para isso, mas, como se viu depois, também foi em vão.



Os logs foram enviados de acordo com o agendador, se houvesse uma conexão , a cada 6 horas: às 00 horas, 06:00, 12:00 e 18:00. Enviei da seguinte maneira.



from send_email import *
...
message_log = "   №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, "  " + curdata + " " + urtime, files)
	except:
		print("Network problem for send mail")
		return False
	return True


Os erros também foram enviados inicialmente. Para começar, eles se acumularam na lista e os enviaram também usando o agendador, se houver uma conexão. No entanto, houve problemas com o fato de o yandex ter um limite no número de mensagens enviadas por dia (dor, tristeza e humilhação). Como pode haver um grande número de erros, mesmo em um minuto, era necessário recusar o envio de erros por correio. Portanto, lembre-se de enviar automaticamente pelos serviços Yandex esse problema.



Servidor de feedback



Para ter acesso a uma peça remota de hardware e poder ajustá-la e reconfigurá-la, eu precisava de um servidor externo. Em geral, com toda a justiça, seria correto enviar todos os dados para o servidor e criar todos os belos gráficos na interface da web. Mas não tudo ao mesmo tempo.



Eu escolhi o ruvds.com como o VPS . O servidor mais simples pode ser usado. E, em geral, para meus propósitos, isso seria suficiente para os olhos. Mas como não estava pagando pelo servidor do bolso, decidi tomá-lo com uma pequena margem para que bastasse se implementássemos uma interface da web, nosso próprio servidor SMTP, VPN, etc. Além disso, ser capaz de configurar um bot do Telegram e não ter problemas com seu bloqueio. Portanto, escolhi Amsterdã e os seguintes parâmetros.







Como forma de se comunicar com uma peça de hardware, o vim2 escolheu uma conexão ssh reversa e, como a prática demonstrou, não é a melhor. Se a conexão for interrompida, o servidor reterá a porta e será impossível conectar-se a ela por algum tempo. Portanto, ainda é melhor usar outros métodos de comunicação, por exemplo, vpn. No futuro, eu queria mudar para vpn, mas não tinha tempo.



Não entrarei nos detalhes da configuração de um firewall, da limitação de direitos, da desativação de conexões ssh root e de outras verdades comuns das configurações de VPS. Eu gostaria de acreditar que você já sabe tudo. Para uma conexão remota, crio um novo usuário no servidor.



adduser vimssh


Em nosso hardware, eu gero chaves de conexão ssh.



ssh-keygen


E eu os copio para o nosso servidor.



ssh-copy-id vimssh@host.com


Em nosso hardware, crio uma conexão automática do ssh reverso a cada inicialização. Preste atenção à porta 8083: ela determina em qual porta vou conectar via ssh reverso. Adicione à inicialização e inicie.



[Unit]

Description=Auto Reverse SSH

Requires=systemd-networkd-wait-online.service

After=systemd-networkd-wait-online.service

[Service]

User=khadas

ExecStart=/usr/bin/ssh -NT -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 -CD 8080 -R 8083:localhost:22 vimssh@host.com

RestartSec=5

Restart=always

[Install]

WantedBy=multi-user.target








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


Você pode até ver o status:



sudo systemctl status autossh.service


Agora, no nosso servidor VPS, se você executar:



ssh -p 8083 khadas@localhost


Então eu chego ao meu provete. E do pedaço de ferro também posso enviar logs e quaisquer dados via ssh para o meu servidor, o que é muito conveniente.



Juntando tudo





Ligando, começamos a desenvolver e depurar o



Fuh, bem, tudo parece ter descrito todos os nós. Agora é hora de juntar tudo. O código pode ser visto aqui .



Um ponto importante com o código: Este projeto como este "vlob" pode não iniciar, pois foi aprimorado em uma tarefa específica de uma arquitetura específica. Embora eu forneça o código fonte, ainda analisarei o mais valioso aqui, diretamente no texto, caso contrário, é completamente incompreensível.



No começo, eu tenho inicialização de gps, gpio e lançamento de um thread do agendador separado.



#  
pShedulerThread = threading.Thread(target=ShedulerThread, args=(1,))
pShedulerThread.start()


O planejador é bastante simples: parece ver se chegou a hora de enviar mensagens e qual é o status do erro agora. Se houver um sinalizador de erro, pisque 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 ponto mais difícil deste projeto é manter a conexão ssh reversa em todos os testes. Em cada teste, o gateway padrão e o servidor DNS são reconfigurados. Como ninguém lê de qualquer maneira, saiba que o trem não rola sobre trilhos de madeira. Quem encontrar um ovo de Páscoa terá um gosto doce.



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


Você pode ler mais sobre como isso funciona neste artigo .



Então eu entro em um loop sem fim, onde sempre que obtemos uma lista de modems conectados (para descobrir se a configuração da rede mudou).



network_list = getNetworklist()


Obter uma 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


Depois de receber a lista, atribuo endereços IP a todas as interfaces, como mostrei na figura no 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")


Então eu apenas passo por cada interface em um loop. E eu configuro cada interface.



	for iface in network_list:
		ConfigNetwork(iface)


def ConfigNetwork(iface):
#  
		cmd_run("sudo ip route flush all")
#   
		cmd_run("sudo route add default gw 192.168.8.1 " + iface)
# dns- (    speedtest)
		cmd_run ("sudo bash -c 'echo nameserver 8.8.8.8 > /etc/resolv.conf'")


Verifico a interface quanto à operacionalidade, se não houver rede, gero erros. Se houver uma rede, é hora de agir!



Aqui eu configuro o roteamento ssh para essa interface (se não tiver sido feito), envio erros para o servidor, se chegar a hora, envio logs e, finalmente, executo um speedtest e salve os logs em um arquivo csv.



if not NetworkAvalible():
....
#   
....
else: # , , !
#    ,   ssh,   
  if (sshint == lastbanint or sshint =="free"):
    print("********** Setup SSH ********************")
    if sshint !="free":
      md_run("sudo ip route del default via 192.168.8.1 dev " + sshint +" table 102")
    SetupReverseSSH(iface)
    sshint = iface
#  ,     !!!
    if ready_to_send:
      print ("**** Ready to send!!!")
        if sendLogs():
          ready_to_send = False
        if error_status:
          SendErrors()
#      . 


Exceto pela função de configuração ssh reversa.



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, você precisa adicionar toda essa beleza à inicialização. Para fazer isso, eu crio um arquivo:



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


E escrevo: ligo o carregamento automático e começo!



[Unit]

Description=Modem Speed Test

Requires=systemd-networkd-wait-online.service

After=systemd-networkd-wait-online.service

[Service]

User=khadas

ExecStart=/usr/bin/python3.6 /home/khadas/modems_speedtest/networks.py

RestartSec=5

Restart=always

[Install]

WantedBy=multi-user.target








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


Agora eu posso assistir os logs do que está acontecendo usando o comando:



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


resultados



Bem, agora o mais importante é o que aconteceu como resultado? Aqui estão alguns gráficos que eu consegui capturar durante o processo de desenvolvimento e depuração. Os gráficos foram construídos usando o gnuplot com 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 a operadora Tele2, que passei por vários dias.







Eu usei um servidor de medição dinâmico aqui. As medições de velocidade funcionam, mas flutuam muito, no entanto, ainda existe algum valor médio visível, e pode ser obtido filtrando os dados, por exemplo, com uma média móvel.



Mais tarde, construí uma série de gráficos para outras operadoras de telecomunicações. Nesse caso, já havia um servidor de teste e os resultados também são muito interessantes.



















Como você pode ver, o tópico é muito extenso para pesquisa e processamento desses dados e claramente não dura algumas semanas de trabalho. Mas…



Resultado do trabalho



O trabalho foi concluído abruptamente devido a circunstâncias fora do meu controle. Um dos pontos fracos deste projeto, na minha opinião subjetiva, era o modem, que realmente não queria trabalhar simultaneamente com outros modems, e fazia esses truques a cada inicialização. Para esses fins, há um grande número de outros modelos de modems, geralmente eles já têm o formato Mini PCI-e e são instalados dentro do dispositivo e são muito mais fáceis de configurar. Mas essa é uma história completamente diferente. O projeto foi interessante e ficou muito feliz por termos conseguido participar.






All Articles