Testare de viteză simultană pe mai multe modemuri LTE

În carantină, mi s-a propus să particip la dezvoltarea unui dispozitiv de măsurare a vitezei modemurilor LTE pentru mai mulți operatori de telefonie mobilă.

Testare de viteză simultană pe mai multe modemuri LTE

Clientul dorea să evalueze viteza diverselor operatori de telecomunicații în diferite puncte geografice, pentru a înțelege care operator de telefonie mobilă este cel mai optim pentru instalarea echipamentelor care utilizează conexiuni LTE, de exemplu, pentru transmisiuni video. Totodată, problema trebuia rezolvată cât mai simplu și ieftin, fără echipamente costisitoare.

Voi spune din start că sarcina nu este cea mai simplă și necesită multă muncă, voi povesti despre problemele întâmpinate și cum le-am rezolvat. Așadar, să începem.

Notă

Măsurarea vitezei conexiunii LTE este o sarcină destul de complicată: este necesar să alegi echipamentele și metodologia de măsurare corecte, de asemenea, este bine să ai o bună înțelegere a topologiei și funcționării rețelei mobile. Plus, viteza poate fi influențată de mai mulți factori: numărul de abonați pe celulă, condițiile meteorologice; chiar de la celulă la celulă, viteza poate varia semnificativ din cauza topologiei rețelei. În general, aceasta este o sarcină cu un număr imens de necunoscute, iar soluția corectă poate fi oferită doar de operatorul de telecomunicații.

Inițial, clientul dorea pur și simplu să trimită un curier cu telefoanele operatorilor, să efectueze măsurători direct pe telefon și apoi să înregistreze rezultatele în carnet. Soluția mea pentru măsurarea vitezei rețelelor LTE, deși nu este perfectă, rezolvă sarcina dată.

Din cauza lipsei de timp, am luat decizii nu în favoarea confortului sau practicii, ci în favoarea rapidității dezvoltării. De exemplu, pentru accesul la distanță, am configurat un SSH invers, în loc de un VPN mai practic, pentru a economisi timp în configurarea serverului și fiecărui client în parte.

Cerințele tehnice

Așa cum se spune în articol Fără TDI: de ce clientul nu vrea unul: Nu lucrați fără TDI! Niciodată, nicăieri!

Specificația tehnică a fost destul de simplă, o voi extinde puțin pentru a fi înțeleasă de utilizatorul final. Alegerea soluțiilor tehnice și a echipamentului a fost dictată de client. Așadar, specificația tehnică, după toate aprobările:

Pe baza unui computer de tip single-board vim2 să fac un tester de viteză a conexiunii LTE prin modemuri Huawei e3372h — 153 câteva operatori de telefonie mobilă (de la unul la n). De asemenea, este necesar să se obțină coordonatele de la receptorul GPS, conectat prin UART. Măsurarea vitezei se va face cu ajutorul serviciului www.speedtest.net și să le adun într-un tabel de tip:

Testare de viteză simultană pe mai multe modemuri LTE

Tabel în format csv. Ulterior, acest tabel va fi trimis pe e-mail la fiecare 6 ore. În caz de erori, va clipi un LED conectat la GPIO.

Specificațiile le-am descris într-o formă liberă, după numeroase discuții. Dar sensul sarcinii este deja vizibil. Timpul pentru tot a fost setat la o săptămână. Însă, în realitate, s-a extins pe trei săptămâni. Acest lucru având în vedere că am lucrat la asta doar după programul de lucru principal și în weekenduri.

Aici vreau să subliniez din nou că, clientul a convenit în avans utilizarea serviciului de măsurare a vitezei și a echipamentului, ceea ce mi-a limitat foarte mult posibilitățile. De asemenea, bugetul a fost restrâns, așa că nu am achiziționat nimic suplimentar. Așa că a trebuit să mă conformeze acestor reguli.

Arhitectura și dezvoltarea

Schema este simplă și evidentă. Așa că o voi lăsa fără comentarii suplimentare.

Testare de viteză simultană pe mai multe modemuri LTE

Întregul proiect l-am decis să-l realizez în python, deși nu aveam deloc experiență în dezvoltarea în acest limbaj. L-am ales deoarece existau multe exemple și soluții gata pregătite care ar putea accelera dezvoltarea. Așadar, rog toți programatorii profesioniști să nu critice prima mea experiență în dezvoltarea în python și întotdeauna sunt deschis la feedback constructiv pentru a-mi îmbunătăți abilitățile.

În proces, am descoperit că python are două versiuni utilizate, 2 și 3, și în final m-am oprit la versiunea a treia.

Noduri hardware

Placă de bază vim2

Ca mașină principală, mi-a fost dată o placă de bază vim2

Testare de viteză simultană pe mai multe modemuri LTE

Un media combinat excelent și puternic pentru casa inteligentă și SMART-TV, dar neobișnuit de inadecvat pentru această sarcină, sau, să spunem, slab adecvat. De exemplu, sistemul său de operare principal este Android, iar Linux este un sistem de operare secundar, și, prin urmare, nimeni nu garantează funcționarea de calitate a tuturor modulelor și driverelor pe Linux. Și presupun că o parte din probleme au fost legate de driverele USB ale acestei platforme, astfel încât modemurile nu au funcționat pe această placă așa cum mă așteptam. De asemenea, are o documentație foarte slabă și dispersată, așa că fiecare operațiune a durat mult timp, căutând prin documente. Chiar și lucrul obișnuit cu GPIO a fost complicat. De exemplu, pentru a configura funcționarea unui LED, mi-a luat câteva ore. Dar, pentru a fi obiectiv, nu era esențial ce tip de plăcuță am folosit, ci faptul că funcționează și că există porturi USB.

Pentru început, trebuie să instalez Linux pe această placă. Pentru a nu căuta în toate colțurile documentației, și de asemenea pentru cei care vor să se familiarizeze cu această placă, scriu acest capitol.

Există două opțiuni pentru a instala Linux: pe un card SD extern sau pe un MMC intern. M-am chinuit cu cardul o seară întreagă, dar nu am reușit să-l fac să funcționeze, așa că am decis să instalez pe MMC, deși fără îndoială ar fi fost mult mai simplu să lucrez cu un card extern.

Despre flashing este explicat prost aici. Traduc dintr-o limbă ciudată în rusă. Pentru a flasha placa, trebuie să conectez un UART hardware. L-am conectat în următorul mod.

  • Tool Pin GND: Pin17 de la GPIO-ul VIM
  • Tool Pin TXD: Pin18 de la GPIO-ul VIM (Linux_Rx)
  • Tool Pin RXD: Pin19 de la GPIO-ul VIM (Linux_Tx)
  • Tool Pin VCC: Pin20 de la GPIO-ul VIM

Testare de viteză simultană pe mai multe modemuri LTE

După aceea, am descărcat firmware-ul de aici. Versiunea specifică a firmware-ului VIM1_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.

Pentru a încărca acest firmware, am nevoie de utilitare. Despre acest lucru este vorba mai detaliat aici. Nu am încercat să flashezi sub Windows, dar trebuie să menționez câteva lucruri despre flashing-ul pe Linux. Mai întâi voi instala utilitarele, conform instrucțiunilor.

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

Și… Nimic nu funcționează. Am petrecut câteva ore modificând scripturile de instalare, pentru ca totul să se instaleze corect la mine. Nu-mi amintesc ce am făcut acolo, dar a fost și un circ cu cai. Așa că fiți atenți. Dar fără aceste utilitare, nu are sens să continui cu vim2. Mai bine să nu mă ocup deloc de el!

După șapte cercuri de iad, configurarea scripturilor și instalarea, am obținut un pachet de utilitare funcționale. Am conectat placa prin USB la computerul meu Linux și, de asemenea, UART-ul este conectat conform schemei de mai sus.
Îmi configurez terminalul preferat minicom la o viteză de 115200, fără control hardware sau software al erorilor. Și începem.

Testare de viteză simultană pe mai multe modemuri LTE

Când pornesc VIM2 în terminalul UART, apăs orice tastă, de exemplu, spas, pentru a opri încărcarea. După ce va apărea linia

kvim2# 

Introduc comanda:

kvim2# run update

Pe gazda de unde încărcăm, execut:

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

Gata, uf. Am flash-uit, placa are Linux. Username/parola khadas:khadas.

După aceasta, fac câteva setări inițiale. Pentru a continua, dezactivez parola pentru sudo (da, nu este sigur, dar este convenabil).

sudo visudo

Editez linia pentru a arăta așa și salvez

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

După care schimb localizarea curentă, astfel încât timpul să fie pe Moscova, altfel va fi pe Greenwich.

sudo timedatectl set-timezone Europe/Moscow

sau

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

Dacă ți s-a părut complicat, atunci nu folosi această placă, mai bine ia un Raspberry Pi. Onest.

Modem Huawei e3372h — 153

Acest modem mi-a dat mult de furcă, iar, de fapt, a devenit cel mai mare punct slab al întregului proiect. De fapt, denumirea „modem” pentru aceste dispozitive nu reflectă deloc natura muncii lor: este o mașină puternică, acest dispozitiv are o unitate compusă care se pretinde a fi un CD-ROM pentru a instala driverele, iar apoi trece în modul de placă de rețea.

Din punct de vedere arhitectural, din perspectiva utilizatorului Linux, după toate setările, arată așa: după conectarea modemului, îmi apare interfața de rețea eth*, care obține adresa IP 192.168.8.100 prin dhcp și gateway-ul implicit 192.168.8.1.

Și cel mai important aspect! Această model de modem nu poate funcționa în modul de modem, controlat de comenzi AT.. Totul ar fi fost mult mai simplu, să creez conexiuni ppp pentru fiecare modem și să operezi cu ele. Dar în cazul meu, „singurul” (de fapt, driverul Linux conform regulilor udev), creează interfața eth și îi alocă o adresă IP prin dhcp.

Pentru a nu mă încurca mai departe, propun să uităm cuvântul „modem” și să vorbim despre placi de rețea și gateway-uri, căci, în esență, este precum conectarea unei noi plăci de rețea cu un gateway.
Când este un singur modem, nu cauzează probleme speciale, dar când sunt mai multe, de fapt n, atunci apare următoarea imagine a rețelei.

Testare de viteză simultană pe mai multe modemuri LTE

Adică n plăci de rețea, fiecare cu o adresă IP, având același gateway implicit. Dar, de fapt, fiecare dintre ele este conectat la operatorul său.

Inițial, aveam o soluție simplă: foloseam comanda ifconfig sau ip pentru a dezactiva toate interfețele și apoi activam pe rând fiecare dintre ele pentru a o testa. Soluția era bună, cu excepția faptului că în momentele de comutare nu puteam să mă conectez la dispozitiv. Și cum comutările erau frecvente și rapide, practic nu aveam posibilitatea să mă conectez deloc.

Așa că am ales să schimb manual adresel poștale ale modemurilor și să continui să dirijez traficul folosind setările de rutare.

Testare de viteză simultană pe mai multe modemuri LTE

Însă problemele cu modemurile nu s-au încheiat aici: în caz de probleme cu alimentarea, acestea se deconectau, necesitând o alimentare stabilă de la un hub USB. Am rezolvat această problemă prin lipirea directă a alimentării la hub. Alta problemă, cu care m-am confruntat și care a distrus întregul proiect: după repornire sau o pornire rece, nu toate modemurile erau recunoscute, și nu știam de ce se întâmpla acest lucru și după ce algoritm. Dar haideți să le luăm pe rând.

Pentru funcționarea corectă a modemului, am instalat pachetul usb-modeswitch.

sudo apt update
sudo apt install -y usb-modeswitch

După aceasta, modemul va fi recunoscut corect și configurat de subsystema udev după conectare. Verific, pur și simplu conectând modemul și asigurându-mă că rețeaua a apărut.
O altă problemă pe care nu am putut să o rezolv: cum să obțin numele operatorului din acest modem? Numele operatorului este conținut în interfața web a modemului la adresa 192.168.8.1. Aceasta este o pagină web dinamică, care primește date prin cereri ajax, așa că nu este suficient să wget-ez pagina și să extrag numele. Așa că am început să mă uit cum să lucrez cu paginile web etc., și mi-am dat seama că fac ceva inutil. În rezultat, am renunțat și am început să obțin operatorul folosind API-ul Speedtest.

Mult ar fi fost mai simplu dacă modemul ar fi avut acces prin comenzi AT. Atunci aș fi putut să-l reconfigurez, să creez o conexiune ppp, să asign IP, să obțin operatorul de telefonie etc. Dar din păcate, lucrez cu ceea ce mi s-a dat.

GPS

Receptorul GPS pe care mi l-au dat avea un interface UART și alimentare. Nu a fost cea mai bună soluție, dar a fost funcțional și simplu. Receptorul arăta cam așa.

Testare de viteză simultană pe mai multe modemuri LTE

Sincer, a fost prima dată când am lucrat cu un receptor GPS, dar, așa cum mă așteptam, totul a fost deja gândit pentru noi. Așa că folosim soluțiile gata disponibile.

Pentru început, activez uart_AO_B (UART_RX_AO_B, UART_TX_AO_B) pentru a conecta GPS-ul.

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

Apoi verific succesul operației.

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

Această comandă, se pare, editează devtree în timp real, ceea ce este destul de convenabil.

După succesul acestei operații, repornim și instalăm demonul GPS.

khadas@Khadas:~$ sudo reboot

Instalarea demonului GPS. Instalez totul și îl opresc imediat pentru o configurare ulterioară.

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

Editez fișierul de configurație.

sudo vim /etc/default/gpsd

Instalez UART-ul pe care va funcționa GPS-ul.

DEVICES="/dev/ttyS4"

Și apoi pornim totul.

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

După aceea, conectez GPS-ul.

Testare de viteză simultană pe mai multe modemuri LTE

În mână am cablul GPS, iar sub degete văd cablurile UART ale debugger-ului.

Mă repornesc și verific funcționarea GPS-ului cu ajutorul programului gpsmon.

Testare de viteză simultană pe mai multe modemuri LTE

În această captură de ecran nu se văd sateliți, dar comunicarea cu receptorul GPS este vizibilă, iar asta arată că totul este în regulă.

Am testat multe variante de funcționare cu acest demon pe python, dar m-am oprit la cea care funcționa corect cu python 3.

Instalez biblioteca necesară.

sudo -H pip3 install gps3 

Și scriu codul de funcționare.

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("Eroare receptor GPS!!!")
			return "NA", "NA"
		time.sleep(1.0)
...
f __name__ == '__main__':
...	#gps
	agps_thread = AGPS3mechanism()  # Instantiate AGPS3 Mechanisms
	agps_thread.stream_data()  # De la localhost (), sau alte gazde, de exemplu, (host='gps.ddns.net')
	agps_thread.run_thread()  # Timp de limitare pentru a dormi după o căutare goală, implicit '()' 0.2 două zecimi de secundă

Dacă am nevoie să obțin coordonatele, atunci se face cu următorul apel:

longitude, latitude = getPositionData(agps_thread)

Și în decurs de 1-10 secunde, voi primi fie coordonata, fie nu. Da, am avut zece încercări de a obține coordonatele. Nu este optim, este imperfect, dar funcționează. Am decis să fac asta pentru că GPS-ul poate funcționa prost și nu obține întotdeauna date. Dacă aș aștepta să primesc datele, în cazul lucrului într-o cameră închisă, programul s-ar bloca în acel loc. De aceea am implementat o variantă mai puțin elegantă.

În principiu, dacă aș fi avut mai mult timp, aș fi putut primi date direct prin UART de la GPS, să le parzez într-un fir separat și să lucrez cu ele. Dar nu am avut deloc timp, de aici codul urât. Și da, nu mi-e rușine.

LED

Conectarea LED-ului a fost simplă și complicată în același timp. Principalul obstacol este că numărul pinului în sistem nu corespunde numărului pinului de pe placă și pentru că documentația este scrisă într-un mod slab. Pentru a corela numărul pinului hardware cu numărul pinului din OS, este necesar să executați comanda:

gpio readall

Va fi afișată o tabelă de corespondență între pinul din sistem și cel de pe placă. După care pot opera cu pinul în OS-ul însuși. În cazul meu, LED-ul este conectat la GPIOH_5.

Testare de viteză simultană pe mai multe modemuri LTE

Transform pinul GPIO în mod de ieșire.

gpio -g mode 421 out

Scriu zero.

gpio -g write 421 0

Scriu unu.

gpio -g write 421 1

Testare de viteză simultană pe mai multe modemuri LTE
Totul se aprinde, după ce scriu „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)

Acum, în caz de erori, apelăm error_blink() și LED-ul ne clipește frumos.

Module software

Speedtest API

Este o mare bucurie că serviciul speedtest.net are propriul său API Python, pe care îl puteți vizualiza la Github.

Este bine că există surse deschise, care pot fi, de asemenea, vizualizate. Cum să lucrați cu acest API (exemple simple) poate fi văzut la secțiunea corespunzătoare.

Instalez biblioteca python cu următoarea comandă.

sudo -H pip3 install speedtest-cli

De exemplu, puteți instala testul de viteză direct în Ubuntu din repo. Este aceeași aplicație python, care poate fi apoi rulată direct din consolă.

sudo apt install speedtest-cli -y

Și să efectuezi măsurători ale vitezei tale de internet.

speedtest-cli
Se recuperează configurația speedtest.net...
Testare din B***** (*.*.*.*)...
Se recuperează lista serverelor speedtest.net...
Alegerea celui mai bun server pe baza ping-ului...
Găzduit de MTS (Moscova) [0.12 km]: 11.8 ms
Testare viteză de descărcare................................................................................
Descărcare: 7.10 Mbit/s
Testare viteză de încărcare......................................................................................................
Încărcare: 3.86 Mbit/s

Ca rezultat, așa cum am făcut eu. A trebuit să mă uit în sursele originale ale acestui test de viteză pentru a le integra mai complet în proiectul meu. Una dintre cele mai importante sarcini este să obțin și numele operatorului de rețea, pentru a-l introduce în tabel.

import speedtest
from datetime import datetime
...
# Specify the specific server for the test
#6053) MaximaTelecom (Moscow, Russian Federation)
servers = ["6053"]
# If you want to use a single-threaded test
threads = None
s = speedtest.Speedtest()
# Get the name of the mobile operator
opos = '%(isp)s' % s.config['client']
s.get_servers(servers)
# Get the text string with server parameters
testserver = '%(sponsor)s (%(name)s) [%(d)0.2f km]: %(latency)s ms' % s.results.server
# Download test
s.download(threads=threads)
# Upload test
s.upload(threads=threads)
# Get the results
s.results.share()

# After that, a string is formed for writing to the csv file.
# Get the GPS coordinates
longitude, latitude = getPositionData(agps_thread)
# Time and date
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"
# Here goes the logging to the file

Aici nu a fost toată situația atât de simplă, deși, părea că nu ar putea fi mai simplu. Inițial, parametrul servers era [], să alegi cel mai bun server. În consecință, am avut servere aleatorii și, după cum era de așteptat, viteza era fluctuantă. Aceasta este o temă destul de complicată, utilizarea unui server fix, dacă da, atunci static sau dinamic, necesită cercetare. Dar iată un exemplu de grafice ale măsurătorilor de viteză ale operatorului Beeline la alegerea dinamică a serverului de testare și a celui fix.

Testare de viteză simultană pe mai multe modemuri LTE
Rezultatele măsurării vitezei la alegerea unui server dinamic.

Testare de viteză simultană pe mai multe modemuri LTE
Rezultatul testării vitezei, utilizând un singur server strict ales.

Există 'fibră' la testare atât acolo cât și aici, și trebuie eliminată prin metode matematice. Dar la serverul fix este puțin mai puțin și amplitudinea este mai stabilă.
De fapt, acesta este un loc pentru cercetări ample. Și aș efectua măsurători de viteză către serverul meu, folosind utilitarul iperf. Dar ne conformăm de la cerințele tehnice.

Trimiterea de emailuri și erorile

Pentru a trimite emailuri, am încercat zeci de variante diferite, dar în cele din urmă m-am oprit la următoarea. Am înregistrat o căsuță poștală pe yandex și apoi am folosit acest exemplu de trimitere a emailurilor. L-am verificat și l-am implementat în program. În acest exemplu sunt discutate diverse variante, inclusiv trimiterea de la gmail și altele. Nu am avut timp și nici dorința de a-mi crea propriul server de email, dar cum s-a dovedit, a fost o greșeală.

Am trimis logurile prin programator, în prezența unei conexiuni, la fiecare 6 ore: la 00:00, 06:00, 12:00 și 18:00. Le trimiteam în felul următor.

from send_email import *
...
message_log = "Logurile testării plăcii nr. 1"
EmailForSend = ["dlinyj@trololo.ru", "pupkin@trololo.ru"]
files = ["/home/khadas/modems_speedtest/csv"]
...
def sendLogs():
	global EmailForSend
	curdata = datetime.now().strftime('%d.%m.%Y')
	curtime = datetime.now().strftime('%H:%M:%S')
	try:
		for addr_to in EmailForSend:
			send_email(addr_to, message_log, "Loguri pentru " + curdata + " " + curtime, files)
	except:
		print("Problemă de rețea la trimiterea email-ului")
		return False
	return True

Erorile au fost de asemenea trimise inițial. La început, acestea erau acumulate într-o listă, apoi le trimiteam tot prin programator, în prezența unei conexiuni. Totuși, au apărut probleme deoarece yandex are o limită pentru numărul de mesaje trimise pe zi (este o durere, o tristete și o umilință). Deoarece puteau fi o cantitate uriașă de erori pe minut, a trebuit să renunț la trimiterea erorilor prin email. Așadar, țineți cont de această problemă atunci când trimiteți automat prin serviciile yandex.

Server de feedback

Pentru a avea acces la hardware-ul de la distanță și a-l putea configura și reconfigura, am avut nevoie de un server extern. De fapt, ar fi fost corect să trimit toate datele pe server și să construiesc toate graficele frumoase în interfața web. Dar nu toate deodată.

Ca VPS, am ales ruvds.com. Aș fi putut lua serverul cel mai simplu. În general, pentru scopurile mele, acest lucru ar fi fost mai mult decât suficient. Dar, deoarece nu plăteam pentru server din propriul buzunar, am decis să aleg cu un mic rezervă, pentru a avea suficient dacă vom desfășura interfața web, propriul server SMTP, VPN etc. În plus, să am posibilitatea de a configura un bot Telegram și să nu am probleme cu blocările acestuia. De aceea am ales Amsterdam și următoarele specificații.

Testare de viteză simultană pe mai multe modemuri LTE

Ca metodă de conectare cu hardware-ul vim2, am ales o conexiune SSH inversă și, așa cum a arătat experiența, aceasta nu este cea mai bună soluție. La întreruperea conexiunii, serverul păstrează portul și nu se poate conecta timp de ceva vreme. Așadar, este mai bine să folosiți alte metode de comunicare, cum ar fi VPN-ul. În viitor, am dorit să trec la VPN, dar nu am avut timp.

Nu voi intra în detalii despre configurarea firewall-ului, restricționarea permisiunilor, dezactivarea conexiunii ssh pentru root și alte setări de bază ale VPS-ului. Sper că știți deja toate acestea. Pentru conexiunea de la distanță, creez un nou utilizator pe server.

adduser vimssh

Pe serverul nostru, generez cheile pentru conexiunea ssh.

ssh-keygen

Și le copiez pe serverul nostru.

ssh-copy-id vimssh@host.com

Pe serverul nostru, creez o conexiune automată inversă ssh la fiecare boot.

[Unit]
Descriere=Auto Reverse SSH
Necesar=systemd-networkd-wait-online.service
După=systemd-networkd-wait-online.service
[Service]
Utilizator=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

Atenție la portul 8083: acesta definește prin ce port voi realiza conexiunea prin ssh invers. Adaugăm la pornire și începem.

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

Se poate verifica chiar și statusul:

sudo systemctl status autossh.service

Acum, pe serverul nostru VPS, dacă execut:

ssh -p 8083 khadas@localhost

Atunci ajung pe echipamentul meu de testare. Și de pe echipament pot trimite jurnale și orice date prin ssh către serverul meu, ceea ce este destul de convenabil.

Adunăm totul la un loc

Testare de viteză simultană pe mai multe modemuri LTE
Întâlnire, să începem dezvoltarea și depanarea

Uf, se pare că am descris toate nodurile. Acum a venit momentul să pun toate acestea într-un singur loc. Codul poate fi vizualizat aici.

Un aspect important legat de cod: Acest proiect nu poate porni așa, direct, deoarece este adaptat pentru o anumită sarcină, cu o arhitectură specifică. Chiar dacă ofer sursele, totuși, cea mai valoroasă parte o voi explica aici, chiar în text, altfel este complet neclar.

La început, am inițializarea gps, gpio și pornirea unui fir dedicat planificatorului.

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

Planificatorul este destul de simplu: el verifică dacă a venit timpul pentru a trimite mesaje și care este starea curentă a erorilor. Dacă există un flag de eroare, atunci clipește un LED.

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

Cel mai complicat aspect al acestui proiect este păstrarea conexiunii ssh inverse la fiecare test. În fiecare test, se reconfigurează din nou gateway-ul implicit și serverul DNS. Deoarece oricum nimeni nu citește, să știți că trenul nu circulă pe șine de lemn. Cine găsește oul de la Paște, obține o bomboană.

Pentru aceasta, creez o tabelă de rutare separată —set-mark 0x2 și o regulă pentru redirecționarea traficului.

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

Detalii despre cum funcționează acest lucru se pot citi în acest articol..

După care intru într-un ciclu infinit, unde obțin de fiecare dată lista modemurilor conectate (pentru a verifica dacă configurația rețelei s-a schimbat).

network_list = getNetworklist()

Obținerea listei interfețelor de rețea este destul de simplă.

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

După obținerea listei, atribui adresele IP tuturor interfețelor, așa cum am arătat în imaginea din capitolul despre 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")

Apoi, pur și simplu parcurg fiecare interfață în ciclu. Și configurez fiecare interfață.

	for iface in network_list:
		ConfigNetwork(iface)

def ConfigNetwork(iface):
#resetăm toate setările
		cmd_run("sudo ip route flush all")
#Atribuim gateway-ul implicit
		cmd_run("sudo route add default gw 192.168.8.1 " + iface)
#atribui dns-server (acesta este necesar pentru funcționarea speedtest)
		cmd_run ("sudo bash -c 'echo nameserver 8.8.8.8 > /etc/resolv.conf'")

Verific interfața pentru funcționare, dacă rețeaua nu există, generează erori. Dacă rețeaua există, vine momentul să acționăm!

Aici configurez rutarea ssh pe această interfață (dacă nu a fost făcută), trimit erorile pe server, dacă a venit timpul, trimit log-urile și, în cele din urmă, efectuez speedtest și salvez log-urile într-un fișier csv.

if not NetworkAvalible():
....
#Aici generăm erori
....
else: #Există rețea, minunat, lucrăm!
#Dacă avem o interfață problematică, pe care se află ssh, atunci o schimbăm
  if (sshint == lastbanint or sshint == "free"):
    print("********** Setup SSH ********************")
    if sshint != "free":
      cmd_run("sudo ip route del default via 192.168.8.1 dev " + sshint +" table 102")
    SetupReverseSSH(iface)
    sshint = iface
#deoarece rețeaua funcționează, haideți să trimitem totul urgent!!!
    if ready_to_send:
      print ("**** Ready to send!!!")
        if sendLogs():
          ready_to_send = False
        if error_status:
          SendErrors()
#și apoi testăm viteza și salvăm log-urile. 

Merită menționat funcția de configurare a ssh-ului invers.

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

Și, bineînțeles, este necesar să adaug toată această frumusețe în autostart. Pentru aceasta, creez un fișier:

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

Și scriu în el:

[Unit]
Descriere=Test de Viteză Modem
Necesar=systemd-networkd-wait-online.service
După=systemd-networkd-wait-online.service
[Service]
Utilizator=khadas
ExecStart=\/usr\/bin\/python3.6 \/home\/khadas\/modems_speedtest\/networks.py
RestartSec=5
Restart=always
[Install]
WantedBy=multi-user.target

Activăm autostartul și îl pornim!

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

Acum pot vizualiza log-urile a ceea ce se întâmplă folosind comanda:

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

Rezultate

Ei bine, acum ceea ce este cel mai important, ce a rezultat în urma asta? Voi prezenta câteva grafice pe care am reușit să le capturez în timpul dezvoltării și depanării. Graficele au fost construite cu ajutorul gnuplot folosind următorul 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"

Prima experiență a fost cu operatorul Tele2, pe care am desfășurat-o pe parcursul câtorva zile.

Testare de viteză simultană pe mai multe modemuri LTE

Aici am folosit un server de măsurare dinamic. Măsurătorile de viteză funcționează, dar variază semnificativ, totuși se observă o anumită medie, care poate fi obținută prin filtrarea datelor, de exemplu, prin media mobilă.

Ulterior, am construit încă câteva grafice pentru alți operatori de telecomunicații. Serverul de testare în acest caz a fost unul singur, iar rezultatele sunt de asemenea foarte interesante.

Testare de viteză simultană pe mai multe modemuri LTE

Testare de viteză simultană pe mai multe modemuri LTE

Testare de viteză simultană pe mai multe modemuri LTE

Testare de viteză simultană pe mai multe modemuri LTE

Așa cum se vede, tema este foarte vastă pentru cercetare și procesare a acestor date, și cu siguranță nu se poate încadra în câteva săptămâni de muncă. Dar...

Rezultatul muncii

Munca a fost brusc întreruptă din circumstanțe care nu depind de mine. Una dintre punctele slabe ale acestui proiect, din punctul meu de vedere subiectiv, a fost modemul, care nu dorise foarte mult să funcționeze simultan cu alte modeme, și la fiecare încărcare făcea astfel de neplăceri. Pentru aceste scopuri există o cantitate enormă de alte modele de modeme, care de obicei au format Mini PCI-e și se instalează în interiorul dispozitivului, iar configurarea lor este mult mai simplă. Dar aceasta este deja o poveste complet diferită. Proiectul a fost interesant și am fost foarte bucuros că am reușit să particip.

Testare de viteză simultană pe mai multe modemuri LTE

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster