Ist "sysfs" eine Kernel ABI?

Mit dem Wechsel eines älteren Systems auf einen neuen Kernel sollte sich ja nichts tun: Alle alten Programme sollten einfach weiter laufen. In einer berüchtigten Diskussion fordert die Phalanx der Kernelentwickler unmißverständlich, alles menschenmögliche zu tun, um die ABI des Kerneln kompatibel zu halten.

Nach dem Reboot schien alles zu funktionieren. Alles, nur IPv6 nicht. Genaugenommen ging SLAAC auf dem Manangementinterface nicht. Das Netz tauchte in der Routingtabelle auf, aber das Interface bekam keine Adresse.

Erst ein Blick auf die Konsole (kernlog) zeigte eine Unmenge von "Duplicate IP" Meldungen. Hat da ein anderes Gerät die gleiche IP? Evtl sogar die gleiche MAC? Mir selbst sind 1992 mal ein Satz Ethernet-Karten mit identischen MACs ins die Hände gefallen, ein Fabrikationsfehler. Ist das etwa wieder vorgekommen?

Am Switch zeigten zwei Port tatsächlich abwechselnd diese MAC. Beide Ports gehören zu einem Active-Backup-Bundle eines Bonding-Interfaces dieses Servers. Ist etwa das Bonding kaputt? Kurze Suche ergab den Bug 503082, einen Nicht-Bug: Won't fix, work's as designed. WTF?

Der Bug war hier ja gar nicht zutreffend, schließlich steht mein Bonding-Interface auf active-backup, nicht auf balance-xor. Oder vielleicht doch? ifconfig auf beiden Interfaces zeigt, daß beide Slaves des Bondings gleichgroße TX-Counter haben. Eine weitere Nachprüfung zeigt, daß /sys/class/net/bond0/bonding/mode tatsächlich auf balance-xor steht. WTF?

Im Initscript wird der Mode korrekt gesetzt. Das System ist frisch gebootet. Wie kann das sein? Der Versuch den Modus umzustellen scheitetet

# echo 1 > /sys/class/net/bond0/bonding/mode
Error: unable to update mode of bond0 because interface is up. 

Dann eben ausgeschaltet:

# (
 ip link set bond0 down;
 echo 1 > /sys/class/net/bond0/bonding/mode;
 ip link set bond0 up )
Error: unable to update mode of bond0 because it has slaves.

Das ist neu. Das ging vorher. Im Initscript steht eindeutig:

ip link set eth2 name eth down
ip link set eth3 name eth_bak down
echo +eth > /sys/class/net/bond0/bonding/slaves
echo +eth_bak > /sys/class/net/bond0/bonding/slaves
echo 1 > /sys/class/net/bond0/bonding/mode
# ... mehr Einstellungen
ip link set bond0 up

Und beim testweisen Reboot erscheint die Fehlermeldung tatsächlich direkt beim Booten.

Ich habe also die Festlegung des Modus vor die Einbindung der Slaves gelegt, neu gebootet und alles tat prima.

Ursachenforschung

Das Problem ist damit aus der Welt, aber nicht gelöst. Die Frage lautet: Warum konnte das überhaupt geschehen?

Die erste Frage muß also sein, wer, wann und warum diesen Änderung vorgenommen hat. Und das geschah im November 2011. Dort wird auch diskutiert, daß damit Änderungen an verbreiteter Software erforderlich werden, sonst fällt die auf die Nase. Wie ich.

Dort wird auch diskutiert, warum diese Änderung sinnvoll ist. Beim Hinzufügen eines Slaves zum Bundle werden viele modusabhängige Aktivitäten vorgenommen. Diese müßten rückabgewickelt und im neuen Modus neu vorgenommen werden. Ist diese Komplexität es an dieser Stelle wert?

Was wäre eigentlich zu tun? Der Code steht praktisch oben drüber:

/* linux/drivers/net/bonding/bond_sysfs.c */
switch (command[0]) {
 case '+':
   pr_info("%s: Adding slave %s.\n", bond->dev->name, dev->name);
   res = bond_enslave(bond->dev, dev);
   break;
 
 case '-':
   pr_info("%s: Removing slave %s.\n", bond->dev->name, dev->name)$
   res = bond_release(bond->dev, dev);
   break;

Es wäre also ein Leichtes, die bestehenden Interfaces rauszuwerfen, den Modus umzustellen und die Interfaces wieder reinzunehmen. Gut, man muß die Fehlerfälle durchgehen: Was ist, wenn sich ein Interface nicht im neuen Modus einbringen läßt? Was ist wenn alle Interfaces im neuen Modus nicht laufen? Eine Variante wäre eine Warnung und ein Rollback. Eine andere wäre, die Fehlermeldungen auszugeben und das Interface im Zweifel unbenutzbar (weil ohne Slaves) zurückzulassen.

Mit Linus Anspruch, man müsse die Kompatibilität halten, müßte man diese Anstrengungen eben unternehmen. Das das nicht gemacht wird, scheint sysfs keine ABI zu sein.

Ursachenforschung Teil 2

Die eigentliche Ursache liegt aber tiefer. Per Voreinstellung wird der Treiber mit balance-xor initialisiert. Dieser Modus erfordert aber spezielle Vorbereitungen des Switches auf der anderen Seite des Bundels. Mit einfach "anstecken und geht schon" hat das nichts zu tun. Im Gegenteil: Da der Switch nichts von der besonderen Konfiguration weiß, schickt er die Frames eines Interfaces auch zum anderen. Fertig ist der IPv6 DAD.

Das es bei IPv4 klappt, ist eher Zufall. Multicast und Broadcast kommen gleichermaßen durcheinander. Möglicherweise ist dieser Default auch der Grund für die Probleme mit den Streamern einer IPTV Plattform: Diese ertrinken in ihren eigenen Streams.

In einem anderen Ticket wird zuerst versucht, auch unter diesen Umständen DAD korrekt auszuführen. Dies muß aber konzeptionell scheitern, weil man nicht zwischen "das bin ich doch selbst" und "da benutzt jemand anderes meine MAC und meine IP" unterscheiden kann. Im Zweifel ist vom Schlimmsten auszugehen. Dies tut DAD konsequent. Konsequenterweise ist der DAD Fehler im balance-Mode ein "Won't fix", weil die Konfiguration fehlerhaft ist.

Es wäre also ein Doppelpatch angebracht: Zum einen sind die fehlerhaften Defaults auf einen harmloseren Fall umzustellen und zum anderen ist der Aufwand zum Moduswechsel notwendig.

Post a comment

Related content