Bird: strange next-hop

Nach meinem Umzug auf OpenWRT kam ich in den Genuss, das bei einem Reconnect nicht jeder Dienst neu gestartet wird. Leider hatte dieses „normale“ verhalten dazu geführt, das BIRD nicht mehr alle Routen propagiert hat. Das Problem: Es tauchten unvermittelt meldungen in folgendem Format im Syslog auf:

KRT: Received route 192.168.100.128/25 with strange next-hop 192.168.100.130

Zu Meldungen dieser Art kommt es wenn eine Routing-Regel aus der Kernel-Routing Tabelle gelernt wird, die ein direkt angeschlossenes Netz über einen entfernten Gateway schleifen will. Typisch für P-T-P und P-T-MP Verbindung wie OpenVPN oder PPPD. Interessanterweise stört BIRD das nur bei neu erlernten Routen. Ist die Route beim Dienst-Start schon in der Routing-Tabelle gibt es keine Probleme. Die Meldung kann man Unterdrücken, was jedoch stört ist die Tatsache, dass die entsprechende Routing-Rule nicht an die anderen Protokolle übertragen wird. Die möglichen Lösungen:

  • Eine statische Route über das Interface definieren und via Filter verhindern, dass diese Route zurück in den Kernel geschrieben wird.
  • BIRD nach einem Reconnect neu starten.
  • Diverse Protokolle bieten es an Netzwerke zu propagieren, die sie eigentlich nicht kennen. Unter OSPF kann man z.B. ein stubnet Konfigurieren. Dies hat den Charme, dass man der Route gleich entsprechende Kosten auferlegen kann. Die Route wird nur an die OSPF-Neighbors weitergereicht nicht an irgendein ein anderes Protokoll in der BIRD Instanz.

Welche der Lösungen man wählt hängt wohl vom Einsatzgebiet ab, ich hab mich für letztere entscheiden.

BIRD manuel auf DD-WRT einrichten

Wenn man die Buffalo DD-WRT Version einsetzt und Routing (RIP, OSPF, BGP) aktiviert und sich danach nichts tut, sollte man mal mittels SSH Kontrollieren ob überhaupt ein Routing-Dienst läuft. Dazu muss man erst mal raus finden welcher dienst überhaupt laufen sollte. Das geht ganz einfach. In der Konsole versuchen „zebrad“ oder „bird“ aufrufen. Schlägt letzterer an muss man wie folgt vorgehen um den BIRD „manuell“ einzurichten.

Als erstet den Router-Modus zurückstellen auf „Gateway“, nicht das einem die Einstellungen aus der WebGUI in die Suppe spucken. Anschließend erstellt man das Verzeichnis /tmp/bird und die Datei /tmp/bird/bird.conf. Diese Datei gestaltet man nach seinen Wünschen und startet dann den BIRD.

mkdir /tmp/bird
vi /tmp/bird/bird.conf
bird

Eine Beispiel-Config findet man hier: Routing unter Ubuntu

Um das ganze zu automatisieren, muss die Config-Datei im NVRam hinterlegen.

nvram set zebra_conf="$(cat /tmp/bird/bird.conf)"
nvram commit

Beim Systemstart muss mittels des Startup-Skriptes das Verzeichnis und die Config-Datei angelegt werden.

mkdir /tmp/bird
nvram get zebra_conf > /tmp/bird/bird.conf

Den BIRD nicht beim Systemstart starten. Leider schießt die ServiceKontrolle/ProcessMonitor den BIRD automatisch ab wenn er da ist und ein Interface hochfährt (oder sich allgemein was ändert). Da die Speichervariablen (die ich noch nicht ermitteln konnte) keinen BIRD-Start vorsehen, wird er leider nicht nach gestartet.
Der richtige „Ort“ zum startet den BIRD ist daher das Firewall-Scriptes. Das wird immer ausgeführt, sobald sich an den Interfaces was ändern und ganz wichtig, es ist das letzte Skript.

if [ -ne $(pidof bird) ]; then
bird
fi

Das IF-Statement verhindert nur, dass der BIRD nochmal gestartet wird, wenn er schon existiert.

Routing unter Ubuntu

Einen Text mit viel „Bla-Bla“ hatte ich heute schon, jetzt gibt es Technisches!

Will man unter Ubuntu einen „echten“ Router betreiben, also dynamisch auf die Netzwerkumgebung reagieren, stehen zwei Routing-Suites zur Verfügung: BIRD und Quagga. Beide unterstützen die wichtigsten Routing-Protokolle: BGP, RIP, OSPF

Wichtiger Hinweis vorweg: in Ubuntu 10.04 wird BIRD noch in Version 1.1.5 ausgeliefert. Die ist mal gut zwei Jahre alt und Unterstützt noch nicht alle Funktionen. Entweder akzeptiert man diese Schwächen oder nutzt das PPA des CZ.NIC Labs.

Die Quagga-Suite ist schon seit einiger Zeit am Markt. Sie bietet ein Config-Interface das einem CISCO Router gleicht. Man kann sowohl Config Files hinterlegen als auch „on the fly“ Config Befehle geben und die entsprechende Config dann raus schreiben (ganz wie bei CISCO Routern). Im Hintergrund werden bei Quagga für jedes Routing-Prokoll ein eigener Dienst gestartet und jeder dieser Dienste macht einen TELNET Port auf. Diesen kann man auf den Localhost beschränken oder so konfigurieren, dass er jede Anfrage ablehnt (kein Password angeben).

Bird befindet sich aktuell noch in der (Weiter-)Entwicklung. Zudem wirkt es auf mich schlanker. Es wird nur ein Dienst gestartet, die Config befindet sich in einer Datei und wirkt übersichtlicher. Neben diesen „Geschmacksfragen“ soll BIRD leistungsschonender sein.[1. Quelle: Vergleich BIRD/Quagga] Laut Wiki kommt er vor allem deswegen in den großen „Verteilerknoten“ zum Einsatz. [2. Quelle: Wikipedia] Dafür spricht auf jeden Fall, dass bei DD-WRT Firmwares für wenig Speicher der BIRD zum Einsatz kommt und bei viel Speicher die Quagga-Suite.

Ich habe beide Implementierungen gezwungenermaßen durch meine Routern im Einsatz. Beim Ubuntu-Router hatte ich die Wahl und mich nach einem kleinen Quagga Test für BIRD entschieden.

Wichtig: Die meisten Routing-Protokolle nutzten MultiCast-Addressen für ihre Kommunikation. Damit das funktioniert muss man eine entsprechende Route hinterlegen.

route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0

Beispiel – Konfiguration BIRD

Einfach über apt-get oder aptitude bird installieren und schon kann es losgehen.

aptitude install bird

Danach kann man die /etc/bird.conf bearbeiten.

log syslog all;
router id 10.1.0.1;

protocol kernel {
        export all;
        learn;
}

protocol device {
        scan time 60;
}

protocol ospf {
        debug { states, routes, interfaces };
        area 0 {
                interface "eth0" 10.1.0.0/16 {
                        cost 10;
                        stub;
                        check link;
                };
                interface "eth1" 10.2.0.0/16 {
                        priority 10;
                        cost 100;
                        type broadcast;
                        hello 30; retransmit 5; wait 10; dead 120;
                        authentication none;
                        check link;
                };
                interface "eth2" 10.3.0.0/16 {
                        priority 10;
                        cost 10;
                        type broadcast;
                        hello 30; retransmit 5; wait 10; dead 120;
                        authentication none;
                        check link;
                };
        };
}

Die Config dürfte selbsterklärend sein. Ein paar Hinweise zum Umgang mit BIRD:

  • Das Kernel-Protokoll wird gebraucht. Ohne die „export all;“ Regel werden keine Routen an das OS bekanntgegeben.
  • Hat man Default-Routen oder pflegt händisch welche über den „route“-Befehl nach, sollte die über das „learn“-Statement von BIRD ermittelt werden.
  • Alle lokalen Netze, die den Nachbarn mitgeteilt werden sollen, benötigen ein interface-Statement. Das stub-Statement markiert Interfaces die nur „announced“ werden sollen aber sonst keine Funktion haben.
  • Wenn man einen PPPoE-DSL-Uplink als Default-Route verwendet, sollte man das PPPoE Interface nicht als Area-Interface hinterlegen.
  • „check link“ funktioniert nur, wenn man neuerere BIRD-Versionen benutzt. BIRD 1.1.5 meckert einen Syntax-Fehler an.

 Beispiel – Konfiguration Quagga

Installation:

aptitude install quagga

Quagga ist anfangs etwas komplizierter. Anfangs muss man erst mal die benötigten Dienste unter /etc/quagga/daemons freischalten. Will man, dass diese Dienste per TelNet auch Remote konfigurierbar sind muss man noch in der /etc/quagga/debian.conf Anpassungen vornehmen.

Auf jeden Fall benötigt man den zebra-Dienst. Dieser ist das „protocol kernel“ Pendant. Zusätzlich muss man noch den Dienst für das gewünschte Protokoll aktivieren. Für den einfachen Einstieg findet man Beispiel-Konfigurationen unter /usr/share/doc/quagga/examples.

zebra.conf

hostname deadend-router

interface br0
  link-detect
interface ath1
   link-detect

in der zerba.conf werden die zu nutzenden interfaces angegeben.

ospf.conf

interface br0
  ip ospf cost 10
  ip ospf dead-interval 120
  ip ospf hello-interval 30
  ip ospf retransmit-interval 5
  ip ospf network broadcast
interface eth0
  ip ospf cost 10
  ip ospf dead-interval 120
  ip ospf hello-interval 30
  ip ospf retransmit-interval 5
  ip ospf network broadcast

router ospf
  ospf router-id 10.3.0.10
  network 10.3.0.0/16 area 0
  network 10.4.0.0/16 area 0
    redistribute kernel
    redistribute connected

In der ospf.conf wird diesen Interfaces erst Eigenschaften zugewiesen und anschließend das Protokoll zugeschaltet. Wichtig ist die Syntax. Das Einrücken dient nur zur Optik und hat kein Einfluss. Die Reihenfolge der Befehle hingegen hat Einfluss. Gewisse Befehle „öffnen“ eine SubConfig-Ebene. Ein „ip ospf cost“ ist nur gültig, wenn vorher eine interface-Direktive stand. Was bei den „interface“-Direktiven noch übersichtlich erscheint, kann bei den area-direktiven unübersichtlich werden, da diese ineinander geschachtelt sein können. Angenehm sind hingegen die redistribute -Direktiven. So muss man nur die Interfaces auflisten, auf den auch wirklich ein weiterer Router lauscht.