f.zz.de
posts /

Random number generator

Posted Tue Mar 7 13:16:14 2017 Florian Lohoff in

Es ist schon spannend wie man sich so die Karten legen kann und das monatelang nicht findet. Ich habe für das Monitoring mit Icinga2 einen interface check in c++ geschrieben der alle möglichen Dinge pollt. D.h. nicht nur die Standard ifAdminStatus oder ifOperStatus sondern auch ifIn/OutPackets, Bytes, Errors, Discards etc. Dann gibt es Schwellwerte die überwacht werden. Zusätzlich polle ich noch die optischen Pegel der SFPs d.h. rxPower, txPower, Current und Temperature.

Das ganze fliesst dann über eine Influxdb in ein Grafana um es sich ansprechend ansehen zu können.

Leider hatte ich seit dem Umzug von einer VM auf richtige Hardware das Problem das immer wieder sporadisch Messwerte fehlten oder auch auch mal kaputt waren d.h. eindeutig falsche Messwerte. Die Fehlermeldungen die ich jedoch sah war "SNMP Timeout" als wenn das Gerät nicht antworten würde.

Also mit tcpdump mal nachgesehen und nein - Es werden alle requests beantwortet. Nach einer Schleife mit der SNMP library snmp++, in der das timeout handling auch noch kaputt war, war ich noch ratloser als vorher.

Bis ich heute mal debug logging eingebaut habe und feststellte das zu dem Zeitpunkt wenn die SNMP Timeouts auftreten alle Requests für das Device eine identische RequestID haben.

Die RequestID wird typischerweise dafür verwendet, das das Target retransmits erkennen kann. D.h. sollte es einen SNMP Request bekommen wird die Antwort erzeugt und diese Antwort zusammen mit der RequestID in einen cache gepackt. Sollte dann ein transmit kommen wird der request mit der Antwort aus dem cache beantwortet um ein paar CPU cycles zu sparen.

Wenn jetzt natürlich unterschiedliche Interfaces und EntitySensors gepollt werden, und alle mit einer identischen RequestID, dann kommen natürlich willkürliche Antworten zurück, je nachdem welcher Request zuerst bearbeitet wurde.

Wenn die Anzahl der Variable bindings aber nicht passt wird jedoch natürlich die Antwort verworfen. Wenn jedoch die Antwort passt d.h. es ist auch Interface oder auch ein EntitySensor werden die Daten durcheinandergewürfelt. TengigabitEthernet0/0/1/0 daten tauchen dann auf TengigabitEthernet0/2/3/2 auf ... Das alles absolut unvorhersagbar und willkürlich.

Des Rätsels Lösung war, das der random number generator initialisiert werden muss. In Wirklichkeit ist das ja nur ein "Pseudo Random Number Generator" PRNG. Dieser erzeugt für ein Seed immer dieselbe Reihe an Zufallszahlen.

Wenn man den Random Number Generator jetzt mit "time(0)" initialisiert, kommt natürlich für alle Prozesse die in derselben Sekunde gestartet werden identische Zufallszahlen bei raus. Es fehlt an Entropie.

Der schnelle fix ist ein

std::srand(std::time(0)^getpid());

gewesen. Der nimmt dann nicht nur die Zeit sondern ein XOR zwischen Zeit und Process ID. Immer noch nicht optimal, aber zumindest fixed es das Problem das zeitgleich gestartete Prozesse identische Zufallszahlen verwenden.