Möchte man mehrere dezentrale Standpunkte in einem Mesh-Network miteinander verbinden, so bieten sich in der Regel Lösungen mittels eines VPN an. Diese sind oftmals auch mit wenig Aufwand eingerichtet, können aber mitunter gewisse Nachteile mit sich bringen. Einer dieser Nachteile betrifft zum Beispiel den Aufbau der Routing-Tabelle, wenn sich das VPN nicht vollständig wie der physikalische Counterpart verhält. Dies ist bei Tinc, einer sehr einfach nutzbaren VPN-Software der Fall, die bei Nutzung des Switch-Modus das gesamte VPN als eine Broadcast-Domäne betrachtet. Da in der Regel aber nicht wirklich jeder VPN-Client mit jedem anderen kommuniziert, führt dies zum Verlust von Struktur-Informationen bei Mesh-Netzwerken, die mittels Broadcast versuchen, die Netzwerk-Struktur zu erkunden. Einer der bekanntesten Vertreter ist hierbei OLSR, was auf Grund dieses Verhaltens haufenweise „virtuelle“ Verbindungen zwischen den VPN-Clients sieht, die real nicht existieren, was mitunter zu ungünstigen Verhaltensweisen beim Aufbau der Routingtabelle führt.
Lösungsansätze gibt es für diese Problematik nun mehrere, wobei die offensichtliche, nämlich Tinc das Broadcasten über nicht-existente Verbindungen abzugewöhnen leider nicht möglich ist, ohne größere Teile von Tinc anzupassen. Da somit der Weg zu einer Lösung auf Netzwerk-Ebene seitens Tinc nicht ohne größere Steine im Weg beschritten werden kann, und auch das partielle Blocken geforwardeter Broadcasts via iptables nicht ganz nebeneffektfrei funktioniert, blieb also nur die Chance, das etwas ungünstige Verhalten von Tinc auf der Seite von OLSR zu korrigieren.
Diese Korrektur erwies sich nach etwas Suche als durchaus recht einfach realisierbar, da OLSR von Haus aus die Möglichkeit bietet, bestimmte Verbindungen virtuell zu verschlechtern, d.h. selbst wenn alles ankommen mag, trotzdem in Bezug auf die Routing-Entscheidungen so zu tun, als ob eine bestimmte Verbindung nicht vorhanden wäre. Der hierfür benötigte Parameter heißt LinkQualityMult und benötigt eine IP, sowie einen Faktor, um den die Verbindung virtuell „verschlechtert“ wahrgenommen werden soll.
Nun ist es recht müßig, OLSR jedes Mal umzukonfigurieren, wenn Tinc eine Neue Verbindung aufbaut oder Abbaut oder wenn ein neuer Knoten im VPN bekannt gemacht werden muss. Die Einfachheit der Idee ist aber auch gerade ihr Potential für die programmatische Umsetzung. Denn glücklicherweise bietet Tinc die Möglichkeit, sich in regelmäßigen Abständen ein Graph Dump File schreiben zu lassen, in dem alle im VPN vorhandenen Meta-Verbindungen aufgeführt sind. Nun sind Meta-Verbindungen nicht gleich direkte TCP-Verbindungen, aber für den beabsichtigten Zweck ist der Unterschied vernachlässigbar. Das einfache Format – die Datei ist im dot-Format, ohne große Schnörkel – erlaubt es zudem, mit einfachsten Mittel die benötigten Informationen auszulesen. Erste Versuche mit Bash-Einzeilern lieferten somit schnell das gewünschte Ergebnis, d.h. die direkten Verbindungen:
MYNODE=node_42_foo grep ' -> ' /var/tmp/tinc.mynetwork.dot|sort -n|grep $MYNODE|tr ";" " "|cut '-d ' -f3|grep -v $MYNODE
Nun ist ein Shellscript vergleichsweise langsam und zudem lässt sich damit OLSR nicht ohne weiteres „in memory“ umkonfigurieren. Durch meine Arbeit an einem anderen OLSR-Plugin (für’s ARP-Roaming, ich berichtete ^^) lag auf meiner Platte ein wunderbares Template, was sich binnen 2 Tagen von Idee bis fertigem, funktionierendem Code umarbeiten ließ.
Das Plugin bietet dabei sogar zwahlreiche Konfigurationsmöglichkeiten, wobei einige davon derzeit noch nicht vollständig verwendet werden:
LoadPlugin "/usr/lib/olsrd_tinclqmult.so.0.1"
{
PlParam "Interface" "tun0"
PlParam "DbgLogfile" "/var/tmp/olsr_tinclqmult.log"
PlParam "TincNetwork" "Network"
PlParam "TincGraph" "/var/tmp/tinc.Network.dot"
PlParam "TincPID" "/var/run/tinc.Network.pid"
PlParam "LinkQualityDefault" "0.1"
PlParam "LinkQualityDirect" "1.0"
PlParam "LinkQualityStatic" "0.5"
PlParam "NodeNetwork" "10.0.0.0/8"
PlParam "NodeScheme" "node_%d_"
}
Die verwendeten Parameter-Namen sprechen hierbei in weiten Teilen für sich. So gibt „Interface“ an, auf welchem Interface der Tinc-Traffic ankommt. Zu beachten ist, dass aus technischen Gründen dieses Interface separat von anderen konfiguriert werden muss, um zu garantieren, dass sich das Plugin nicht mit anderen Interfaces behakt.
Im „DbgLogfile“ stehen einige Ausgaben über die Arbeit des Plugins. Da dieses derzeit noch sehr fleißig über OLSR Ausgaben erzeugt, wird das Logfile bisher nicht weiter beachtet.
Die 3 interessanten Parameter für Tinc sind nun „TincNetwork“, der Name des Tinc-Netzwerkes, welches überwacht wird, „TincGraph“, die mittels „GraphDumpFile“ in der Tinc-Konfiguration hinterlegte Datei mit den Verbindungen und „TincPID“, der Pfad zur PID-File des Tinc-Netzwerkes. Letztere wird dazu verwendet, um festzustellen, ob das angegebene Tinc-Netzwerk gerade aktiv ist, um ggf. in einen Fallback-Modus zu gehen.
Die Magie des Plugins kann schließlich mit Hilfe der Parameter „LinkQualityDefault“, „LinkQualityDirect“ und „LinkQualityStatic“ beeinflusst werden. Der „LinkQualityDefault“-Wert gibt dabei an, welche LinkQuality unkonfigurierte Verbindungen maximal erreichen können. Dieser Wert sollte vergleichsweise niedrig sein. Mit „LinkQualityStatic“ gibt man an, wie gut statisch in der OLSR-Konfiguration eingetragene Links maximal werden können. Und mit „LinkQualityDirect“ gibt man schließlich an, wie die via Graph Dump File bestätigten Verbindungen zu bewerten sind. Hierbei haben Direktverbindungen immer Vorrang vor statischen Verbindungen. Außerdem wird der Defaultwert nur für Knoten herangezogen, die weder statisch konfiguriert sind, noch eine Direktverbindung durch Tinc besitzen.
Um dem Plugin nun zu ermöglichen, anhand der Knotennamen von Tinc auf die zugehörige IP bei OLSR für entfernte Knoten zu schließen, benötigt man die letzten beiden Optionen: Während die erste Option („NodeNetwork“ angibt, aus welchem Netzbereich IPs stammen, legt die zweite Option das Namensschema fest. Im obigen Beispiel wären die Knoten mit node_1_foo, node_2_bar, node_3_baz durchnummeriert, wobei die IP für node_1_foo mit 10.0.0.1, für node_2_bar mit 10.0.0.2 und für node_3_baz mit 10.0.0.3 angenommen wird. Sollte man mehr als 255 Knoten haben, geht das natürlich auch: node_256_quo hätte für das Plugin die IP 10.0.1.0. IPv6-Support ist aber leider noch nicht vorhanden, sollte aber mit relativ wenigen Handgriffen nachrüstbar sein.
Seinen Zweck hat das Plugin aber bereits jetzt erfüllt: Die Anzahl virtueller Verbindungen in einem doch bereits recht großen Freifunk-Netzwerk mit VPN konnten stark reduziert werden, was den OLSR-Traffic zumindest ein wenig reduziert hat. Herunterzuladen gibt’s das Plugin beim Freifunk Chemnitz im SVN. Das Plugin spielt zusammen mit OLSR v0.6.1 und Tinc 1.0.13. Tinc 1.1.x bietet eine etwas andere API, die ich mir ggf. mal anschauen werde. Da es aber sicherlich längerfristig keine Umstellung auf Tinc 1.1.x im Netz kommeen wird, ist da der Bedarf derzeit eher gering.
Über Bugreports würde ich mich freuen. Von zumindest einem unerklärlichen Segfault beim Beenden (wenn upldatelqmult aufgerufen wird) weiß ich. Da das aber nicht zwingend notwendig ist, ist die Zeile derzeit auskommentiert. Darum kümmert sich das Plugin eh beim Aufräumen in der Folgezeile (wenn auch nicht so gründlich wie es das updatelqmult machen würde).