Wir haben seit einiger Zeit einen Unold 38915 Onyx Duplex Toaster. Der ist nun kaputt, d.h. er rastet nicht mehr ein, wenn man etwas toasten will. Leider sind im Netz keine Reparaturanleitungen vorhanden. Deswegen schreibe ich mal auf, wie man an die Innereien kommt und sich ein Wegschmeißen erspart.

Zunächst benötigt man Werkzeug: Zwei Messer, einen Vierkant- und einen Dreikant-Schraubendreher.

Werkzeug

Als erstes werden die seitlichen Griffe entfernt. Diese sind nur aufgesteckt (wenn auch stramm). Mit zwei Messern kann man gleichmäßig Druck ausüben ohne die Bleche zu verbiegen.

Griffe abhebeln
Griffe ab

Der Drehknopf hat eine Einkerbung, die man später wieder treffen muss, aber das ergibt sich von selbst.

Zunächst muss aber die Umhüllung fallen. Dazu dreht man den Toaster um und findet auf der Unterseite mehrere Schrauben. Die Vierkantschrauben sind mittig leicht zu finden. Die Dreikantschrauben verstecken sich unter den Gummifüßen, die zum Glück nicht verklebt sind.

Vierkant
Gummifuss
Dreikant

Die Vierkantschrauben halten ein paar straffe Metallohren, die man heraus ziehen muss und schon kann man das Gehäuse anheben. Aber vorsichtig und auf der Seite gegenüber der Griffe.

Anheben

Hat man die Diagonale erreicht, wird es sehr knapp. Mit Geschick und guten Willen bekommt man jedoch die Hülle über die Kante.

Kante

Nun ist der Toaster offen. Beim Aufklappen lässt man besser alle Drähte dran, denn dort ist nichts kaputt.

Offen
Innen

Die eigentliche Ursache, warum der Toaster nicht mehr einrastet, ist simpel. Es ist Dreck zwischen dem Magneten und dem Eisen. Das merkt man, wenn man mal runter drückt. Das Eisen muss dann flach auf dem Magneten aufliegen.

Magnet1
Magnet2

Wenn man mal das Gerät offen hat, kann man sich gleich noch ansehen, wie die Mechanik zum Absenken und Festhalten funktioniert. Es ist halt ein billiges Gerät, bei dem sich leicht was verbiegt. Sollte das der Fall sein, so korrigiert man das gleich mit.

Seilzug1
Seilzug2

Nach Säubern und Geradebiegen aller Komponenten kann das Gehäuse wieder drauf. Dabei gibt es noch einen Moment, der Aufmerksamkeit erfordert: Das Gehäuse muss oben in zwei Schlitze einrasten.

Einstecken

Abschließend alle Schrauben fest drehen und Gummifüße und Griffe wieder einstecken.

Fertig.

Typischerweise haben Server einen RAID-Controller, der einen Festplattenausfall vor dem Betriebssystem verstecken kann. Wenn also eine Platte den Geist aufgibt, kann man sie wechseln, ohne auf irgendeine Besonderheit des installierten Systems Rücksicht nehmen zu müssen. Das erleichtert die Arbeit im Rechenzentrum erheblich: Platte tot → Austauschen → Fertig.

Redundante Redundanz

Auf einen Satz Server ist Proxmox zum Spielen drauf gekommen. Der Installer richtet auf einer ausgewählten Platte das System ein. In dem Fall also auf dem Hardware-RAID. Soweit so gut.

Für das Storage möchte ich auf Ceph zurück greifen, auf Neudeutsch hyperkonvergent arbeiten. Deswegen habe ich den größten Teil der Platte frei gelassen um den Rest als OSD einbinden zu können.

Ceph verwaltet eine eigene Redundanz über die OSD-Datenträger. Es berücksichtigt dabei großräumigere Strukturen als nur Platten an einem Contoller. Dies führt zu massiver Platzverschwendung: Daten liegen nicht mindestens doppelt, sondern vier- bis sechsfach vor.

Wird das Hardware-RAID aufgebrochen, kann Ceph die einzelen Platte direkt verwalten und damit effizienter umgehen. Aber was wird  aus dem Basissystem?

Eine Neuinstallation später steht fest, dass der Proxmox-Installer das System ausschließlich auf eine der beiden Platte installiert hat. Konzeptionell ist das nachvollziehbar, da so mehr Platz für die OSDs bleibt. Geht die Systemplatte kaputt, installiert man den Knoten halt komplett neu und der Cluster erledigt den Rest.

Ich scheue aber den Aufwand, da die Netzwerkinstallation des Basissystem hier doch stärker vom Proxmox-Standard abweicht, als erwartet. Aber dazu ein andermal.

Aus eins mach zwei

Zuerst ein Blick auf die Situation direkt nach der Installation:

root@server21:~# fdisk /dev/sda

Welcome to fdisk (util-linux 2.29.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk /dev/sda: 279.4 GiB, 300000000000 bytes, 585937500 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3B2CD483-DE39-45BA-BF6A-C35E2AD8F783

Device       Start      End  Sectors  Size Type
/dev/sda1       34     2047     2014 1007K BIOS boot
/dev/sda2     2048  1050623  1048576  512M EFI System
/dev/sda3  1050624 41943040 40892417 19.5G Linux LVM

Die Platte sdb ist leer.

Im ersten Schritt kopiere ich den Anfang der Platte incl. alle Boot-Informationen:

root@server21:~# dd if=/dev/sda of=/dev/sdb bs=512 count=1050623

Ja, die GPT ist auf der zweiten Platte kaputt, da die Kopie am Ende der Platte fehlt. Aber das behebt fdisk beim nächsten Aufruf.

So kann nun die zweite Platte so eingerichtet werden, wie später es sein soll:

root@server21:~# fdisk /dev/sdb
[...]
Command (m for help): t
Partition number (1-3, default 3): 
Hex code (type L to list all codes): 29

Changed type of partition 'Linux LVM' to 'Linux RAID'.

Command (m for help): p
Disk /dev/sdb: 279.4 GiB, 300000000000 bytes, 585937500 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3B2CD483-DE39-45BA-BF6A-C35E2AD8F783

Device       Start      End  Sectors  Size Type
/dev/sdb1       34     2047     2014 1007K BIOS boot
/dev/sdb2     2048  1050623  1048576  512M EFI System
/dev/sdb3  1050624 41943040 40892417 19.5G Linux RAID

Und wenn wir schon mal hier sind, dann auch gleich das OSD vorbereiten

Command (m for help): n
Partition number (4-128, default 4): 
First sector (41943041-585937466, default 41945088): 
Last sector, +sectors or +size{K,M,G,T,P} (41945088-585937466, default 585937466): 

Created a new partition 4 of type 'Linux filesystem' and of size 259.4 GiB.

Command (m for help): t
Partition number (1-4, default 4): 
Hex code (type L to list all codes): 76

Changed type of partition 'Linux filesystem' to 'Ceph OSD'.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Damit sehen die Platten so aus:

lvm-raid1

Die grünen Partitionen sind schon in Ordnung, die grünen Inhalte ebenfalls. Rot markierte Teile sind noch beheben, die Blauen noch unbenutzt.

Aus zwei mach eins

Zunächst muss das RAID als solches fertig werden. Es soll ein Spiegel werden, aber anfangs nur mit einer Partition.

root@server21:~# mdadm --create /dev/md0 -n 1 -f -l 1 /dev/sdb3 
mdadm: Note: this array has metadata at the start and
    may not be suitable as a boot device.  If you plan to
    store '/boot' on this device please ensure that
    your boot-loader understands md/v1.x metadata, or use
    --metadata=0.90

Sehr gute Frage! Ich habe den Boot-Kram in separaten Boot-Partitionen, was kann da schon schief gehen?

mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.
root@server21:~# cat /proc/mdstat 
Personalities : [raid1] 
md0 : active raid1 sdb3[0]
      20429824 blocks super 1.2 [1/1] [U]
      
unused devices: <none>

Schaut gut aus. Jetzt nur noch die Daten des LVM rein kopieren.

Die Idee ist dabei, das LVM aufzublasen und dann die alte Partition wieder raus zu nehmen.

root@server21:~# pvcreate /dev/md0
  Physical volume "/dev/md0" successfully created.
root@server21:~# pvdisplay 
  --- Physical volume ---
  PV Name               /dev/sda3
  VG Name               pve
  PV Size               19.50 GiB / not usable 3.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              4991
  Free PE               3775
  Allocated PE          1216
  PV UUID               ijshQ9-3z2d-oVxd-WJB2-8LUv-HEfL-lTZzEi
   
  "/dev/md0" is a new physical volume of "19.48 GiB"
  --- NEW Physical volume ---
  PV Name               /dev/md0
  VG Name               
  PV Size               19.48 GiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               G8kgdF-Gcec-ddbO-92ys-9rsf-dkpo-Za9C4a

root@server21:~# pvdisplay -C
  PV         VG  Fmt  Attr PSize  PFree 
  /dev/md0       lvm2 ---  19.48g 19.48g
  /dev/sda3  pve lvm2 a--  19.50g 14.75g

Es gibt nun zwei LVM-Datenträger, von denen einer das Volume enthält. Nun zum Umzug.

root@server21:~# vgextend pve /dev/md0
  Volume group "pve" successfully extended
root@server21:~# pvdisplay -C
  PV         VG  Fmt  Attr PSize  PFree 
  /dev/md0   pve lvm2 a--  19.48g 19.48g
  /dev/sda3  pve lvm2 a--  19.50g 14.75g
root@server21:~# vgdisplay -C
  VG  #PV #LV #SN Attr   VSize  VFree 
  pve   2   1   0 wz--n- 38.98g 34.23g
root@server21:~# vgreduce pve /dev/sda3 
  Physical volume "/dev/sda3" still in use

Vergrößern ging, aber die alte Partition lässt sich nicht entfernen!

Warum? Weil noch Daten drauf sind. Schließlich wurde ja nur neuer Platz hinzugefügt. Nur der ist unbenutzt.

root@server21:~# pvmove /dev/sda3
  /dev/sda3: Moved: 0.00%
  /dev/sda3: Moved: 18.17%
  /dev/sda3: Moved: 36.43%
  /dev/sda3: Moved: 54.52%
  /dev/sda3: Moved: 72.86%
  /dev/sda3: Moved: 91.04%
  /dev/sda3: Moved: 100.00%
root@server21:~# pvdisplay 
  --- Physical volume ---
  PV Name               /dev/sda3
  VG Name               pve
  PV Size               19.50 GiB / not usable 3.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              4991
  Free PE               4991
  Allocated PE          0
  PV UUID               ijshQ9-3z2d-oVxd-WJB2-8LUv-HEfL-lTZzEi
   
  --- Physical volume ---
  PV Name               /dev/md0
  VG Name               pve
  PV Size               19.48 GiB / not usable 3.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              4987
  Free PE               3771
  Allocated PE          1216
  PV UUID               G8kgdF-Gcec-ddbO-92ys-9rsf-dkpo-Za9C4a

Nun ist nichts mehr auf der alten Partition in Benutzung. "Allocated PE" ist 0.

Also müsste sich die Partition nun entfernen lassen.

root@server21:~# vgreduce pve /dev/sda3 
  Removed "/dev/sda3" from volume group "pve"
root@server21:~# pvdisplay -C
  PV         VG  Fmt  Attr PSize  PFree 
  /dev/md0   pve lvm2 a--  19.48g 14.73g
  /dev/sda3      lvm2 ---  19.50g 19.50g

Hurra! Nun noch die Partition dem LVM entziehen.

root@server21:~# pvremove /dev/sda3
  Labels on physical volume "/dev/sda3" successfully wiped.
root@server21:~# pvdisplay -C
  PV         VG  Fmt  Attr PSize  PFree 
  /dev/md0   pve lvm2 a--  19.48g 14.73g

Und die Partition umwidmen.

root@server21:~# fdisk /dev/sda

Welcome to fdisk (util-linux 2.29.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk /dev/sda: 279.4 GiB, 300000000000 bytes, 585937500 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3B2CD483-DE39-45BA-BF6A-C35E2AD8F783

Device       Start      End  Sectors  Size Type
/dev/sda1       34     2047     2014 1007K BIOS boot
/dev/sda2     2048  1050623  1048576  512M EFI System
/dev/sda3  1050624 41943040 40892417 19.5G Linux LVM
Command (m for help): t
Partition number (1-3, default 3): 
Hex code (type L to list all codes): 29

Changed type of partition 'Linux LVM' to 'Linux RAID'.

Command (m for help): p
Disk /dev/sda: 279.4 GiB, 300000000000 bytes, 585937500 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3B2CD483-DE39-45BA-BF6A-C35E2AD8F783

Device       Start      End  Sectors  Size Type
/dev/sda1       34     2047     2014 1007K BIOS boot
/dev/sda2     2048  1050623  1048576  512M EFI System
/dev/sda3  1050624 41943040 40892417 19.5G Linux RAID

Command (m for help): n
Partition number (4-128, default 4): 
First sector (41943041-585937466, default 41945088): 
Last sector, +sectors or +size{K,M,G,T,P} (41945088-585937466, default 585937466): 

Created a new partition 4 of type 'Linux filesystem' and of size 259.4 GiB.

Command (m for help): t
Partition number (1-4, default 4): 
Hex code (type L to list all codes): 76

Changed type of partition 'Linux filesystem' to 'Ceph OSD'.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Bei der Gelegenheit auch gleich noch die OSD Partition vorbereitet. Sehr schön.

Jetzt kann das RAID breit gezogen werden.

root@server21:~# mdadm -a /dev/md0 /dev/sda3
mdadm: added /dev/sda3
root@server21:~# cat /proc/mdstat 
Personalities : [raid1] 
md0 : active raid1 sda3[1](S) sdb3[0]
      20429824 blocks super 1.2 [1/1] [U]

Nein.Das ist kein "hot spare", das ist Bestandteil des RAIDs selbst. Ich hätte wohl gleich mit zwei Partitionen, davon eine als "none", anfangen sollen.

root@server21:~# mdadm -r /dev/md0 /dev/sda3
mdadm: hot removed /dev/sda3 from /dev/md0
root@server21:~# mdadm --grow /dev/md0 -n 2 -a /dev/sda3
mdadm: added /dev/sda3
raid_disks for /dev/md0 set to 2
root@server21:~# cat /proc/mdstat 
Personalities : [raid1] 
md0 : active raid1 sda3[1] sdb3[0]
      20429824 blocks super 1.2 [2/1] [U_]
      [>....................]  recovery =  3.2% (669248/20429824) finish=1.4min speed=223082K/sec 

Hurra! Jetzt schaut es so aus.

lvm-raid2

Reboot

Da nun alles im laufenden Betrieb umgezogen ist, bleibt nur noch der finale Reboot.

Klappt aber nicht, weil der Grub das LVM-Volume nicht mehr findet. Sollte /boot nicht separat liegen?! Mal beim Nachbar nachschauen:

root@server22:~# mount | grep boot
/dev/sda2 on /boot/efi type vfat ...

Ohje. Also nochmal von vorn und diesmal mit "--metadata=0.9". Siehe an, es geht.

Aber was ist eigentlich passiert? Zur Erinnerung nochmal die Warnung.

mdadm: Note: this array has metadata at the start and
    may not be suitable as a boot device.  If you plan to
    store '/boot' on this device please ensure that
    your boot-loader understands md/v1.x metadata, or use
    --metadata=0.90

Die Metadaten des RAID können also am Anfang (neu) oder am Ende (alt) der Partition stehen. Wenn sie am Ende stehen, muss niemand irgendwas von dem RAID1 (Mirror) verstehen, um auf den Inhalt zugreifen zu können. Die Partition sieht halt aus, als gäbe es gar kein RAID.

Stehen die Daten am Anfang der Partition, muss die Software damit umgehen können. Im Prinzip ist das auch sehr einfach, weil man nur über die RAID-Kennung hinweg springen muss. Leider kann das Grub nicht und ist damit ein steter Quell von Problemen.

Wir fahren nach Berlin! Vom Leiden einer Reisebuchung am ersten April.

Es ist BCIX Stammtisch und ich darf dabei sein. Hurra!

Anreise

Dazu muss eine Reise gebucht werden und schon kommt das erste Problem auf: Ich kann auf dem Bahn-Portal nicht bezahlen. Die Zahlung per Kreditkarte wird abgelehnt.

Anruf beim Support: "Das ist zu Ihrer Sicherheit! Sie haben schon so oft mit Kreditkarte Bahnfahrkarten gekauft, das könnte auch ein Betrüger sein, also ist das nun gesperrt. Gegen Sie zum Schalter!"

Genau genommen funktioniert mit der Commzerbank das 3D Secure Verfahren nie, weswegen jeder, der ein Konto dort hat es ausschaltet. Nun besteht die Bahn spontan auf der Einhaltung des Verfahren, auch wenn die Bank es direkt als unnötig ablehnt. Die Bahn kann mit der Ablehnung aber nicht umgehen und die Buchung scheitert.

Was auch nicht geht, ist ein Umstellung auf Lastschrift. Nicht, weil der Prozess per Post und Papier abläuft, sondern weil er aus Sicherheitsgründen seitens der Bahn abgebrochen wird. Es gab ja eben erst eine fehlgeschlagene Kreditkartenbuchung.

Auf eine öffentliche Beschwerde hin, antwortet die Bahn:

Aktuell sind verstärkt betrügerische Aktivitäten basierend auf sogenannten Phishing-E-Mails zu verzeichnen. Als eine vorsorgliche Maßnahme zum Schutz unserer Kunden können deshalb Sparpreis-Tickets auf bahn.de und im DB Navigator bis auf Weiteres nur

  • per "Sofort." (SOFORT Überweisung) und
  • Kreditkarte unter Abfrage des 3D-Secure-Passwortes

bezahlt werden. Dafür bitten wir um Verständnis.

https://www.bahn.de/p/view/home/info/sonderkommunikation-phishing.shtml

Der Betrüger darf also den teuren Flexpreis gern zu meinen Lasten in Anspruch nehmen, nicht aber die Sparpreise. Super, Deutsche Bahn!

Und nein, ich werde meine Online-Banking-Daten nicht irgendeinem fremden Unternehmen in die Hände drücken. Das fällt aus.

Übernachtung

Und nun zu Teil zwei: Ich brauch ein Hotel, weil nach der Veranstaltung nichts mehr nach Hause fährt.

Bei Booking alles soweit kein Problem, nur gibt's keinen Ausdruck der Buchung mehr direkt auf die Hand. Das neue Verfahren generiert das PDF offenbar aus einem C64-Font heraus:

2019-04-01-150217_1278x1022_scrot

Echt retro.

Eine unglückliche Platzierung eines Datenschutzlinks wird unfreiwillig komisch, wenn dann Fehler auftreten.

Bildschirmfoto vom 2019-02-26 10.18.10

Genau. Kein Kamerabild, weil ... ganz unten "Powered by Datenschutz" steht.

Eigentlich ist es ganz anders.

Im Rahmen der DSGVO wurde der Webseite ein Footer mit einem Datenschutzlink verpasst. Allerdings beißt sich das mit dem bisherigen Design, bei dem die Sponsoren als "Powered by" aufgeführt sind.

Als dann die Kamera kein Bild liefern konnte, entstand dieser Schnappschuß-.

A customer complained about network problems. An SMB/CIFS mount would always break down between two of his servers. Not that there were any noticeable problems, but there are still some error messages in the log.

Setup

The customer has a certain number of servers in his Layer2 segment. One of them is a Windows file server for a group of Windows computers. Another is the Linux monitoring system, which regularly tries to access the share.

The whole thing has a longer history, which led half a year ago to the recommendation to abandon SMB1. This part is not relevant, it is what followed the recommendation.
Since the transition, the monitoring Linux has had strange entries in the kernel log:

Feb 12 19:07:02 kernel: CIFS VFS: Server a.b.c.d has not responded in 120 seconds. Reconnecting...

Where do these 120 seconds come from? The man page does help:

echo_interval=n

sets the interval at which echo requests are sent to the server on an idling
connection. This setting also affects the time required for a connection to
an unresponsive server to timeout. Here n is the echo interval in seconds.
The reconnection happens at twice the value of the echo_interval set for
an unresponsive server. If this option is not given then the default value of
60 seconds is used.

That explains the 120 seconds: Every minute an SMB echo is sent and if no echo is answered twice, the connection is believed to be dead. Therefore, the customer (understandably) thinks that there would be packet loss in the network.

To prove this assumption wrong takes weeks. For this purpose, the data traffic is recorded on both sides and put next to each other packet by packet.

Unfortunately, this still doesn't solve the real problem.

Analysis

Again and again such a recording is examined, in order to discover any unusual phenomenon.

smb-tcp-flow

It's awesome to see each minute the keep-alive request-response game is happening. Then data is sent.

The communication comes to a sudden pause and the time-out stated in the log occurs. Between 19:05:01.99... and 19:07:02.25... there are a little more than 120 seconds. So far that seems to fit.

The transmission error (the one with the TCP keep-alive) is remarkable, because it hits the server directly before the connection is terminated. This must be investigated!

Why are the lines black? Because the keep-alive sends exactly one byte over again, which has been acked for a long time. It is a very unusual conversation. Wireshark colours such sequence errors in black.

  • At 19:05:01.949511 128 bytes are received.
  • At 19:05:01.997203 the reception of these 128 bytes is confirmed.
  • At 19:07:01.999481 the final of the 128 bytes is transmitted again (together with the keep-alive flag).

If the acknowledgement of the data reception (ACK) had not arrived, the entire 128 bytes would be sent again. But they are not.

Did a firewall gamble on the sequence numbers underway? But there is no firewall in between, both servers are in the same LAN and see each other directly. But the other side verifies that the acknowledgement has arrived completely.

So why should the kernel resend a single byte? It turns out that the Windows implementation of the TCP keepalive sends exactly one byte again, while the Linux implementation sends the keepalive without payload. This is apparently an adjustment of Windows to broken middleware, which drops TCP packets without payload.

So the part is fine. But what is it then?

Maybe there are some delays somewhere? So let's take a look at the round-trip times. Maybe there are outliers.

smb-tcp-rtt

There are no particular irregularities with the remote location. Everything looks nice.

smb-tcp-rtt2

Even the local processing is completely inconspicuous: Everything that the kernel can process directly is done in almost no time. If the application software is involved, it takes longer. One can see very clearly how regular the measurements are.

Nothing is striking here either. But what is it then?

A closer look reveals that an echo request should have been sent at 19:06:00. But that is missing!

Kernel Archaeology

The function cifs_echo_request is responsible for sending the echo requests in the Linux kernel. There it says:

static void
cifs_echo_request(struct work_struct *work)
{
 int rc;
 struct TCP_Server_Info *server = container_of(work,
     struct TCP_Server_Info, echo.work);
 unsigned long echo_interval;

 /*
  * If we need to renegotiate, set echo interval to zero to
  * immediately call echo service where we can renegotiate.
  */
 if (server->tcpStatus == CifsNeedNegotiate)
  echo_interval = 0;
 else
  echo_interval = server->echo_interval;

 /*
  * We cannot send an echo if it is disabled.
  * Also, no need to ping if we got a response recently.
  */

 if (server->tcpStatus == CifsNeedReconnect ||
     server->tcpStatus == CifsExiting ||
     server->tcpStatus == CifsNew ||
     (server->ops->can_echo && !server->ops->can_echo(server)) ||
     time_before(jiffies, server->lstrp + echo_interval - HZ))
  goto requeue_echo;

 rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
 if (rc)
  cifs_dbg(FYI, "Unable to send echo request to server: %s\n",
    server->hostname);

requeue_echo:
 queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval);
}

The code is interesting in several ways:

  • On the one hand, an echo is sent only if there exists a real need to do so.
  • On the other hand, this is a daisy chain scheduling: Only after work has been done the next action is planned.

As far as the needs are concerned, no echoes are sent out as long as the last response was received earlier than one echo interval.

But what is a response? In the code, the server→lstrp is always set to the current time whenever a packet is received. Regardless wether it is an echo response or normal data.

Subtracting HZ (one second) is a countermeasure preventing the echo response to your own request from being interpreted as interesting traffic. So this hard-coded value is calculated assuming that the answer from the remote station comes always more quickly than in a second.

If such an SMB connection runs over a longer distance or against a slower server, every second echo request will be suppressed if no further traffic occurs. This directly leads to the fact that SMB only works in the LAN.

Due to the protocol architecture, all requests are processed sequentially. If an echo request is sent while another request is running on the server, the echo request will not be processed until the previous request has been completed. Asynchronous processing was abandoned with the transition from SMB1 to SMB2. Now the server should tell the client that a more complex request is still being processed.

In this case an answer was received at 19:05:01.91... from the server. The echo packet should have been sent around 19:06:00. That's a very precise mistake!

The second problem is the scheduling. Only when all the work has been done (sending the echo packet) the next echo is scheduled to be sent 60 seconds later. The entire processing time is missing from the planning. This means that the echo packets are not sent exactly after 60 seconds, but always a bit later.

The recording shows this very clearly: 19:01:55.05, 19:02:56.49, 19:03:57.94, 19:04:59.37, 19:06:00.90, 19:07:02.27. The intervals are about 61.5 seconds. So 1.5 seconds more than planned. In the last step the interval is shorter, because the echo packet was not sent.

Racecondition

But what really happens is explained quickly: Suppressing the planned echo request is faulty.

In detail:

smb-tcp-timing
  • Daisy chaining scheduling creates a gap.
  • If traffic comes unfortunate shortly after the last echo, the planned echo is suppressed.
  • Due to the gap, the next echo transmission is delayed until after the timeout, which is set hard to twice the echo interval.

It is particularly charming to realize that the final echo request is first sent and then the time-out strikes, because the first action when receiving the echo response is to check for a time-out and terminate it. Ironically, the successful echo triggered the abort.

Now the question arises since when the problem occurred and who is responsible for it:

  • The patch c740 will send permanently echo requests every 60 seconds if no other traffic occurred. (Jan 11, 2011)
  • The patch fda3 all these echoes are used to trigger a timeout at five times the interval (configurable) without traffic. (Jan 20, 2011)
  • The patch 6dae switches from the configurable 60s x variable(5) to variable(60s) x two. (Feb 21, 2012)

The gap and suppression was introduced on 11 January 2011. However, this has no effect, as the time-out starts at five times the interval.

With the changeover on 21 February 2012, the gap now takes effect, as the time-out was set hard to twice the interval.

Solutions

There are three options.

First, eliminate the gap by scheduling at fixed times (always add 60 seconds to the last schedule time). By the way, it is not enough to move the rescheduling to the beginning of the routine. This only shortens the gap, but it will not disappear.

Another possibility is to send the echo requests in any case regardless of other traffic. In other words, if traffic is already running, the additional request will not bother any more. There is a potential risk that a server will choke on an echo between other requests.

Furthermore, avoiding the entire problem by waiting at least three times the interval length seems plausible.

If you want a quick fix, you should choose the third approach: Change a 2 to a 3 in the code:

static bool
server_unresponsive(struct TCP_Server_Info *server)
{
 /*
  * We need to wait 2 echo intervals to make sure we handle such
  * situations right:
  * 1s  client sends a normal SMB request
  * 2s  client gets a response
  * 30s echo workqueue job pops, and decides we got a response recently
  *     and don't need to send another
  * ...
  * 65s kernel_recvmsg times out, and we see that we haven't gotten
  *     a response in >60s.
  */
 if ((server->tcpStatus == CifsGood ||
     server->tcpStatus == CifsNeedNegotiate) &&
     time_after(jiffies, server->lstrp + 2 * server->echo_interval)) {
  cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
    server->hostname, (2 * server->echo_interval) / HZ);
  cifs_reconnect(server);
  wake_up(&server->response_q);
  return true;
 }

 return false;
}

All that remains is the question of the TCP keepalive. Windows will wait exactly 120s until it sends a keepalive on a TCP session. Note that the Windows server sends the TCP keepalive first, because it transmitted the last packet before it arrived at Linux.

Acknowledgement

The entire analysis was done by my colleague Jens, who just asked me to write things together. This is what I did here.

The only thing left to do now is to send a bug report to the right place.

Microsoft stellt einen eigenen BGP Router für Windows bereit. Wir benötigen an einer Stelle, wo bisher nur ein paar Hyper-V fähige Kisten stehen einen unabhängigen Internetzugang. Was liegt also näher als alles aus einer Hand zu bauen?

Installation

Auf eine Windows VM kommt aus der RAS Rolle das Feature LAN Routing zum Einsatz. Damit kann die VM zwischen Interfaces routen.

Als nächstes wird die BGP Rolle installiert. Auch das ist problemlos, die benötigten Abhängigkeiten sind gleich dabei.

Alle folgenden Schritte benötigen die Powershell, was dem geneigten Admin sehr entgegen kommt. Zuerst also einen neuen BGP Router definieren.

PS> Add-BgpRouter -BgpIdentifier <IPAddress> -LocalASN <UInt32>

Man gibt also seine lokales AS Nummer an (zum experimentieren gibt private Nummern) und eine eindeutige IP Adresse, unter der der Router arbeiten wird. Am besten die IP eines Interfaces. Erfreulich ist die Verwendung eines UInt32, der auf die Unterstützung von 4-Byte ASNs hinweist.

Als nächstes kommt dann die Einrichtung eines BGP Peers, also eines Nachbar mit dem diese Maschine reden soll.

PS> Add-BgpPeer [-Name] <String> -LocalIPAddress <IPAddress> -PeerASN <UInt32> -PeerIPAddress <IPAddress>

Der Peer bekommt einen sprechenden Namen unter dem er später erscheinen soll. Des weiteren wird die AS-Nummer des Peers benötigt. Wenn diese die gleiche ist, wie die eigene, handelt es ich um ein i(nternal)BGP, sonst um ein e(xternal)BGP Peer.

Die Kommunikation erfolgt zwischen zwei IP Adressen, die auf beiden Seiten übereinstimmen müssen. I.d.R. werden da IP Adressen genommen, die sich im gleichen Netz befinden und direkt miteinander reden können. Die meisten eBGP Peers erwarten das. bei iBGP ist eine durchaus längere Routingstrecke zwischen den Peers nichts ungewöhnliches.

Cisco als Gegenstelle

Zum Test lasse ich den Server gegen einen normalen Cisco Router arbeiten.

router bgp 15725
 neighbor <WindowsIP> remote-as 65432
 address-family ipv4
  neighbor <WindowsIP> activate
  neighbor <WindowsIP> soft-reconfiguration inbound
  neighbor <WindowsIP> prefix-list from_windows in
  neighbor <WindowsIP> prefix-list to_windows out
 exit-address-family
!
ip prefix-list from_windows seq 5 deny 0.0.0.0/0 le 32
ip prefix-list to_windows seq 1 permit 185.98.236.0/22
ip prefix-list to_windows seq 5 deny 0.0.0.0/0 le 32

Für den Anfang gebe ich nur eine Route raus und nehme nichts an. Sicher ist sicher.

Die BGP Session kommt hoch und das Windows lernt eine Route!

Mit Get-BgpPeer und Get-BgpRouteInformation kann man sich die Ergebnisse ansehen. Die Route taucht sogar in der normalen Routing Tabelle auf.

Auffällig ist aber, dass die Cisco etwas seltsames anzeigt:

  Neighbor capabilities:
    Route refresh: advertised and received(new)
    Four-octets ASN Capability: advertised
    Address family IPv4 Unicast: advertised and received
    Graceful Restart Capability: advertised
    Enhanced Refresh Capability: advertised

Irgendwie fehlt da die 4-Byte ASN Funktionalität. Gleich mal ausprobieren.

PS> Add-BgpPeer test4byte -LocalIPAddress <IPAddress> -PeerASN 199932 -PeerIPAddress <IPAddress>
windows bgp 4byte asn

Oops. Das ist ein KO-Kriterium. Eigentlich müsste ich hier sofort aufhören zu evaluieren.

Full Table

Aber probieren wir mal was anderes. Was tut die Kiste, wenn sie der vollen Internet-Routingtabelle ausgesetzt wird?

(config)#ip prefix-list to_windows seq 2 perm 0.0.0.0/0 le 24

Die CPUs gehen auf Anschlag und bleiben dort eine ganze Weile. Trotzdem bleibt das System benutzbar. Der RAM Bedarf steigt um zwei GByte, was ziemlich okay ist.

Anschließend sind alle Kerne mit ca 50% CPU belastet ohne dass irgendeine Aktivität von außen rein kommt. Seltsam.

Ein Blick in die BGP Routingtabelle mit Get-BgpRouteInformation zeigt, dass alle knapp 750.000 Routen angekommen sind. Allerdings braucht die Maschine unter CPU Volllast für die Ausgabe geschlagene drei Minuten.

Die Überraschung gibt es aber mit dem Blick in die aktive Routing Tabelle:

windows bgp routing missing

Dies ist mit unvollständig nur unzureichend umschrieben.

Real fehlen abertausende Routen wie die folgenden:

B     206.0.0.0/15 [20/0] via 94.135.173.249, 4d15h
B     206.2.0.0/16 [20/0] via 94.135.173.249, 4d15h
B     206.2.76.0/24 [20/0] via 94.135.173.249, 00:36:24
B     206.3.0.0/19 [20/0] via 5.102.160.98, 4w0d
B     206.3.32.0/19 [20/0] via 94.135.173.249, 4d15h
B     206.3.42.0/24 [20/0] via 5.102.160.98, 19:43:50
B     206.3.64.0/18 [20/0] via 94.135.173.249, 4d15h
B     206.3.128.0/17 [20/0] via 94.135.173.249, 4d15h
B     206.4.0.0/14 [20/0] via 94.135.173.249, 4d15h
B     206.5.12.0/22 [20/0] via 94.135.173.249, 4d15h
B     206.8.0.0/14 [20/0] via 94.135.173.249, 4d15h
B     206.8.2.0/24 [20/0] via 94.135.173.249, 4d15h
B     206.8.88.0/24 [20/0] via 5.102.160.98, 19:43:49
B     206.8.120.0/24 [20/0] via 94.135.173.249, 4d15h
B     206.8.121.0/24 [20/0] via 94.135.173.249, 4d15h
B     206.8.122.0/24 [20/0] via 94.135.173.249, 4d15h

Das heißt, dass die Maschine nun nicht in der Lage die Pakete korrekt ans Ziel zuzustellen!

Das ist ein KO-Kriterium. Eigentlich müsste ich hier sofort aufhören zu evaluieren.

Wegräumen

Also nehme ich das Announcement der Routen wieder weg.

(config)#no ip prefix-list to_windows seq 2 perm 0.0.0.0/0 le 24

Nach erfreulich schnellen 40 Sekunden sinkt die CPU Last rapide auf nahe 0. Allerdings sind noch immer tausende von Routen im Kernel aktiv.

Als ich zur Kontrolle mir die BGP Routingtabelle mit Get-BgpRouteInformation anzeigen lassen will, behauptet das System, dass die betreffenden Dienste nicht laufen würden.

windows bgp rras dead

Erst im Ereignislog zeigt sich das ganze Ausmaß der Katastrophe:

windows bgp crash

Es hat so ziemlich jeden laufenden Dienst abgeschossen. Nicht nur Routing, sondern auch die Nutzerverwaltung, die Hardware Treiber etc. pp.

Das ist ein KO-Kriterium. Eigentlich müsste ich hier sofort aufhören zu evaluieren.

Zum Glück starten alle Services von alleine neu und ich kann Screenshots für den Blog machen.

IPv6 teste ich nicht mehr.

There is a much talking about quantum communication in wide area networks, but what quantum mechanics really means for networkers stays unclear. But the world's networkers know macroscopic quantum phenomena very well.

1280px-Schroedingers_cat_film_copenhagen.svg

Von Christian Schirm - Eigenes Werk, CC0, https://commons.wikimedia.org/w/index.php?curid=68587012

One interpretation of quantum mechanics involves the entanglement of different states, which collapse to the currently measured state during measurement. In essence, this interpretation means that the system is in the determined state immediately after the measurement. It says nothing about how the system will evolve.

Networkers are familiar with the problem of purchasing cable connections:

  • The terminations of the connection are part of the contract and therefore fixed boundary conditions. The route the wire will take is unknown.
  • It is possible to specify a certain route or to get an explicit promise. However, the operator reserves the right to change the route in case of failures or other difficulties.
  • The exact route of a connection can only be determined if a (dredger) fault has occurred.

In such a way each purchased connection is a macroscopic quantum effect:

  • The digger measuring tool detects the location of a pipeline at the time of measurement.
  • With the impact of the excavator damage, the location of the pipeline is reliably determined.
  • When the damage is fixed, a new functional state is achieved, which may have been repaired on site or relocated.
  • The new cable route is therefore a new macroscopic quantum phenomenon.

Die deutsche Wirtschaft besteht hauptsächlich aus kleinen, spezialisieren Unternehmen. Die meisten von ihnen haben nichts mit IT am Hut, brauchen es aber trotzdem. Also holen sie sich einen Bekannten als Dienstleister bis irgendwann mal aufgeräumt werden muss.

Der Auftrag

Ein typisches 10-Personen-Unternehmen wendet sich an uns, weil ein Bekannter uns empfahl.

Die Firma gibt es schon lange, hat in diese Gegend hier expandiert und nun diesen Teil abgespalten. Dieser Teil braucht also neue, eigenständige IT. Der Auftrag besteht darin, herauszubekommen, welche Dienste die Ex-Abteilung überhaupt benötigt, wo die bisher betrieben wurden und wie man die separiert. Natürlich muss die Umstellung im laufenden Betrieb stattfinden.

So weit, so gut.

Dass zu den meisten Dienstleistungen – weil bisher intern – keine Verträge existieren, ist nachvollziehbar. Dass die Mitarbeiter nur ihre Arbeit machen, so wie man es ihnen gesagt hat, ist nachvollziehbar. Dass bei der Hauptfirma keiner weiß, welche Dienste existieren und welche Verträge bestehen, ist schwierig aber eben auch nicht zu ändern. Dass die bisherigen Dienstleister nicht zwingend Lust haben zu helfen, ist nachvollziehbar.

Kurz und gut, der Auftrag besteht mehr aus Unternehmensberatung als aus Technik. Es gelingt, über mehrere Monate hinweg, Daten zu verlagern, Dienste wie Steuerbüro, Bank, Dokumentenverwaltung, E-Mails, Webauftritt neu aufzusetzen.

Branchensoftware

Was sich als wirklich schwierig gestaltet, ist die eingesetzte Branchenlösung.

Selbstverständlich gibt es online so gut wie keine Dokumentation, denn die Lösung wurde von einem anderen KMU entwickelt und ist nur regional von Bedeutung. Sie ist aber groß genug, um die Abwicklung ausschließlich über Partner (Systemhäuser) zu realisieren.

Selbstverständlich ist jede Installation eine individuell angepasste Vor-Ort-Installation, für die der Hersteller weder Auskunft gibt, noch davon Kenntnis hat. Die klassische Antwort ist da in der Regel: Diese Version ist völlig veraltet.

Es stellt sich heraus, dass die Mitarbeiter über ein VPN auf einem Terminalserver an einem anderen Firmenstandort arbeiten. Leider kann niemand etwas zu dem Server und der dortigen Software sagen. Der betreffende Mitarbeitet ist schon länger nicht mehr angestellt.

Bei einem Vor-Ort-Termin bekommen wir heraus, dass die Software offenbar nur ein Frontend ist, die ihrerseits ein Backend anspricht. Wo dieses Backend steht, weiß keiner.

Die Backend-IP führt zu einem Systemhaus in der Nachbarstadt. Dort weiß man zunächst nichts von dem Kunden oder gar einem Serverbetrieb. Mehr aus Neugier folgt man unseren Angaben und meldet zurück: Endlich wissen wir, was diese Maschine da soll. Wir konnten die bisher nicht zuordnen. Übernehmen Sie die?

Selbstverständlich gibt es weder Vertrag zwischen Firma und Systemhaus, noch irgendwelche Zahlungen, wobei man bei letztem allgemein unsicher ist.

Technik

Was dann bei uns ankam, waren drei Geräte.

Man sagte uns, ein Server habe viele Festplatten und sei echt schwer. Es steht APC drauf. Sie haben also die USV mit ausgebaut und versendet.

Ein Server ist ein Tower, der andere im 19" Einbaurahmen. Mal sehen, was da drauf ist.