Speedtest simultaneo su diversi modem LTE

Durante il periodo di quarantena, mi è stato proposto di partecipare allo sviluppo di un dispositivo per misurare la velocità dei modem LTE per diversi operatori di telefonia mobile.

Speedtest simultaneo su diversi modem LTE

Il cliente voleva valutare la velocità di vari operatori di telefonia in diverse località geografiche, per capire quale operatore fosse il più adatto per installare attrezzature che utilizzassero connessioni LTE, ad esempio per trasmissioni video. Era importante risolvere il problema nel modo più semplice ed economico possibile, senza attrezzature costose.

Dico subito che la sfida non è delle più semplici e richiede conoscenze tecniche, e vi racconterò quali problemi ho incontrato e come li ho risolti. Dunque, cominciamo.

Nota

Misurare la velocità di una connessione LTE è un compito complesso: è necessario scegliere correttamente l'hardware e la metodologia di misurazione, oltre a capire bene la topologia e il funzionamento della rete mobile. Inoltre, diversi fattori possono influenzare la velocità: il numero di utenti sulla cellula, le condizioni meteorologiche, e anche da cellula a cellula la velocità può variare notevolmente a causa della topologia della rete. In generale, si tratta di un problema con un gran numero di incognite, e solo un operatore di telecomunicazioni può risolverlo correttamente.

Inizialmente, il cliente voleva semplicemente far misurare la velocità da un corriere con i telefoni degli operatori, effettuando le misurazioni direttamente sul telefono e registrando i risultati su un quaderno. La mia soluzione per misurare la velocità delle reti LTE, pur non essendo perfetta, risolve il problema posto.

A causa della mancanza di tempo, ho dovuto prendere decisioni a favore della rapidità di sviluppo piuttosto che del comfort o della praticità. Ad esempio, per l'accesso remoto ho impostato un SSH inverso, invece di una VPN più pratica, per risparmiare tempo nella configurazione del server e di ogni singolo client.

Specifiche tecniche

Come scritto nell'articolo Senza un documento di requisiti: perché il cliente non lo vuole: Non lavorate senza un documento di requisiti! Mai, da nessuna parte!

Il documento di requisiti era piuttosto semplice, lo espanderò un po' per chiarire al termine l'utente finale. La scelta delle soluzioni tecniche e dell'hardware era dettata dal cliente. Quindi, il documento di requisiti, dopo tutte le approvazioni:

Basato su un computer a scheda singola vim2 creare un tester di velocità per la connessione LTE tramite modem Huawei e3372h — 153 di diversi operatori di telecomunicazioni (da uno a n). È necessario anche ricevere le coordinate da un ricevitore GPS collegato tramite UART. Le misurazioni di velocità devono essere effettuate utilizzando il servizio www.speedtest.net e compilarle in una tabella del tipo:

Speedtest simultaneo su diversi modem LTE

Tabella in formato csv. Successivamente inviare via email questa tabella ogni 6 ore. In caso di errori, far lampeggiare un LED collegato a GPIO.

Il documento di requisiti l'ho descritto in forma libera, dopo molte approvazioni. Ma il senso del compito è già chiaro. Il tempo limite era di una settimana per tutto. Ma in realtà si è allungato a tre settimane. Questo considerando che lo facevo solo dopo il lavoro principale e nei fine settimana.

Qui voglio sottolineare che il cliente aveva già specificato l'uso di un servizio di misurazione della velocità e l'hardware, il che ha limitato fortemente le mie possibilità. C'era anche un budget limitato, quindi non è stato acquistato nulla di extra. Dunque, ho dovuto seguire queste regole.

Architettura e sviluppo

Lo schema è semplice e ovvio. Quindi lo lascerò senza particolari commenti.

Speedtest simultaneo su diversi modem LTE

Ho deciso di implementare l'intero progetto in Python, nonostante non avessi alcuna esperienza pregressa in questo linguaggio. L'ho scelto poiché c'erano moltissimi esempi e soluzioni già pronte, che potevano velocizzare lo sviluppo. Pertanto, chiedo a tutti i programmatori professionisti di non criticare il mio primo tentativo di sviluppo in Python, e sono sempre pronto ad ascoltare critiche costruttive per migliorare le mie competenze.

Durante il processo ho anche scoperto che Python ha due versioni principali, 2 e 3, e alla fine mi sono concentrato sulla terza.

Moduli hardware

Schemario vim2

Come macchina principale, mi è stato fornito un computer a scheda singola vim2

Speedtest simultaneo su diversi modem LTE

Ottimo, potente media-combinazione per la casa intelligente e SMART-TV, ma sorprendentemente poco adatto per questa attività, o per essere più chiari, solo poco adatto. Ad esempio, il suo sistema operativo principale è Android, mentre Linux è un sistema operativo secondario, quindi non si può garantire il corretto funzionamento di tutti i componenti e driver su Linux. Ritengo che alcuni dei problemi siano legati ai driver USB di questa piattaforma, pertanto i modem non funzionavano come previsto su questa scheda. Inoltre, la documentazione è molto scarsa e disorganizzata, quindi ogni operazione richiedeva molto tempo per essere approfondita. Anche il lavoro semplice con GPIO ha richiesto un notevole sforzo. Ad esempio, per configurare il funzionamento di un LED, mi sono volute diverse ore. Tuttavia, per essere obiettivo, non era fondamentale quale scheda sia, l'importante è che funzionasse e avesse porte USB.

Per cominciare, devo installare Linux su questa scheda. Per evitare di cercare tra fiumi di documentazione, e per coloro che vogliono comprendere questa scheda, scrivo questo capitolo.

Ci sono due opzioni per installare Linux: su una scheda SD esterna o sulla MMC interna. Ho impiegato un po' di tempo con la scheda e non sono riuscito a farla funzionare, quindi ho deciso di installare su MMC, anche se senza dubbio lavorare con una scheda esterna sarebbe stato molto più semplice.

Sulla programmazione è raccontato male qui. Traduco da un linguaggio strano al russo. Per flashare la scheda, devo collegare un UART hardware. L'ho collegato nel seguente modo.

  • Tool Pin GND: Pin17 del GPIO di VIM
  • Tool Pin TXD: Pin18 del GPIO di VIM (Linux_Rx)
  • Tool Pin RXD: Pin19 del GPIO di VIM (Linux_Tx)
  • Tool Pin VCC: Pin20 del GPIO di VIM

Speedtest simultaneo su diversi modem LTE

Dopo di che, ho scaricato il firmware da qui. La versione specifica del firmware VIM1_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.

Per caricare questo firmware, ho bisogno degli strumenti. Di questo si parla più dettagliatamente qui. Non ho provato a programmare sotto Windows, ma devo dire due parole sul flashing sotto Linux. Per prima cosa, installerò gli strumenti secondo le istruzioni.

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

E… niente funziona. Ho speso un paio d'ore a modificare gli script di installazione affinché tutto si installasse correttamente. Cosa ho fatto non lo ricordo, ma è stata pure una vera e propria farsa. Quindi fate attenzione. Ma senza questi strumenti non ha senso continuare a sbattere su vim2. È meglio non occuparsene affatto!

Dopo sette cerchi dell'inferno, configurazione degli script e installazione, ho ottenuto un pacchetto di strumenti funzionanti. Ho collegato la scheda tramite USB al mio computer Linux, e ho anche collegato l UART secondo lo schema sopra.
Configuro il mio terminale preferito minicom a una velocità di 115200, senza controllo hardware e software degli errori. E iniziamo.

Speedtest simultaneo su diversi modem LTE

Durante il boot di VIM2 nel terminale UART premo un tasto qualsiasi, ad esempio lo spazio, per interrompere il caricamento. Dopo che appare la riga

kvim2# 

Inserisco il comando:

kvim2# run update

Sul host da cui carichiamo, eseguo:

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

Ecco, fuh. Flashato, sulla scheda c'è Linux. Login/password khadas:khadas.

Dopo di che alcune configurazioni iniziali. Per il lavoro successivo disabilito la password per sudo (sì, non è sicuro, ma è comodo).

sudo visudo

Modifico la riga in questo modo e salvo

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

Dopo di che cambio la locale attuale, così che l'ora sia secondo Mosca, altrimenti sarà secondo Greenwich.

sudo timedatectl set-timezone Europe/Moscow

oppure

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

Se ti è sembrato complicato, non usare questa scheda, meglio Raspberry Pi. Seriamente.

Modem Huawei e3372h — 153

Questo modem mi ha dato un bel po' di grattacapi e, in effetti, è diventato il collo di bottiglia del progetto. In realtà, il termine "modem" per questi dispositivi non riflette affatto la loro funzionalità: è una macchina potente, questo dispositivo ha una configurazione composta, che si presenta come un CD-ROM per installare i driver, per poi passare a una modalità di scheda di rete.

Architettonicamente, dal punto di vista dell'utente Linux dopo tutte le configurazioni, si presenta così: dopo il collegamento del modem, appare un'interfaccia di rete eth*, che riceve un indirizzo IP 192.168.8.100 tramite DHCP, e un gateway predefinito 192.168.8.1.

E il punto principale! Questo modello di modem non sa funzionare in modalità modem controllata da comandi AT.Sarebbe stato molto più semplice creare connessioni ppp per ogni modem e poi gestirli. Ma nel mio caso, il dispositivo stesso (o meglio, i driver Linux secondo le regole di udev) crea un'interfaccia eth e assegna un indirizzo IP tramite DHCP.

Per non confonderci ulteriormente, suggerisco di dimenticare la parola "modem" e parlare di una scheda di rete e di un gateway, poiché in realtà si tratta di collegare una nuova scheda di rete con un gateway.
Quando c'è un modem, non ci sono problemi particolari, ma quando ce ne sono più di uno, precisamente n pezzi, allora si crea la seguente situazione di rete.

Speedtest simultaneo su diversi modem LTE

Cioè, n schede di rete, con un solo indirizzo IP, ognuna con lo stesso gateway predefinito. Ma in effetti, ognuno di essi è connesso al proprio operatore.

Inizialmente avevo una soluzione semplice: usando il comando ifconfig o ip spegnere tutte le interfacce e semplicemente accenderne una alla volta testando ciascuna. La soluzione andava bene, tranne per il fatto che nei momenti di commutazione non riuscivo a connettermi al dispositivo. E poiché le commutazioni sono frequenti e veloci, in effetti non avevo la possibilità di collegarmi affatto.

Quindi ho scelto di cambiare manualmente gli indirizzi IP dei modem e continuare a instradare il traffico tramite le impostazioni di routing.

Speedtest simultaneo su diversi modem LTE

Così i miei problemi con i modem non erano finiti: in caso di problemi di alimentazione, si disconnettevano, era necessaria una buona alimentazione stabile per l'hub USB. Ho risolto questo problema saldando direttamente l'alimentazione all'hub. Un altro problema con cui mi sono confrontato e che ha rovinato l'intero progetto è stato che dopo un riavvio o un avvio a freddo, non tutti i modem venivano riconosciuti e non sempre, e non sono riuscito a capire il motivo e l'algoritmo dietro questo. Ma procediamo in ordine.

Per un corretto funzionamento del modem, ho installato il pacchetto usb-modeswitch.

sudo apt update
sudo apt install -y usb-modeswitch

Dopo di che, il modem sarà correttamente riconosciuto e configurato dal sottosistema udev una volta collegato. Verifico semplicemente collegando il modem e assicurandomi che la rete appaia.
Un altro problema che non sono riuscito a risolvere: come ottenere il nome dell'operatore con cui lavoriamo da questo modem? Il nome dell'operatore si trova nell'interfaccia web del modem all'indirizzo 192.168.8.1. Questa è una pagina web dinamica, che riceve dati tramite richieste ajax, quindi non è possibile semplicemente fare un wget della pagina e strappare il nome. Quindi ho iniziato a vedere come lavorare su una pagina web ecc., e ho capito che stavo facendo qualcosa di insensato. Alla fine ho desistere e ho iniziato a ottenere il nome dell'operatore utilizzando l'API di Speedtest.

Molto sarebbe stato più semplice se il modem avesse avuto accesso tramite comandi AT. Avrei potuto riconfigurarlo, creare una connessione ppp, assegnare un IP, ottenere il nome dell'operatore e così via. Ma sfortunatamente, lavoro con ciò che mi è stato dato.

GPS

Il ricevitore GPS che mi è stato fornito aveva un'interfaccia UART e alimentazione. Non era la soluzione migliore, ma comunque funzionante e semplice. Il ricevitore era di questo tipo.

Speedtest simultaneo su diversi modem LTE

A dire il vero, era la prima volta che lavoravo con un ricevitore GPS, ma come previsto, tutto era già stato pensato per noi. Quindi utilizziamo semplicemente soluzioni pronte.

Per cominciare, attivo uart_AO_B (UART_RX_AO_B, UART_TX_AO_B) per collegare il GPS.

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

Dopo controllo il successo dell'operazione.

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

Questo comando, a quanto pare, modifica al volo il devtree, il che è piuttosto comodo.

Dopo il successo di questa operazione, riavviamo e installiamo il demone gps.

khadas@Khadas:~$ sudo reboot

Installazione del demone gps. Installo tutto e poi lo disabilito subito per ulteriori configurazioni.

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

/* GPS daemon stop/disable */
sudo systemctl stop gpsd.socket
sudo systemctl disable gpsd.socket

Modifico il file di configurazione.

sudo vim /etc/default/gpsd

Imposto l'UART a cui sarà collegato il GPS.

DEVICES="/dev/ttyS4"

E poi attiviamo tutto e avviamo.

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

Dopo di che, collego il GPS.

Speedtest simultaneo su diversi modem LTE

In mano c'è il cavo GPS, sotto le dita si vedono i cavi UART del debugger.

Riavvio e verifico il funzionamento del GPS con il programma gpsmon.

Speedtest simultaneo su diversi modem LTE

In questo screenshot non si vedono satelliti, ma si può vedere la comunicazione con il ricevitore GPS, e questo indica che tutto va bene.

Ho provato molte varianti per lavorare con questo demone in python, ma mi sono fermato su quella che funzionava correttamente con python 3.

Installo la libreria necessaria.

sudo -H pip3 install gps3 

E scrivo il codice per interagire.

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("Errore del ricevitore GPS!!!")
			return "NA", "NA"
		time.sleep(1.0)
...
if __name__ == '__main__':
...
	#gps
	agps_thread = AGPS3mechanism()  # Instanzia i meccanismi AGPS3
	agps_thread.stream_data()  # Da localhost (), o altri host, ad esempio, (host='gps.ddns.net')
	agps_thread.run_thread()  # Tempo di throttling per dormire dopo una ricerca vuota, default '()' 0.2 due decimi di secondo

Se ho bisogno di ottenere le coordinate, lo faccio con la seguente chiamata:

longitude, latitude = getPositionData(agps_thread)

E entro 1-10 secondi otterrò le coordinate o meno. Sì, ho avuto dieci tentativi per ottenere le coordinate. Non è ottimale, un po' goffo e imperfetto, ma funziona. Ho deciso di fare così perché il GPS può avere delle difficoltà e non sempre ottenere i dati. Se aspetto di ricevere i dati, nel caso di un funzionamento in un ambiente chiuso, il programma si bloccerebbe in quel punto. Perciò ho implementato una soluzione non elegante.

In generale, se avessi avuto più tempo, avrei potuto ricevere i dati GPS direttamente tramite UART, analizzarli in un thread separato e lavorarci. Ma non avevo tempo affatto, quindi ecco un codice bruttissimo. E sì, non mi vergogno.

LED

La connessione del LED è stata sia semplice che complicata. La principale difficoltà è che il numero del pin nel sistema non corrisponde al numero del pin sulla scheda e perché la documentazione è scritta male. Per mappare il numero del pin hardware e il numero del pin nel sistema operativo, devo eseguire il comando:

gpio readall

Verrà visualizzata una tabella di corrispondenza tra il pin nel sistema e sulla scheda. Dopo di che posso già operare sul pin nel sistema operativo. Nel mio caso, il LED è collegato a GPIOH_5.

Speedtest simultaneo su diversi modem LTE

Passo il pin GPIO in modalità output.

gpio -g mode 421 out

Scrivo zero.

gpio -g write 421 0

Scrivo uno.

gpio -g write 421 1

Speedtest simultaneo su diversi modem LTE
Tutto si accende dopo aver scritto «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)

Ora, in caso di errori, chiamo error_blink() e il LED lampeggia in modo piacevole.

Moduli software

Speedtest API

Grande gioia, il servizio speedtest.net ha la propria python-API, che si può vedere su Github.

È bello che ci siano i codici sorgente, che possono essere esaminati anch'essi. Come utilizzare questa API (esempi semplici) può essere visualizzato in sezione corrispondente.

Installo la libreria python con il seguente comando.

sudo -H pip3 install speedtest-cli

Per esempio, puoi semplicemente installare speedtest su Ubuntu direttamente dai repository. È lo stesso programma python, che poi puoi lanciare direttamente dal terminale.

sudo apt install speedtest-cli -y

E misurare la velocità della tua connessione internet.

speedtest-cli
Recuperando la configurazione di speedtest.net...
Test in corso da B***** (*.*.*.*)...
Recuperando l'elenco dei server di speedtest.net...
Selezione del server migliore in base al ping...
Ospitato da MTS (Mosca) [0,12 km]: 11,8 ms
Test della velocità di download................................................................................
Download: 7,10 Mbit/s
Test della velocità di upload......................................................................................................
Upload: 3,86 Mbit/s

Di conseguenza, come ho fatto io. Ho dovuto entrare nei codici sorgente di questo speedtest, per integrarli meglio nel mio progetto. Una delle sfide principali è ottenere anche il nome dell'operatore di rete, da inserire nella tabella.

import speedtest
from datetime import datetime
...
# Indico un server specifico per il test
#6053) MaximaTelecom (Mosca, Federazione Russa)
servers = ["6053"]
# Se vuoi utilizzare un test a thread singolo
threads = None
s = speedtest.Speedtest()
# otteniamo il nome dell'operatore di telefonia mobile
opos = '%(isp)s' % s.config['client']
s.get_servers(servers)
# otteniamo una stringa testuale con i parametri del server
testserver = '%(sponsor)s (%(name)s) [%(d)0.2f km]: %(latency)s ms' % s.results.server
# test di download
s.download(threads=threads)
# test di upload
s.upload(threads=threads)
# otteniamo i risultati
s.results.share()

# Dopodiché, si forma una stringa per la scrittura nel file csv.
# otteniamo la posizione GPS
longitude, latitude = getPositionData(agps_thread)
# tempo e data
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"
# qui avviene la scrittura nel file di log

Qui è risultato non essere così semplice, anche se sembrava così. Inizialmente, il parametro servers era impostato a [], quindi scegli il migliore server. Di conseguenza, avevo server casuali, e come è facile intuire, velocità variabile. È un argomento abbastanza complesso, utilizzare un server fisso, e se sì, statico o dinamico, richiede studio. Ma ecco un esempio dei grafici delle misurazioni della velocità dell'operatore Beeline con la scelta dinamica del server di test e un server statico fissato.

Speedtest simultaneo su diversi modem LTE
Risultato della misurazione della velocità con scelta di un server dinamico.

Speedtest simultaneo su diversi modem LTE
Risultato del test di velocità, con un server rigorosamente scelto.

C'è 'rumore' nei test in entrambi i casi, e deve essere rimosso con metodi matematici. Ma con un server fissato, c'è un po' meno rumore e l'ampiezza è più stabile.
In generale, questo è un luogo di grandi ricerche. E io avrei condotto misurazioni della velocità al mio server, tramite lo strumento iperf. Ma ci atteniamo alle specifiche.

Invio di email e errori

Per l'invio di email ho provato diverse decine di opzioni, ma alla fine ho optato per la seguente. Ho registrato un'email su yandex e poi ho preso questo esempio di invio email. L'ho controllato e integrato nel programma. In questo esempio vengono considerati vari opzioni, incluso l'invio da gmail, ecc. Non avevo voglia di configurare il mio server di posta e non avevo tempo per farlo, ma come si è rivelato, era stato un errore inutile.

L'invio dei log avveniva tramite un pianificatore, in caso di connessione, ogni 6 ore: a mezzanotte, alle 6 di mattina, a mezzogiorno e alle 6 di sera. Inviavo nel modo seguente.

from send_email import *
...
message_log = "Log del test della scheda 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, "Log per " + curdata + " " + сurtime, files)
	except:
		print("Problema di rete durante l'invio della mail")
		return False
	return True

Gli errori venivano inizialmente inviati. All'inizio venivano accumulati in un elenco e poi inviati anche tramite il pianificatore, quando era disponibile la connessione. Tuttavia, successivamente ci sono stati problemi poiché Yandex ha un limite sul numero di messaggi inviati al giorno (è un dolore, una tristezza e un'umiliazione). Poiché gli errori potevano accumularsi anche in un minuto, ho dovuto rinunciare all'invio degli errori via email. Quindi, tenete presente che, con l'invio automatico tramite i servizi di Yandex, c'è questo problema.

Server di feedback

Per avere accesso all'hardware remoto e avere la possibilità di riconfigurarlo, avevo bisogno di un server esterno. In realtà, a dire il vero, sarebbe corretto inviare tutti i dati a un server e costruire tutte le belle grafiche nell'interfaccia web. Ma non tutto insieme.

Come VPS ho scelto ruvds.com. Si sarebbe potuto optare per il server più semplice. In generale, per i miei scopi, questo sarebbe stato più che sufficiente. Ma poiché non pagavo il server di tasca mia, ho deciso di prendere qualcosa con un piccolo margine, nel caso avessimo dovuto implementare l'interfaccia web, il nostro server SMTP, VPN, ecc. Inoltre, volevo configurare un bot di Telegram e non avere problemi con eventuali blocchi. Perciò ho scelto Amsterdam e le seguenti specifiche.

Speedtest simultaneo su diversi modem LTE

Come metodo di collegamento con l'hardware, ho scelto una connessione SSH inversa, e come ha mostrato la pratica, non è stata la scelta migliore. In caso di interruzione della connessione, il server mantiene la porta occupata e non è possibile riconnettersi per un certo periodo. Pertanto, sarebbe meglio utilizzare altri metodi di collegamento, come VPN. In futuro, volevo passare alla VPN, ma non ho avuto tempo.

Non entrerò nei dettagli della configurazione del firewall, delle restrizioni sui diritti, della disabilitazione della connessione SSH root e di altre nozioni basilari sulla configurazione di un VPS. Spero che lo sappiate già. Per la connessione remota, creo un nuovo utente sul server.

adduser vimssh

Sul nostro hardware genero le chiavi della connessione SSH.

ssh-keygen

E le copio sul nostro server.

ssh-copy-id vimssh@host.com

Sul nostro hardware creo una connessione automatica SSH inversa ad ogni avvio.

[Unit]
Descrizione=Auto Reverse SSH
Richiede=systemd-networkd-wait-online.service
Dopo=systemd-networkd-wait-online.service
[Service]
Utente=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

Notate la porta 8083: è quella che determina la porta utilizzata per la connessione SSH inversa. Aggiungiamo all'avvio automatico e avviamo.

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

Si può anche controllare lo stato:

sudo systemctl status autossh.service

Ora, sul nostro server VPS, se eseguo:

ssh -p 8083 khadas@localhost

Entro nel mio hardware di test. E da questo hardware posso anche inviare log e qualsiasi dato tramite SSH al mio server, il che è molto comodo.

Mettiamo tutto insieme

Speedtest simultaneo su diversi modem LTE
Accensione, iniziamo lo sviluppo e il debug

Fuh, bene, credo di aver descritto tutti i nodi. Ora è il momento di unire tutto in un'unica soluzione. Puoi vedere il codice qui.

Un punto importante sul codice: questo progetto potrebbe non partire così com'è, poiché è stato specificamente progettato per un compito particolare e un'architettura specifica. Anche se fornisco i sorgenti, spiegherò comunque le parti più rilevanti qui, direttamente nel testo, altrimenti risulterebbe completamente incomprensibile.

All'inizio inizializzo GPS, GPIO e avvio un thread separato del pianificatore.

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

Il pianificatore è abbastanza semplice: controlla se è arrivato il momento di inviare messaggi e quale sia lo stato degli errori. Se c'è un flag di errore, facciamo lampeggiare il 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)

Il momento più complicato di questo progetto è mantenere la connessione SSH inversa in ogni test. In ciascun test si procede a una nuova configurazione del gateway predefinito e del DNS. Poiché nessuno legge, sappiate che il treno non corre su rotaie di legno. Chi trova l'uovo di Pasqua, riceve un dolcetto.

Per questo creo una tabella di routing separata —set-mark 0x2 e una regola per reindirizzare il traffico.

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

Puoi leggere di più su come funziona in questo articolo.

Dopo di che passo a un ciclo infinito, dove ad ogni iterazione otteniamo l'elenco dei modem connessi (per sapere se, per caso, la configurazione della rete è cambiata).

network_list = getNetworklist()

Ottenere l'elenco delle interfacce di rete è abbastanza semplice.

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

Dopo aver ottenuto l'elenco, assegno gli indirizzi IP a tutte le interfacce, come indicato nell'immagine del capitolo sui 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")

Poi, semplicemente, in un ciclo, passo attraverso ciascuna interfaccia. E configuro ogni interfaccia.

	for iface in network_list:
		ConfigNetwork(iface)

def ConfigNetwork(iface):
#ripristina tutte le impostazioni
		cmd_run("sudo ip route flush all")
#Assegna il gateway predefinito
		cmd_run("sudo route add default gw 192.168.8.1 " + iface)
#imposta il server dns (necessario per il funzionamento dello speedtest)
		cmd_run ("sudo bash -c 'echo nameserver 8.8.8.8 > /etc/resolv.conf'")

Controllo l'interfaccia per verificarne il funzionamento; se non c'è rete, genero errori. Se la rete è presente, è tempo di agire!

Qui imposto la routizzazione ssh su questa interfaccia (se non è già stata fatta), invio gli errori al server, se è giunto il momento, invio i log e alla fine eseguo lo speedtest, salvando i log in un file csv.

if not NetworkAvalible():
....
#Qui formiamo gli errori
....
else: #C'è rete, evviva, lavoriamo!
#Se abbiamo un'interfaccia problematica, su cui è ssh, la cambiamo
  if (sshint == lastbanint or sshint =="free"):
    print("********** Imposta SSH ********************")
    if sshint !="free":
      cmd_run("sudo ip route del default via 192.168.8.1 dev " + sshint +" table 102")
    SetupReverseSSH(iface)
    sshint = iface
#dal momento che la rete funziona, andiamo a inviare tutto quanto!!!
    if ready_to_send:
      print ("**** Pronto per inviare!!!")
        if sendLogs():
          ready_to_send = False
        if error_status:
          SendErrors()
#e poi testiamo la velocità e salviamo i log. 

Vale la pena menzionare la funzione di configurazione del reverse ssh.

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 ovviamente, è necessario aggiungere tutta questa bellezza all'avvio automatico. A tal fine creo un file:

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

E ci scrivo dentro:

[Unit]
Descrizione=Test di Velocità del Modem
Richiede=systemd-networkd-wait-online.service
Dopo=systemd-networkd-wait-online.service
[Service]
Utente=khadas
ExecStart=/usr/bin/python3.6 /home/khadas/modems_speedtest/networks.py
RestartSec=5
Restart=always
[Install]
WantedBy=multi-user.target

Attivo l'avvio automatico e lo avvio!

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

Ora posso visualizzare i log di ciò che accade con il comando:

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

Risultati

E ora la cosa più importante: quale risultato abbiamo ottenuto? Riporterò alcuni grafici che sono riuscito a catturare durante lo sviluppo e il debug. I grafici sono stati costruiti utilizzando gnuplot con il seguente 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 mia prima prova è stata con l'operatore Tele2, che ho condotto nell'arco di alcuni giorni.

Speedtest simultaneo su diversi modem LTE

Qui ho utilizzato un server di misura dinamico. Le misurazioni della velocità funzionano, ma oscillano molto; tuttavia, è visibile una certa media, che può essere ottenuta filtrando i dati, ad esempio con la media mobile.

Successivamente ho creato altri grafici per altri operatori di rete. In questo caso, il server di test era uno solo, e anche i risultati sono stati molto interessanti.

Speedtest simultaneo su diversi modem LTE

Speedtest simultaneo su diversi modem LTE

Speedtest simultaneo su diversi modem LTE

Speedtest simultaneo su diversi modem LTE

Come si può vedere, il tema è molto ampio per ricerche e analisi di questi dati, e chiaramente non si limita a un paio di settimane di lavoro. Ma...

Risultato del lavoro

Il lavoro è stato bruscamente interrotto per motivi indipendenti dalla mia volontà. Una delle debolezze di questo progetto, a mio avviso, è stata il modem, che non riusciva benissimo a lavorare contemporaneamente con altri modem e creava problemi ad ogni avvio. Per questi scopi, esiste un'ampia varietà di altri modelli di modem, di solito già in formato Mini PCI-e e installabili all'interno del dispositivo, e sono molto più facili da configurare. Ma questa è un'altra storia. Il progetto è stato interessante e sono stato molto felice di poter partecipare.

Speedtest simultaneo su diversi modem LTE

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS 🔥 Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS | ProHoster