Test de vitesse simultané sur plusieurs modems LTE

En quarantaine, on m'a proposé de participer au développement d'un dispositif de mesure de la vitesse des modems LTE pour plusieurs opérateurs mobiles.







Le client souhaitait évaluer la vitesse de tous types d'opérateurs télécoms dans différentes zones géographiques, afin de comprendre quel opérateur mobile est le plus optimal pour lui lors de l'installation d'équipements utilisant une connexion LTE, par exemple pour des diffusions vidéo. Dans le même temps, la tâche devait être résolue aussi simplement et à moindre coût que possible, sans équipement coûteux.



Je dois dire tout de suite que la tâche n'est pas la plus simple et la plus gourmande en connaissances, je vais vous dire quels problèmes j'ai rencontré et comment je les ai résolus. Alors allons-y.



Remarque



Mesurer la vitesse d'une connexion LTE est une question très difficile: vous devez choisir le bon équipement et la bonne méthode de mesure, et également avoir une bonne idée de la topologie et du fonctionnement du réseau cellulaire. De plus, la vitesse peut être influencée par plusieurs facteurs: le nombre d'abonnés par cellule, les conditions météorologiques, même d'une cellule à l'autre, la vitesse peut être très différente en raison de la topologie du réseau. En général, il s'agit d'un problème avec un grand nombre d'inconnues, et seul un opérateur télécom peut le résoudre correctement.



Au départ, le client voulait simplement conduire le courrier avec les téléphones des opérateurs, prendre des mesures directement sur le téléphone et ensuite noter les résultats de la mesure de la vitesse dans un ordinateur portable. Ma solution pour mesurer la vitesse des réseaux lte, bien que non idéale, résout le problème.



Par manque de temps, j'ai pris des décisions non pas en faveur de la commodité ou de l'aspect pratique, mais en faveur de la rapidité du développement. Par exemple, pour l'accès à distance, le reverse ssh a été lancé, au lieu du VPN plus pratique, afin de gagner du temps sur la configuration du serveur et de chaque client individuel.



Tâche technique



Comme indiqué dans l'article Sans TK: pourquoi le client ne le veut pas : ne travaillez pas sans TK! Jamais, nulle part!



La mission technique était assez simple, je vais l'élargir un peu pour comprendre l'utilisateur final. Le choix des solutions techniques et des équipements a été dicté par le client. Donc, le savoir traditionnel lui-même, après toutes les approbations:



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







csv. - 6 . , GPIO.


J'ai décrit les savoirs traditionnels sous une forme libre, après de nombreuses approbations. Mais le sens de la tâche est déjà visible. Le délai pour tout était fixé à une semaine. Mais en réalité, cela a duré trois semaines. Ceci étant donné que je ne l'ai fait qu'après le travail principal et le week-end.



Je voudrais ici attirer votre attention sur le fait que le client avait auparavant accepté d'utiliser le service et le matériel de mesure de la vitesse, ce qui limitait considérablement mes capacités. Le budget était également limité, donc rien n'a été acheté en plus. J'ai donc dû jouer selon ces règles.



Architecture et développement



Le schéma est simple et direct. Par conséquent, je vais le laisser sans commentaires particuliers.







J'ai décidé de mettre en œuvre l'ensemble du projet en python, malgré le fait que je n'avais aucune expérience de développement dans ce langage du tout. Je l'ai choisi car il y avait un tas d'exemples prêts à l'emploi et de solutions qui pourraient accélérer le développement. Par conséquent, je demande à tous les programmeurs professionnels de ne pas gronder ma première expérience en développement python, et je suis toujours heureux d'entendre des critiques constructives pour améliorer mes compétences.



Également dans le processus, j'ai découvert que python avait deux versions en cours d'exécution 2 et 3, en conséquence, je me suis arrêté à la troisième.



Nœuds matériels



Carte unique vim2



En tant que machine principale, j'ai reçu un vim2 monocarte







Une excellente combinaison multimédia puissante pour une maison intelligente et SMART-TV, mais extrêmement inadaptée à cette tâche, ou, dirons-nous, mal adaptée. Par exemple, son système d'exploitation principal est Android, et Linux est un système d'exploitation de passage, et donc personne ne garantit le fonctionnement de haute qualité de tous les nœuds et pilotes sous Linux. Et je suppose que certains des problèmes étaient liés aux pilotes USB de cette plate-forme, de sorte que les modems ne fonctionnaient pas comme prévu sur cette carte. Il a également une documentation très pauvre et dispersée, de sorte que chaque opération a pris beaucoup de temps à creuser dans les quais. Même le travail ordinaire avec GPIO buvait beaucoup de sang. Par exemple, il m'a fallu plusieurs heures pour configurer le travail avec la LED. Mais, pour être objectif, le type d'appareil monocarte n'était fondamentalement pas important, l'essentiel est qu'il fonctionne et dispose de ports USB.



Tout d'abord, je dois installer Linux sur cette carte. Afin de ne pas parcourir la jungle de la documentation pour tout le monde, ainsi que pour ceux qui traiteront de ce dispositif monocarte, j'Ă©cris ce chapitre.



Il existe deux options pour installer Linux: sur une carte SD externe ou sur une MMC interne. J'ai eu du mal avec la carte le soir, et je ne savais pas comment la faire fonctionner, j'ai donc décidé de l'installer sur MMC, même si sans aucun doute il serait beaucoup plus facile de travailler avec une carte externe.



Le firmware est décrit de manière tordue ici . Je traduis d'étrange en russe. Afin de flasher la carte, je dois connecter le matériel UART. Je l'ai connecté comme suit.



  • Outil Pin GND: <—> Pin17 du GPIO des VIM
  • Tool Pin TXD: <—> Pin18 du GPIO des VIM (Linux_Rx)
  • Tool Pin RXD: <—> Pin19 du GPIO des VIM (Linux_Tx)
  • Outil Pin VCC: <—> Pin20 du GPIO des VIM






Après cela, j'ai téléchargé le firmware à partir d'ici . La version spécifique du micrologiciel est VIM1_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231 .



Pour télécharger ce firmware, j'ai besoin de certains utilitaires. Cliquez ici pour en savoir plus . Je n’ai pas essayé de le flasher sous Windows, mais je dois vous dire quelques mots sur le firmware Linux. Tout d'abord, je vais installer les utilitaires conformément aux instructions.



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


Iii ... Rien ne fonctionne. J'ai passé quelques heures à éditer les scripts d'installation afin que tout soit correctement installé pour moi. Je ne me souviens pas de ce que j'ai fait là-bas, mais aussi de ce cirque avec des chevaux. Donc sois prudent. Mais sans ces utilitaires, il ne sert à rien de torturer davantage vim2. Mieux vaut ne pas le jouer du tout!



Après sept cercles d'enfer, la configuration et l'installation du script, j'ai reçu un paquet d'utilitaires fonctionnels. J'ai connecté la carte via USB à mon ordinateur Linux, et l'UART est également connecté selon le schéma ci-dessus.

Je règle mon terminal minicom préféré sur 115200, pas de contrôle des erreurs matérielles ou logicielles. Et commençons.







Lors du démarrage de VIM2 dans le terminal UART, j'appuie sur n'importe quelle touche, par exemple la barre d'espace, pour arrêter le démarrage. Après l'apparition de la ligne



kvim2# 


J'entre la commande:



kvim2# run update


Sur l'hôte à partir duquel nous téléchargeons, j'exécute:



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


Tout le monde, ouf. J'ai demandé, il y a Linux sur la carte. Login / mot de passe khadas: khadas.



Après cela, petits réglages initiaux. Pour plus de travail, je désactive le mot de passe pour sudo (oui, pas sécurisé, mais pratique).



sudo visudo


Je modifie la ligne dans la vue et je sauvegarde



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


Ensuite, je change la locale actuelle pour que l'heure soit Ă  Moscou, sinon ce sera GMT.



sudo timedatectl set-timezone Europe/Moscow


ou



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


Si vous trouvez cela difficile, n'utilisez pas cette carte, Raspberry Pi est meilleur. Juste.



Modem Huawei e3372h - 153



Ce modem a bien bu mon sang et, en fait, il est devenu le goulot d'étranglement de tout le projet. En général, le nom de «modem» pour ces appareils ne reflète pas du tout l'essence du travail: il s'agit d'une moissonneuse-batteuse puissante, ce matériel possède un appareil composite qui fait semblant d'être un CD-ROM pour installer les pilotes, puis passe en mode carte réseau.



Architecturalement, du point de vue d'un utilisateur Linux, après tous les paramètres, cela ressemble à ceci: après avoir connecté le modem, j'ai l'interface réseau eth *, qui reçoit l'adresse IP 192.168.8.100 via dhcp, et la passerelle par défaut 192.168.8.1.



Et le point le plus important! Ce modèle de modem ne sait pas fonctionner en mode modem, qui est contrôlé par des commandes AT... Tout serait beaucoup plus facile, créer des connexions ppp pour chaque modem et ensuite fonctionner avec eux. Mais dans mon cas, "moi-même" (plus précisément un plongeur Linux selon les règles udev), crée une interface eth et lui assigne une adresse IP via dhcp.



Afin de ne pas me confondre davantage, je propose d'oublier le mot «modem» et de dire une carte réseau et une passerelle, car en fait c'est comme connecter une nouvelle carte réseau à une passerelle.

Lorsqu'il y a un modem, cela ne pose aucun problème particulier, mais lorsqu'il y a plus d'un modem, à savoir n-pièces, l'image suivante du réseau apparaît.







Autrement dit, n cartes réseau, avec la même adresse IP, chacune avec la même passerelle par défaut. Mais en fait, chacun d'eux est connecté à son propre opérateur.



Au départ, j'avais une solution simple: utiliser la commande ifconfig ou ip pour éteindre toutes les interfaces et en activer une à son tour et la tester. La solution était bonne pour tout le monde, sauf que pendant les moments de commutation, je n'ai pas pu me connecter à l'appareil. Et comme la commutation est fréquente et rapide, en fait je n'ai eu aucune possibilité de me connecter.



Par conséquent, j'ai choisi la manière de changer "manuellement" les adresses IP des modems et de continuer à générer du trafic en utilisant les paramètres de routage.







Ce n'était pas la fin de mes problèmes avec les modems: en cas de problèmes d'alimentation, ils tombaient, une bonne alimentation stable du hub USB était nécessaire. Ce problème a été résolu en soudant durement l'alimentation électrique directement sur le hub. Autre problème auquel j'ai été confronté et qui a ruiné l'ensemble du projet: après un redémarrage ou un démarrage à froid de l'appareil, tous les modems n'ont pas été détectés et pas toujours, et pourquoi cela s'est produit et par quel algorithme je n'ai pas pu installer. Mais tout d'abord.



Pour que le modem fonctionne correctement, j'ai installé le package usb-modeswitch.



sudo apt update
sudo apt install -y usb-modeswitch


Après cela, le modem après la connexion sera correctement détecté et configuré par le sous-système udev. Je vérifie en branchant simplement le modem et en m'assurant que le réseau est actif.

Autre problème que je n'ai pas pu résoudre: comment obtenir le nom de l'opérateur avec lequel nous travaillons à partir de ce modem? Le nom de l'opérateur est contenu dans l'interface Web du modem au 192.168.8.1. Il s'agit d'une page Web dynamique qui reçoit des données via des requêtes ajax, vous ne pouvez donc pas simplement wget la page et analyser le nom. J'ai donc commencé à chercher comment créer une page Web, etc., et j'ai réalisé que je faisais des absurdités. En conséquence, il cracha et commença à recevoir l'opérateur en utilisant l'API du Speedtest lui-même.



Beaucoup de choses seraient plus faciles si le modem était accessible via des commandes AT. Il serait possible de le reconfigurer, de créer une connexion ppp, d'attribuer une adresse IP, d'obtenir un opérateur, etc. Mais hélas, je travaille avec ce que j'ai donné.



GPS



Le récepteur GPS qui m'a été fourni avait une interface UART et une alimentation. Ce n'était pas la meilleure solution, mais néanmoins elle fonctionnait et était simple. Le récepteur était quelque chose comme ça.







Pour être honnête, c'était la première fois que je travaillais avec un récepteur GPS, mais comme prévu, tout a été inventé pour nous il y a longtemps. Nous n'utilisons donc que des solutions toutes faites.



Tout d'abord, j'active uart_AO_B (UART_RX_AO_B, UART_TX_AO_B) pour connecter le GPS.



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


Ensuite, je vérifie le succès de l'opération.



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


Cette commande, apparemment, modifie devtree à la volée, ce qui est très pratique.



Une fois l'opération réussie, redémarrez et installez le démon gps.



khadas@Khadas:~$ sudo reboot


Installation du démon gps. J'installe tout et le coupe tout de suite pour une configuration ultérieure.



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


Modification du fichier de paramètres.



sudo vim /etc/default/gpsd


J'installe l'UART sur lequel le GPS va s'accrocher.



DEVICES="/dev/ttyS4"


Et puis on allume tout et on commence.



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


Après cela, je connecte le GPS.







Le fil GPS est entre les mains, les fils UART du débogueur sont visibles sous les doigts.



Je redémarre et vérifie le GPS à l'aide du programme gpsmon.







Dans cette capture d'écran, vous ne pouvez pas voir les satellites, mais vous pouvez voir la communication avec le récepteur GPS, ce qui indique que tout va bien.



En python, j'ai essayé de nombreuses options pour travailler avec ce démon, mais j'ai choisi celle qui fonctionnait correctement avec python 3.



Installez la bibliothèque requise.



sudo -H pip3 install gps3 


Et je sculpte le code du travail.



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


Si j'ai besoin d'obtenir les coordonnées, cela se fait par l'appel suivant:



longitude, latitude = getPositionData(agps_thread)


Et dans les 1 à 10 secondes, j'obtiendrai les coordonnées ou non. Oui, j'ai eu dix tentatives pour obtenir les coordonnées. Pas optimal, tordu et de travers, mais cela fonctionne. J'ai décidé de le faire, car le GPS peut mal capter et ne pas toujours recevoir de données. Si vous attendez que les données soient reçues, si vous travaillez dans une pièce éloignée, le programme se figera à cet endroit. Par conséquent, j'ai implémenté une option si peu élégante.



En principe, il y aurait plus de temps, il serait possible de recevoir des données du GPS directement via UART, de les analyser dans un flux séparé et de travailler avec elles. Mais il n'y avait pas du tout de temps, d'où le code horrible et laid. Et oui, je n'ai pas honte.



Diode Ă©lectro-luminescente



La connexion de la LED était simple et compliquée à la fois. La principale difficulté est que le numéro de broche dans le système ne correspond pas au numéro de broche sur la carte et que la documentation est écrite avec le talon gauche. Pour faire correspondre le numéro de broche matériel et le numéro de broche dans le système d'exploitation, vous devez exécuter la commande:



gpio readall


Un tableau de correspondance des broches dans le système et sur le tableau sera affiché. Après cela, je peux déjà utiliser la broche dans le système d'exploitation lui-même. Dans mon cas, la LED est connectée à GPIOH_5 .







Je transfère la broche GPIO en mode sortie.



gpio -g mode 421 out


J'écris zéro.



gpio -g write 421 0


J'en Ă©cris un.



gpio -g write 421 1




Tout est allumé, après l'enregistrement de "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)


Maintenant, en cas d'erreur, j'appelle error_blink () et la LED clignote bien pour nous.



NĹ“uds logiciels



API Speedtest



C'est une grande joie que le service speedtest.net ait sa propre API python, vous pouvez le voir sur Github .



La bonne nouvelle est qu'il existe des codes sources qui peuvent également être consultés. Comment travailler avec cette API (les exemples les plus simples) peuvent être trouvés dans la section correspondante .



Installez la bibliothèque python avec la commande suivante.



sudo -H pip3 install speedtest-cli


Par exemple, vous pouvez même installer le testeur de vitesse dans Ubuntu directement à partir du représentant. Il s'agit de la même application python que vous pouvez ensuite exécuter directement depuis la console.



sudo apt install speedtest-cli -y


Et mesurez la vitesse de votre Internet. En conséquence, comme je l'ai fait. J'ai dû fouiller dans les codes sources de ce speedtest afin de les implémenter plus pleinement dans mon projet. L'une des tâches les plus importantes est d'obtenir le nom de l'opérateur télécom afin de le remplacer dans la plaque.



speedtest-cli

Retrieving speedtest.net configuration...

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

Retrieving speedtest.net server list...

Selecting best server based on ping...

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

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

Download: 7.10 Mbit/s

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

Upload: 3.86 Mbit/s








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

#       csv-.
#  GPS
longitude, latitude = getPositionData(agps_thread)
#  
curdata = datetime.now().strftime('%d.%m.%Y')
curtime = datetime.now().strftime('%H:%M:%S')
delimiter = ';'
result_string = opos + delimiter + str(curpos) + delimiter + \
	curdata + delimiter + curtime + delimiter + longitude + ', ' + latitude + delimiter + \
	str(s.results.download/1000.0/1000.0) + delimiter + str(s.results.upload / 1000.0 / 1000.0) + \
	delimiter + str(s.results.ping) + delimiter + testserver + "\n"
#     


Ici aussi, tout s'est avéré moins simple, même si cela semblerait beaucoup plus facile. Au départ, le paramètre des serveurs était égal à [] , disent-ils, choisissez le meilleur serveur. En conséquence, j'avais des serveurs aléatoires et, comme vous pouvez le deviner, une vitesse flottante. C'est un sujet assez complexe, l'utilisation d'un serveur fixe, si oui, alors statique ou dynamique, nécessite des recherches. Mais voici un exemple de graphique pour mesurer la vitesse de l'opérateur Beeline avec une sélection dynamique d'un serveur de test et un serveur fixe statiquement.





Le résultat de la mesure de la vitesse lors du choix d'un serveur dynamique.





Résultat du test de vitesse, avec un serveur strictement sélectionné.



La «laine» pendant les tests est là et là, et elle doit être éliminée par des méthodes mathématiques. Mais avec un serveur fixe, c'est légèrement moins et l'amplitude est plus stable.

En général, c'est un lieu de grandes recherches. Et je mesurerais la vitesse de mon serveur en utilisant l'utilitaire iperf. Mais nous nous en tenons aux savoirs traditionnels.



Envoi d'e-mails et d'erreurs



J'ai essayé plusieurs douzaines d'options différentes pour envoyer du courrier, mais en conséquence j'ai choisi ce qui suit. J'ai enregistré une boîte aux lettres sur yandex, puis j'ai pris cet exemple d'envoi de courrier . Je l'ai vérifié et mis en œuvre dans le programme. Cet exemple explore diverses options, y compris l'envoi depuis Gmail, etc. Je ne voulais pas me soucier d'élever mon serveur de messagerie et je n'ai pas eu le temps pour cela, mais comme il s'est avéré plus tard, c'était également en vain.



Les logs étaient envoyés selon le planificateur, s'il y avait une connexion , toutes les 6 heures: à 00 heures, 06 heures, 12 heures et 18 heures. Je l'ai envoyé comme suit.



from send_email import *
...
message_log = "   â„–1"
EmailForSend = ["dlinyj@trololo.ru", "pupkin@trololo.ru"]
files = ["/home/khadas/modems_speedtest/csv"]
...
def sendLogs():
	global EmailForSend
	curdata = datetime.now().strftime('%d.%m.%Y')
	urtime = datetime.now().strftime('%H:%M:%S')
	try:
		for addr_to in EmailForSend:
			send_email(addr_to, message_log, "  " + curdata + " " + urtime, files)
	except:
		print("Network problem for send mail")
		return False
	return True


Des erreurs ont également été initialement soumises. Pour commencer, ils se sont accumulés dans la liste, puis les ont envoyés également en utilisant le planificateur, s'il y avait une connexion. Cependant, il y a eu des problèmes avec le fait que yandex a une limite sur le nombre de messages envoyés par jour (c'est la douleur, la tristesse et l'humiliation). Puisqu'il pouvait y avoir un grand nombre d'erreurs même en une minute, il était nécessaire de refuser d'envoyer les erreurs par courrier. Gardez donc à l'esprit lors de l'envoi automatique via les services Yandex d'un tel problème.



Serveur de commentaires



Pour avoir accès à un matériel distant et pouvoir le modifier et le reconfigurer, j'avais besoin d'un serveur externe. En général, en toute honnêteté, il serait correct d'envoyer toutes les données au serveur et de créer tous les beaux graphiques dans l'interface Web. Mais pas tous à la fois.



J'ai choisi ruvds.com comme VPS . Le serveur le plus simple pourrait être pris. Et en général, pour mes besoins, ce serait suffisant pour les yeux. Mais comme je ne payais pas le serveur de ma poche, j'ai décidé de le prendre avec une petite marge, pour qu'il suffise de déployer une interface Web, notre propre serveur SMTP, vpn, etc. De plus, pour pouvoir configurer un bot Telegram et ne pas avoir de problèmes pour le bloquer. Par conséquent, j'ai choisi Amsterdam et les paramètres suivants.







Pour communiquer avec un matériel, vim2 a choisi une connexion SSH inversée, et comme la pratique l'a montré, ce n'est pas la meilleure. Si la connexion est interrompue, le serveur détient le port et il est impossible de s'y connecter pendant un certain temps. Par conséquent, il est toujours préférable d'utiliser d'autres méthodes de communication, par exemple vpn. À l'avenir, je voulais passer au VPN, mais je n'ai pas eu le temps.



Je n'entrerai pas dans les détails de la configuration d'un pare-feu, de la limitation des droits, de la désactivation des connexions root ssh et d'autres vérités courantes des paramètres VPS. J'aimerais croire que vous savez déjà tout. Pour une connexion à distance, je crée un nouvel utilisateur sur le serveur.



adduser vimssh


Sur notre matériel, je génère des clés de connexion ssh.



ssh-keygen


Et je les copie sur notre serveur.



ssh-copy-id vimssh@host.com


Sur notre matériel, je crée une connexion automatique du ssh inversé à chaque démarrage. Faites attention au port 8083: il détermine sur quel port je vais me connecter via ssh inversé. Ajouter au démarrage et démarrer.



[Unit]

Description=Auto Reverse SSH

Requires=systemd-networkd-wait-online.service

After=systemd-networkd-wait-online.service

[Service]

User=khadas

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

RestartSec=5

Restart=always

[Install]

WantedBy=multi-user.target








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


Vous pouvez mĂŞme voir le statut:



sudo systemctl status autossh.service


Maintenant, sur notre serveur VPS, si vous exécutez:



ssh -p 8083 khadas@localhost


Ensuite, j'arrive à ma pièce de test. Et à partir du morceau de fer, je peux également envoyer des journaux et des données via ssh à mon serveur, ce qui est très pratique.



Mettre tous ensemble









Allumant , nous commençons à développer et à déboguer Fuh, eh bien, tout semble avoir décrit tous les nœuds. Il est maintenant temps de tout rassembler. Le code peut être consulté ici .



Un point important avec le code: ce projet comme ce "vlob" peut ne pas démarrer, car il a été affiné sur une tâche spécifique d'une architecture spécifique. Bien que je donne le code source, j'analyserai toujours le plus précieux ici, directement dans le texte, sinon c'est complètement incompréhensible.



Au début, j'ai l'initialisation de gps, gpio et le lancement d'un thread de planification séparé.



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


Le planificateur est assez simple: il cherche Ă  voir si le moment est venu d'envoyer des messages et quel est le statut d'erreur maintenant. S'il y a un indicateur d'erreur, faites clignoter la 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)


Le point le plus difficile de ce projet est de conserver la connexion ssh inversée à chaque test. Dans chaque test, la passerelle par défaut et le serveur DNS sont reconfigurés. Puisque personne ne lit de toute façon, sachez que le train ne roule pas sur des rails en bois. Celui qui trouve un œuf de Pâques aura la dent sucrée.



Pour ce faire, je crée une table de routage séparée --set-mark 0x2 et une règle pour rediriger le trafic.



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


Vous pouvez en savoir plus sur la façon dont cela fonctionne dans cet article .



Ensuite, je rentre dans une boucle sans fin, où à chaque fois nous obtenons une liste de modems connectés (pour savoir si la configuration du réseau a changé).



network_list = getNetworklist()


Obtenir une liste des interfaces réseau est assez simple.



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


Après avoir reçu la liste, j'attribue des adresses IP à toutes les interfaces, comme je l'ai montré dans l'image dans le chapitre sur le 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")


Ensuite, je parcours chaque interface en boucle. Et je configure chaque interface.



	for iface in network_list:
		ConfigNetwork(iface)


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


Je vérifie l'opérabilité de l'interface, s'il n'y a pas de réseau, je génère des erreurs. S'il y a un réseau, alors il est temps d'agir!



Ici, j'ai configuré le routage ssh vers cette interface (si cela n'a pas été fait), envoyer des erreurs au serveur, si le moment est venu, envoyer des journaux et enfin exécuter un test de vitesse et enregistrer les journaux dans un fichier csv.



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


Sauf pour la fonction de configuration inverse 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")


Et bien sûr, vous devez ajouter toute cette beauté au démarrage. Pour ce faire, je crée un fichier:



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


Et j'écris dedans: j'active le chargement automatique et je démarre!



[Unit]

Description=Modem Speed Test

Requires=systemd-networkd-wait-online.service

After=systemd-networkd-wait-online.service

[Service]

User=khadas

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

RestartSec=5

Restart=always

[Install]

WantedBy=multi-user.target








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


Maintenant, je peux regarder les journaux de ce qui se passe en utilisant la commande:



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


résultats



Eh bien, maintenant, la chose la plus importante est ce qui s'est passé en conséquence? Voici quelques graphiques que j'ai réussi à capturer pendant le processus de développement et de débogage. Les graphiques ont été construits en utilisant gnuplot avec le script suivant.



#! /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 première expérience a été l'opérateur Tele2, que j'ai passé plusieurs jours.







J'ai utilisé un serveur de comptage dynamique ici. Les mesures de vitesse fonctionnent, mais elles flottent beaucoup, cependant, une certaine valeur moyenne est encore visible, et elle peut être obtenue en filtrant les données, par exemple, avec une moyenne mobile.



Plus tard, j'ai construit une série de graphiques pour d'autres opérateurs télécoms. Dans ce cas, il y avait déjà un serveur de test, et les résultats sont également très intéressants.



















Comme vous pouvez le voir, le sujet est très vaste pour la recherche et le traitement de ces données, et ne dure manifestement pas quelques semaines de travail. Mais…



RĂ©sultat des travaux



Les travaux ont été brusquement terminés en raison de circonstances indépendantes de ma volonté. L'une des faiblesses de ce projet, à mon avis subjectif, était le modem, qui ne voulait pas vraiment fonctionner simultanément avec d'autres modems, et faisait de telles astuces à chaque démarrage. À ces fins, il existe un grand nombre d'autres modèles de modems, généralement ils ont déjà le format Mini PCI-e et sont installés à l'intérieur de l'appareil et sont beaucoup plus faciles à configurer. Mais c'est une histoire complètement différente. Le projet était intéressant et très heureux que nous ayons réussi à y participer.






All Articles