Samtidigt hastighetstest på flera LTE-modem

Under karantänen erbjöds jag att delta i utvecklingen av en enhet för att mäta hastigheten på LTE-modem för flera mobiloperatörer.

Samtidigt hastighetstest på flera LTE-modem

Kunden ville utvärdera hastigheten hos olika teleoperatörer på olika geografiska platser för att kunna förstå vilken mobiloperatör som var mest optimal för honom vid installation av utrustning med hjälp av en LTE-anslutning, till exempel för videosändningar. Samtidigt måste problemet lösas så enkelt och billigt som möjligt, utan dyr utrustning.

Jag ska genast säga att uppgiften inte är den enklaste och mest kunskapsintensiva, jag ska berätta vilka problem jag stötte på och hur jag löste dem. Låt oss gå.

Notera

Att mäta hastigheten på en LTE-anslutning är en mycket komplex fråga: du måste välja rätt utrustning och mätteknik, och även ha en god förståelse för topologin och driften av det mobila nätverket. Dessutom kan hastigheten påverkas av flera faktorer: antalet abonnenter på en cell, väderförhållanden, även från cell till cell kan hastigheten variera dramatiskt på grund av nätverkstopologin. I allmänhet är detta ett problem med ett stort antal okända, och endast en teleoperatör kan lösa det korrekt.

Från början ville kunden bara köra kuriren med operatörernas telefoner, göra mätningar direkt på telefonen och sedan skriva ner hastighetsmätningsresultaten i en anteckningsbok. Min lösning för att mäta hastigheten på lte-nätverk, även om den inte är idealisk, löser problemet.

På grund av tidsbrist fattade jag beslut inte till förmån för bekvämlighet eller praktiska, utan till förmån för snabb utveckling. Till exempel användes omvänd ssh för fjärråtkomst, istället för det mer praktiska VPN, för att spara tid på att sätta upp servern och varje enskild klient.

Teknisk uppgift

Som det står i artikeln Utan tekniska specifikationer: varför kunden inte vill ha det: Arbeta inte utan tekniska specifikationer! Aldrig någonstans!

Den tekniska uppgiften var ganska enkel, jag kommer att utöka den lite för förståelsen för slutanvändaren. Valet av tekniska lösningar och utrustning dikterades av kunden. Så, själva den tekniska specifikationen, efter alla godkännanden:

Baserad på en enkelkortsdator vim2 gör en hastighetstestare för lte-anslutningar via H-modemuawei e3372h - 153 flera teleoperatörer (från ett till n). Det är också nödvändigt att ta emot koordinater från en GPS-mottagare ansluten via UART. Gör hastighetsmätningar med hjälp av tjänsten www.speedtest.net och placera dem i en tabell så här:

Samtidigt hastighetstest på flera LTE-modem

Tabell i csv-format. Skicka sedan denna skylt med e-post var 6:e ​​timme. Vid fel blinkar lysdioden som är ansluten till GPIO.

Jag beskrev de tekniska specifikationerna i fri form, efter många godkännanden. Men meningen med uppgiften är redan synlig. En vecka gavs för allt. Men i verkligheten varade det i tre veckor. Detta med hänsyn till det faktum att jag gjorde detta först efter mitt huvudjobb och på helgerna.

Här vill jag återigen uppmärksamma det faktum att kunden i förväg kommit överens om användningen av hastighetsmätningstjänsten och hårdvaran, vilket kraftigt begränsade mina möjligheter. Budgeten var också begränsad, så inget speciellt köptes in. Så vi var tvungna att följa dessa regler.

Arkitektur och utveckling

Schemat är enkelt och självklart. Därför lämnar jag det utan några särskilda kommentarer.

Samtidigt hastighetstest på flera LTE-modem

Jag bestämde mig för att implementera hela projektet i python, trots att jag inte hade någon erfarenhet av att utveckla på detta språk alls. Jag valde det för att det fanns ett gäng färdiga exempel och lösningar som kunde skynda på utvecklingen. Därför ber jag alla professionella programmerare att inte skälla på min första erfarenhet av att utvecklas i python, och jag är alltid glad över att höra konstruktiv kritik för att förbättra mina kunskaper.

Under processen upptäckte jag också att python har två versioner 2 och 3 som körs, som ett resultat av att jag bestämde mig för den tredje.

Hårdvaru noder

Enkelplatta vim2

Jag fick en enkelkortsdator som min huvudmaskin vim2

Samtidigt hastighetstest på flera LTE-modem

En utmärkt, kraftfull mediaprocessor för ett smart hem och SMART-TV, men extremt olämplig för denna uppgift, eller, låt oss säga, dåligt lämpad. Till exempel är dess huvudoperativsystem Android, och Linux är ett sekundärt operativsystem, och följaktligen garanterar ingen högkvalitativ drift av alla noder och drivrutiner under Linux. Och jag antar att några av problemen var relaterade till USB-drivrutinerna för den här plattformen, så modemen fungerade inte som förväntat på det här kortet. Den har också mycket dålig och spridd dokumentation, så varje operation tog mycket tid att gräva genom hamnen. Även vanligt arbete med GPIO tog mycket blod. Det tog mig till exempel flera timmar att sätta upp lysdioden. Men för att vara objektiv så var det i grunden inte viktigt vilken typ av enkelkort det var, huvudsaken var att det fungerade och det fanns USB-portar.

Först måste jag installera Linux på det här kortet. För att inte leta igenom vildmarken med dokumentation för alla, och även för dem som kommer att ta itu med detta system med en enda styrelse, skriver jag detta kapitel.

Det finns två alternativ för att installera Linux: på ett externt SD-kort eller på en intern MMC. Jag tillbringade en kväll med att försöka komma på hur jag skulle få det att fungera med kortet, så jag bestämde mig för att installera det på MMC, även om det utan tvekan skulle vara mycket lättare att arbeta med ett externt kort.

Om firmware snett berättat här. Jag översätter från konstigt till ryska. För att flasha kortet måste jag ansluta hårdvaran UART. Anslut den som följer.

  • Tool Pin GND: <—> Pin17 av VIMs GPIO
  • Tool Pin TXD: <—> Pin18 av VIMs GPIO (Linux_Rx)
  • Tool Pin RXD: <—> Pin19 av VIMs GPIO (Linux_Tx)
  • Tool Pin VCC: <—> Pin20 av VIMs GPIO

Samtidigt hastighetstest på flera LTE-modem

Därefter laddade jag ner firmware hence. Specifik firmwareversion VIM1_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.

För att ladda upp den här firmware behöver jag verktyg. Mer information om detta här. Jag har inte provat att flasha det under Windows, men jag måste berätta några ord om firmware under Linux. Först installerar jag verktygen enligt instruktionerna.

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

Aaand... Ingenting fungerar. Jag tillbringade ett par timmar med att redigera installationsskripten så att allt skulle installeras korrekt för mig. Jag minns inte vad jag gjorde där, men det fanns också den där cirkusen med hästar. Så var försiktig. Men utan dessa verktyg är det ingen idé att tortera vim2 ytterligare. Det är bättre att inte bråka med honom alls!

Efter sju helvetescirklar, skriptkonfiguration och installation fick jag ett paket med fungerande verktyg. Jag kopplade kortet via USB till min Linux-dator, och kopplade även UART enligt diagrammet ovan.
Jag ställer in min favoritminikomterminal för en hastighet på 115200, utan felkontroll i hårdvara och mjukvara. Och låt oss börja.

Samtidigt hastighetstest på flera LTE-modem

När jag laddar VIM2 i UART-terminalen trycker jag på en tangent, till exempel mellanslagstangenten, för att stoppa laddningen. Efter att raden visas

kvim2# 

Jag skriver in kommandot:

kvim2# run update

På den värd som vi laddar från kör jag:

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

Det var allt, fy. Jag kollade, det finns Linux på kortet. Inloggning/lösenord khadas:khadas.

Efter det, några mindre initiala inställningar. För vidare arbete inaktiverar jag lösenordet för sudo (ja, inte säkert, men bekvämt).

sudo visudo

Jag redigerar raden till formuläret och sparar

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

Sedan ändrar jag den aktuella lokalen så att klockan är i Moskva, annars blir det i Greenwich.

sudo timedatectl set-timezone Europe/Moscow

eller

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

Om du tycker att det är svårt, använd inte det här brädan, Raspberry Pi är bättre. Ärligt.

Modem Huawei e3372h – 153

Det här modemet var en betydande blodkälla för mig, och i själva verket blev det flaskhalsen i hela projektet. I allmänhet återspeglar inte namnet "modem" för dessa enheter essensen av arbetet alls: det här är en kraftfull kombination, den här hårdvaran har en sammansatt enhet som utger sig för att vara en CD-ROM för att installera drivrutiner, och växlar sedan till nätverkskortsläge.

Arkitektoniskt sett, ur en Linux-användares synvinkel, efter alla inställningar, ser det ut så här: efter att ha anslutit modemet har jag ett eth* nätverksgränssnitt, som via dhcp får IP-adressen 192.168.8.100, och standardgatewayen är 192.168.8.1.

Och det viktigaste ögonblicket! Denna modemmodell kan inte fungera i modemläge, som styrs av AT-kommandon. Allt skulle vara mycket enklare, skapa PPP-anslutningar för varje modem och sedan arbeta med dem. Men i mitt fall skapar "själv" (mer exakt, en Linux-dykare enligt udev-reglerna), ett eth-gränssnitt och tilldelar en IP-adress till det via dhcp.

För att undvika ytterligare förvirring föreslår jag att du glömmer ordet "modem" och säger nätverkskort och gateway, för i huvudsak är det som att ansluta ett nytt nätverkskort med en gateway.
När det finns ett modem orsakar detta inga speciella problem, men när det finns fler än ett, nämligen n-stycken, uppstår följande nätverksbild.

Samtidigt hastighetstest på flera LTE-modem

Det vill säga n nätverkskort, med samma IP-adress, vart och ett med samma standardgateway. Men i själva verket är var och en av dem kopplad till sin egen operatör.

Från början hade jag en enkel lösning: använd ifconfig eller ip-kommandot, stäng av alla gränssnitt och slå helt enkelt på ett i tur och ordning och testa det. Lösningen var bra för alla, förutom att jag under växlingsmomenten inte kunde ansluta till enheten. Och eftersom bytet är frekvent och snabbt hade jag faktiskt ingen möjlighet att ansluta alls.

Därför valde jag vägen att manuellt ändra IP-adresserna för modemen och sedan driva trafik med hjälp av routinginställningar.

Samtidigt hastighetstest på flera LTE-modem

Detta var inte slutet på mina problem med modem: i händelse av strömproblem ramlade de av, och en bra stabil strömförsörjning till USB-hubben krävdes. Jag löste detta problem genom att hårdlöda strömmen direkt till navet. Ett annat problem som jag stötte på och som förstörde hela projektet: efter en omstart eller kallstart av enheten upptäcktes inte alla modem och inte alltid, och jag kunde inte avgöra varför detta hände och med vilken algoritm. Men först till kvarn.

För att modemet skulle fungera korrekt installerade jag paketet usb-modeswitch.

sudo apt update
sudo apt install -y usb-modeswitch

Efter anslutningen kommer modemet att detekteras och konfigureras korrekt av undersystemet udev. Jag kollar genom att helt enkelt ansluta modemet och se till att nätverket dyker upp.
Ett annat problem som jag inte kunde lösa: hur kan jag få namnet på operatören vi arbetar med från det här modemet? Operatörsnamnet finns i modemets webbgränssnitt på 192.168.8.1. Detta är en dynamisk webbsida som tar emot data via Ajax-förfrågningar, så att bara wgeta sidan och analysera namnet kommer inte att fungera. Så jag började titta på hur man utvecklar en webbsida osv, och insåg att jag höll på med något slags nonsens. Som ett resultat spottade han och operatören började ta emot med själva Speedtest API.

Mycket skulle vara lättare om modemet hade åtkomst via AT-kommandon. Det skulle vara möjligt att konfigurera om det, skapa en ppp-anslutning, tilldela en IP, skaffa en teleoperatör osv. Men tyvärr, jag jobbar med det jag har fått.

GPS

GPS-mottagaren jag fick hade ett UART-gränssnitt och ström. Det var inte den bästa lösningen, men det var ändå fungerande och enkelt. Mottagaren såg ut ungefär så här.

Samtidigt hastighetstest på flera LTE-modem

För att vara ärlig så var detta första gången jag arbetade med en GPS-mottagare, men som jag förväntade mig var allt tänkt för oss för länge sedan. Så vi använder bara färdiga lösningar.

Först aktiverar jag uart_AO_B (UART_RX_AO_B, UART_TX_AO_B) för att ansluta GPS.

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

Efteråt kontrollerar jag operationens framgång.

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

Det här kommandot redigerar tydligen devtree i farten, vilket är väldigt bekvämt.

När den här operationen har lyckats, starta om och installera GPS-demonen.

khadas@Khadas:~$ sudo reboot

Installera GPS-demonen. Jag installerar allt och skär av det omedelbart för vidare konfiguration.

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

Redigera inställningsfilen.

sudo vim /etc/default/gpsd

Jag installerar en UART som GPS:en kommer att hänga på.

DEVICES="/dev/ttyS4"

Och så sätter vi på allt och börjar.

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

Efter det kopplar jag in GPS:en.

Samtidigt hastighetstest på flera LTE-modem

GPS-kabeln är i mina händer, UART-debuggertrådarna är synliga under mina fingrar.

Jag startar om och kontrollerar GPS-funktionen med hjälp av gpsmon-programmet.

Samtidigt hastighetstest på flera LTE-modem

Du kan inte se satelliterna i den här skärmdumpen, men du kan se kommunikation med GPS-mottagaren, och det betyder att allt är bra.

I python försökte jag många alternativ för att arbeta med den här demonen, men jag bestämde mig för den som fungerade korrekt med python 3.

Jag installerar det nödvändiga biblioteket.

sudo -H pip3 install gps3 

Och jag skulpterar arbetskoden.

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

Om jag behöver få koordinater görs detta med följande samtal:

longitude, latitude = getPositionData(agps_thread)

Och inom 1-10 sekunder får jag antingen koordinaten eller inte. Ja, jag hade tio försök att få koordinater. Inte optimalt, snett och snett, men det funkar. Jag bestämde mig för att göra detta eftersom GPS kan ha dålig mottagning och inte alltid ta emot data. Om du väntar på att få data, om du arbetar i ett avlägset rum, kommer programmet att frysa på denna plats. Därför implementerade jag detta oeleganta alternativ.

Om det fanns mer tid skulle det i princip vara möjligt att ta emot data från GPS direkt via UART, tolka det i en separat tråd och arbeta med det. Men det fanns ingen tid alls, därav den brutalt fula koden. Och ja, jag skäms inte.

Ljusdiod

Att ansluta lysdioden var enkelt och svårt på samma gång. Den största svårigheten är att pinnumret i systemet inte motsvarar pinnumret på tavlan och att dokumentationen är skriven med vänster hand. För att jämföra hårdvaru-pinnumret och pin-numret i operativsystemet måste du köra kommandot:

gpio readall

En tabell med pinkorrespondens i systemet och på tavlan kommer att visas. Därefter kan jag redan använda stiftet i själva OS. I mitt fall är lysdioden ansluten till GPIOH_5.

Samtidigt hastighetstest på flera LTE-modem

Jag växlar GPIO-stiftet till utgångsläge.

gpio -g mode 421 out

Jag skriver ner noll.

gpio -g write 421 0

Jag skriver ner en.

gpio -g write 421 1

Samtidigt hastighetstest på flera LTE-modem
Allt är upplyst, efter att ha skrivit "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)

Nu, vid fel, ringer jag error_blink() och lysdioden blinkar vackert.

Programvaru noder

Speedtest API

Det är en stor glädje att speedtest.net-tjänsten har sin egen python-API, du kan titta på Github.

Det som är bra är att det finns källkoder som också kan ses. Hur man arbetar med detta API (enkla exempel) finns i relevant avsnitt.

Jag installerar python-biblioteket med följande kommando.

sudo -H pip3 install speedtest-cli

Till exempel kan du till och med installera en hastighetstestare i Ubuntu direkt från programvaran. Detta är samma python-applikation, som sedan kan startas direkt från konsolen.

sudo apt install speedtest-cli -y

Och mät din internethastighet.

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

Som ett resultat, precis som jag gjorde. Jag var tvungen att komma in i källkoderna för detta hastighetstest för att mer fullständigt kunna implementera dem i mitt projekt. En av de viktigaste uppgifterna är att få fram namnet på teleoperatören för att ersätta det i plattan.

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"
#тут идет запись в файл логов

Även här visade sig allt inte vara så enkelt, även om det verkar mycket enklare. Ursprungligen var serverns parameter lika med [], säger de, välj den bästa servern. Som ett resultat hade jag slumpmässiga servrar och, som du kanske gissar, variabel hastighet. Detta är ett ganska komplext ämne, att använda en fast server, om så är fallet, statisk eller dynamisk, kräver forskning. Men här är ett exempel på hastighetsmätningsgrafer för en Beeline-operatör när man dynamiskt väljer en testserver och en statiskt fixerad.

Samtidigt hastighetstest på flera LTE-modem
Resultatet av hastighetsmätning vid val av dynamisk server.

Samtidigt hastighetstest på flera LTE-modem
Resultatet av hastighetstestning, med en strikt vald en server.

Under testningen finns det "päls" på båda ställena och den måste tas bort med matematiska metoder. Men med en fast server är det något mindre och amplituden är mer stabil.
I allmänhet är detta en plats för stor forskning. Och jag skulle mäta hastigheten på min server med hjälp av iperf-verktyget. Men vi håller oss till de tekniska specifikationerna.

Skickar mail och fel

För att skicka e-post försökte jag flera dussin olika alternativ, men till slut bestämde jag mig för följande. Jag registrerade en brevlåda på Yandex och tog sedan Detta är ett exempel på att skicka e-post. Jag kontrollerade det och implementerade det i programmet. Det här exemplet undersöker olika alternativ, inklusive att skicka från gmail, etc. Jag ville inte bry mig om att ställa in min e-postserver och hade inte tid med det, men som det visade sig senare var det också förgäves.

Loggarna skickades enligt schemaläggaren, om det finns ett samband, var 6:e ​​timme: klockan 00, 06, 12 och 18. Skickade den enligt följande.

from send_email import *
...
message_log = "Логи тестирования платы №1"
EmailForSend = ["[email protected]", "[email protected]"]
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

Fel skickades också inledningsvis. Till att börja med ackumulerades de i listan och skickades sedan även med schemaläggaren, om det fanns en anslutning. Men sedan uppstod problem med det faktum att Yandex har en gräns för antalet meddelanden som skickas per dag (detta är smärta, sorg och förnedring). Eftersom det kunde vara ett stort antal fel även per minut, var vi tvungna att överge att skicka fel per post. Så kom ihåg när du automatiskt skickar information om ett sådant problem via Yandex-tjänster.

Feedbackserver

För att få tillgång till en fjärrstyrd maskinvara och kunna anpassa och konfigurera om den behövde jag en extern server. I allmänhet, för att vara rättvis, skulle det vara korrekt att skicka all data till servern och bygga alla vackra grafer i webbgränssnittet. Men inte allt på en gång.

För VPS valde jag ruvds.com. Du kan ta den enklaste servern. Och i allmänhet, för mina syften skulle detta vara tillräckligt. Men eftersom jag inte betalade för servern ur egen ficka, bestämde jag mig för att ta den med en liten reserv så att det skulle räcka om vi skulle distribuera ett webbgränssnitt, vår egen SMTP-server, VPN, etc. Plus, kunna ställa in en Telegram-bot och inte ha problem med att den blockeras. Därför valde jag Amsterdam och följande parametrar.

Samtidigt hastighetstest på flera LTE-modem

Som en metod för kommunikation med hårdvaran valde vim2 en omvänd ssh-anslutning och, som praxis har visat, är den inte den bästa. Om anslutningen bryts håller servern porten och det är omöjligt att ansluta via den under en tid. Därför är det fortfarande bättre att använda andra kommunikationsmetoder, till exempel VPN. I framtiden ville jag byta till VPN, men hade inte tid.

Jag kommer inte att gå in på detaljer om att sätta upp en brandvägg, begränsa rättigheter, inaktivera root ssh-anslutningar och andra truismer för att sätta upp en VPS. Jag skulle vilja tro att du redan vet allt. För en fjärranslutning skapar jag en ny användare på servern.

adduser vimssh

Jag genererar ssh-anslutningsnycklar på vår hårdvara.

ssh-keygen

Och jag kopierar dem till vår server.

ssh-copy-id [email protected]

På vår hårdvara skapar jag en automatisk omvänd ssh-anslutning vid varje start.

[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 [email protected]
RestartSec=5
Restart=always
[Install] WantedBy=multi-user.target

Var uppmärksam på port 8083: den bestämmer vilken port jag ska använda för att ansluta via omvänd ssh. Lägg till det i start och starta.

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

Du kan till och med se status:

sudo systemctl status autossh.service

Nu, på vår VPS-server, om vi kör:

ssh -p 8083 khadas@localhost

Sedan kommer jag till min testbit av hårdvara. Och från hårdvaran kan jag också skicka loggar och eventuell data via ssh till min server, vilket är väldigt bekvämt.

Att sätta allt ihop

Samtidigt hastighetstest på flera LTE-modem
Slå på, låt oss börja utveckla och felsöka

Puh, det är det, jag beskrev alla noder. Nu är det dags att få ihop allt. Du kan se koden just här.

En viktig punkt med koden: Det här projektet kanske inte startar så här, eftersom det var skräddarsytt för en specifik uppgift, av en specifik arkitektur. Även om jag ger källkoden kommer jag ändå att förklara de mest värdefulla sakerna här, direkt i texten, annars är det helt obegripligt.

I början initierar jag gps, gpio och startar en separat schemaläggartråd.

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

Schemaläggaren är ganska enkel: den ser ut om det är dags att skicka meddelanden och vad den aktuella felstatusen är. Om det finns en felflagga blinkar vi med lysdioden.

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

Den svåraste delen av detta projekt är att upprätthålla den omvända ssh-anslutningen för varje test. Varje test involverar omkonfigurering av standardgatewayen och DNS-servern. Eftersom ingen läser ändå, vet att tåget inte åker på träräls. Den som hittar påskägget får lite godis.

För att göra detta skapar jag en separat routingtabell -set-mark 0x2 och en regel för att omdirigera trafik.

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

Du kan lära dig mer om hur det fungerar läs i den här artikeln.

Därefter går jag in i en oändlig loop, där vi varje gång får en lista över anslutna modem (för att ta reda på om nätverkskonfigurationen plötsligt har ändrats).

network_list = getNetworklist()

Att få en lista över nätverksgränssnitt är ganska enkelt.

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

Efter att ha fått listan satte jag IP-adresser till alla gränssnitt, som jag visade på bilden i kapitlet om modemet.

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

Sedan går jag helt enkelt igenom varje gränssnitt i en slinga. Och jag konfigurerar varje gränssnitt.

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

Jag kontrollerar gränssnittet för funktionalitet, om det inte finns något nätverk, genererar jag fel. Om det finns ett nätverk är det dags att agera!

Här konfigurerar jag ssh-routing till detta gränssnitt (om det inte har gjorts), skickar fel till servern om det är dags, skickar loggar och kör slutligen ett speedtest och sparar loggarna till en csv-fil.

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()
#и далее тестируем скорость и сохраняем логи. 

Det är värt att nämna funktionen för att ställa in omvänd 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")

Och naturligtvis måste du lägga till all denna skönhet till start. För att göra detta skapar jag en fil:

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

Och jag skriver i den:

[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

Jag sätter på autoloading och börjar!

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

Nu kan jag se loggar över vad som händer med kommandot:

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

Resultat

Nåväl, nu är det viktigaste, vad hände som ett resultat? Här är några grafer som jag lyckades fånga under utvecklings- och felsökningsprocessen. Graferna byggdes med gnuplot med följande skript.

#! /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"

Den första erfarenheten var med Tele2-operatören, som jag genomförde under flera dagar.

Samtidigt hastighetstest på flera LTE-modem

Här använde jag en dynamisk mätserver. Hastighetsmätningar fungerar, men fluktuerar väldigt mycket, men ett visst medelvärde är fortfarande synligt, och detta kan erhållas genom att filtrera data, till exempel med ett glidande medelvärde.

Senare byggde jag ett antal grafer åt andra teleoperatörer. I det här fallet fanns det redan en testserver, och resultaten var också mycket intressanta.

Samtidigt hastighetstest på flera LTE-modem

Samtidigt hastighetstest på flera LTE-modem

Samtidigt hastighetstest på flera LTE-modem

Samtidigt hastighetstest på flera LTE-modem

Som du kan se är ämnet mycket omfattande för forskning och bearbetning av dessa data, och varar uppenbarligen inte under ett par veckors arbete. Men…

Resultatet av arbetet

Arbetet slutfördes plötsligt på grund av omständigheter utanför min kontroll. En av svagheterna med detta projekt, enligt min subjektiva uppfattning, var modemet, som egentligen inte ville arbeta samtidigt med andra modem, och gjorde sådana knep varje gång det laddades. För dessa ändamål finns det ett stort antal andra modemmodeller; vanligtvis är de redan i Mini PCI-e-formatet och är installerade inuti enheten och är mycket lättare att konfigurera. Men det är en helt annan historia. Projektet var intressant och jag var väldigt glad att jag fick delta i det.

Samtidigt hastighetstest på flera LTE-modem

Källa: will.com

Lägg en kommentar