MariaDB, Master/Slave – Master/Slave-Replikation – Synchronisation der Binary Logs mit dem Storage ? – II

Im letzten Beitrag hatte ich eine row-basierte Master/Slave-Replikation zwischen zwei MariaDB-Servern konfiguriert und mit kontinuierlichen INSERTs getestet. Ein Ergebnis war, dass es bei einer Dauerlast auf dem Master und einer hochfrequenten Synchronisation der Log-Files auf dem Slave-System mit Festplatten durchaus zu einem systematischen Anwachsen der “Catch Up”-Zeit zwischen Master- und Slave-System kommen kann. Als Ursache erschien plausibel, dass der Slave mehr mit Updates der Logfiles und deren Synchronisation [SYNC] in Richtung Storage-System beschäftigt ist als mit der Durchführung der SQL-Änderungen in der Datenbank selbst.

Ein Heilmittel bestand darin, die Sychronisation der Log-Files im Bedarfsfall nicht, wie üblicherweise empfohlen, nach jeder Änderung sondern erst nach mehreren Änderungen vornehmen zu lassen. Das RDBMS kann dann wieder Commits in hinreichender Anzahl ausführen und der Änderungsfrequenz auf dem Master-RDBMS nahtlos folgen.

Im vorliegenden Beitrag überprüfen wir diesen Befund nun mittels eines etwas komplexeren Szenarios – nämlich einer parallel stattfindenden “Master/Slave – Master/Slave”-Replikation zwischen zwei Servern für zwei unterschiedliche Datenbanken (Schemata).

Konfiguration des ersten Servers

Die Skizze aus dem letzten Beitrag zeigt die Konfiguration schematisch:

Wir haben zwei RDBMS-Serversysteme “histux” und “hertux“. “hertux” fungiert als Master bzgl. der Datenbank “Kirk”, “histux” dagegen als Master bzgl. der Datenbank “Spock”. Repliziert wird zum jeweils anderen Server.

Die für die Replikation relevanten Einträge in der Konfigurationsdatei “/etc/my.cnf” auf dem Server “hertux” sehen dann etwa wie folgt aus:

Server “hertux”:

[mysqld]
# Enforce GTID consistency
#gtid-mode=ON
#enforce_gtid_consistency=1

# Binary Log 
log_bin=/var/lib/mysql/mysql-bin
binlog_format=row 
binlog_do_db='Kirk'

# Slave with respect to "Spock"
relay_log=/var/lib/mysql/relay-bin
skip_slave_start
log_slave_updates=1

slave-parallel-threads=10
replicate_do_db='Spock' 

# SYNC statements
sync_binlog=1
sync_master_info=2
sync_relay_log=2
sync_relay_log_info=2

# Server ID
server-id	= 2

# These are commonly set, remove the # and set as required.
# port = 3306
...
...

 
Die meisten Einträge kennen wir bereits aus dem letzten Artikel. Die Statements, die sich auf die Slave-Rolle beziehen, wurden dort für das System “histux” erläutert. Sie sind nun in gleicher Weise auf dem System “hertux” für die Datenbank “Spock” zur Anwendung zu bringen.

Neu ist dagegen das Statement

binlog_do_db=’Kirk’

Dieses Statement schränkt die Aufzeichnung der zu replizierenden Master-Änderungen(SQL-Statements oder Row-Änderungen) im Binary Log File auf die Datenbank “Kirk” ein! Das ist im vorliegenden Fall harmlos. Anders sähe die Situation dagegen im Fall einer statement-basierten Replikation aus: Die Einschränkung bezieht sich nämlich immer nur auf die aktive Bank! Das hat Auswirkungen bei bank-übergreifenden SQL-Statements! Im Fall statement-basierter Replikaton sollte man deshalb die Warnungen unter “https://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html” beachten:

Zitat bzgl. der Variable “binlog-do-db=db_name”:
…. Statement-based logging: Only those statements are written to the binary log where the default database (that is, the one selected by USE) is db_name. To specify more than one database, use this option multiple times, once for each database; however, doing so does not cause cross-database statements such as UPDATE some_db.some_table SET foo=’bar’ to be logged while a different database (or no database) is selected. …” (Hervorhebung durch mich).

Für die im aktuellen Szenario verwendete “row-basierte” Replikation ist die Situation jedoch einfacher.

Zitat:
“… Row-based logging: Logging is restricted to database db_name. Only changes to tables belonging to db_name are logged; the default database has no effect on this. Suppose that the server is started with –binlog-do-db=sales and row-based logging is in effect, and then the following statements are executed:

USE prices;
UPDATE sales.february SET amount=amount+100;

The changes to the february table in the sales database are logged in accordance with the UPDATE statement; this occurs whether or not the USE statement was issued. However, when using the row-based logging format and –binlog-do-db=sales, changes made by the following UPDATE are not logged:

USE prices;
UPDATE prices.march SET amount=amount-25;

Even if the USE prices statement were changed to USE sales, the UPDATE statement’s effects would still not be written to the binary log. ….”

Das entspricht aus meiner Sicht doch recht gut der Erwartungshaltung eines Anwenders.

Bzgl. seiner zweiten Rolle als Slave-Systems schränkt das Statement

replicate_do_db=’Spock’

die Replikation auf die Bank “Spock” ein; “replicate_do_db” ist das slave-bezogene Gegenstück zum Statement “binlog_do_db” für die Master-Rolle.

Im Falle einer Replikation mehrerer Datenbanken ist zudem folgender Punkt zu beachten:

To specify multiple databases you must use multiple instances of this option. Because database names can contain commas, the list will be treated as the name of a single database if you supply a comma-separated list.

Konfiguration des zweiten Servers

Für den Server “histux” nehmen wir eine gespiegelte Konfiguration vor:

Server “histux”

[mysqld]
# Enforce GTID consistency
#gtid_mode=ON
#enforce_gtid_consistency=1

# Binary Log File 
log_bin=/var/lib/mysql/mysql-bin
binlog_format=row 
binlog_do_db='Spock'

# Slave with respect to database "Kirk"
relay_log=/var/lib/mysql/relay-bin
skip_slave_start
log_slave_updates=1
slave-parallel-threads=10
replicate_do_db='Kirk' 

# SYNC statements  
sync_binlog=1
sync_master_info=2
sync_relay_log=2
sync_relay_log_info=2

#Server ID 
server-id	= 3

# These are commonly set, remove the # and set as required.
port = 3386
...
...

 
Wir haben hier zusätzlich den MySQL-Port geändert! Natürlich müssen festgelegte Ports für die Replikation in evtl. zwischengeschalteten Firewalls geöffnet werden.

Test 1: 10000 INSERTs auf beiden Servern / SYNC-Werte ≤ 2 / Replikationsstart zeitlich versetzt

Auf beiden Servern sehen wir – wie im letzten Artikel beschrieben – einen manuellen Start der Replikation vor (skip_slave_start !). Den priviligierten Datenbank-User für die Durchführung von Replikationen hatten wir bereits im letzten Artikel auf beiden RDBMS angelegt.

Wie im letzten Artikel erzeugen wir auf beiden Servern für eine begrenzte Zeit von ca. 80 Sek. eine
Dauerlast durch permanente Durchführung von 10000 Einzel-INSERTs in Tabellen der Bank “Kirk” auf “hertux” und nun such in Tabellen der Bank “Spock” auf “histux”. Nach dem Start des Testprograms starten wir auf beiden Servern etwas zeitversetzt die jeweilige Slave-Replikation. Vor dem Replikationsstart auf “hertux” müssen wir allerdings noch (einmalig) die Daten für den Master-Server “histux” (DB Spock) am MySQL-Prompt setzen; dies geschieht in Anlehnung an das Vorgehen im letzten Artikel durch folgende Statements:

MariaDB [Spock]> CHANGE MASTER TO MASTER_HOST='histux.mynet.de',  MASTER_USER='repl', MASTER_PASSWORD='MyReplPasswd', MASTER_PORT=3386;
MariaDB [Spock]> CHANGE MASTER TO master_use_gtid=slave_pos;
MariaDB [Spock]> START SLAVE;

Für SYNC-Werte

sync_binlog=1
sync_master_info=2
sync_relay_log=2
sync_relay_log_info=2

auf beiden Servern erhielt ich für meine HW-Konfiguration ein systematisch anwachsendes Nachlaufen eines der beiden RDBMS:

30 < Catch Up-Zeit < 60 Sekunden

Welcher Server hinterherhinkte und welchen genauen Wert die Catch Up-Zeit annahm, hing u.a. davon ab

  • auf welchem Server die INSERTs zuerst gestartet wurden,
  • und wie groß der zeitliche Versatz des Starts der Slave-Replikationen gewählt wurde.

Festzuhalten bleibt aber auch diesmal, dass ein systematisches Anwachsen der Catch Up-Zeit durchaus möglich ist, wenn die SYNC-Parameter zu klein gewählt werden. Die absoluten Werte für die Catch Up-Zeit wirken klein; angesichts der gesamten INSERT-Zeit von ca. 80 Sekunden pro Server sind sie aber signifikant groß.

Test 2: 10000 INSERTs auf beiden Servern / SYNC-Werte ≥ 2 / Replikationsstart zeitlich versetzt

Wählt man hingegen SYNC-Werte von

# SYNC-Werte
sync_binlog=1
sync_master_info=3
sync_relay_log=3
sync_relay_log_info=3

und führt wieder zeitlich etwas versetzte INSERTS auf beiden Servern aus, so ergibt sich keine nenneswerte Catch Up-Zeit:

Server “histux”:

MariaDB [(none)]> SHOW SLAVE STATUS\G
....              
                  Master_Host: hertux.mynet.de
                  Master_User: repl
                  Master_Port: 3306
....
              Replicate_Do_DB: Kirk
....
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1660492
              Relay_Log_Space: 943
....
        Seconds_Behind_Master: 0
....
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 2
                   Using_Gtid: Slave_Pos
                  Gtid_IO_Pos: 0-2-537280
1 row in set (0.00 sec)

 
Server “hertux”:

MariaDB [(none)]> SHOW SLAVE STATUS\G

                  Master_Host: histux.mynet.de
                  Master_User: repl
                  Master_Port: 3386
...
              Replicate_Do_DB: Spock
...                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 342
              Relay_Log_Space: 1671507
...
        Seconds_Behind_Master: 0
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 3
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
                   Using_Gtid: Slave_Pos
                  Gtid_IO_Pos: 0-3-535624
1 row in set (0.00 sec)

 
Beide
Server arbeiten also synchron; auf beiden RDBMS gilt:

Seconds_Behind_Master: 0

Bewertung und Fazit

Steht der bzw. stehen die Master-Server in einer Replikation vom Typ

  • “Master-Slave”>
  • oder “Master/Slave – Master/Slave”

unter dauerhafter Last, sollte man ein Auge auf die SYNC-Parametrierung für die Log-Files werfen. Ggf. sollten die slave-bezogenen SYNC-Variablen auf Werte > 2 gesetzt werden, um ein systematisches Anwachsen von Catch Up-Zeiten zwischen den RDBMS-Systemen zu vermeiden.

sync_binlog=1
sync_master_info=3
sync_relay_log=3
sync_relay_log_info=3

Der zu wählende Wert ist natürlich abhängig von der HW-Konfiguration.

Wir groß ist der potentielle Schaden im Fall eines Crashes, in dem Änderungen verloren gehen, die nicht rechtzeitig auf das Plattensystem geschrieben wurden? Aus meiner Sicht nicht groß. Relevant nach einem Systemcrash ist ja der zu wählende richtige Aufsetzpunkt für die jeweilige lave-Replikation. (Bzgl. der Änderungen in einer Master-Datenbank müssen sowieso Mechanismen der jeweiligen Applikation greifen.) Werden die SYNC-Parameter klein gewählt, sind nur einige wenige letzte Transaktionen vor dem Crash zu prüfen, um den richtigen Aufsetzpunkt (bzw. die zugehörige GTID) zu bestimmen. In einer Abwägung

zwischen einem nicht ganz nahtlosen Wiederaufsetzen der Replikation nach einem Crash
undeiner systematisch anwachsenden Catch UP-Zeit während der Replikation

erscheint mir der begrenzte Aufwand für die Identifikation der richtigen GTID das kleinere Übel zu sein.

Links

https://mariadb.com/kb/en/library/gtid/
https://www.lexiconn.com/blog/2014/04/how-to-set-up-selective-master-slave-replication-in-mysql/
https://docs.jelastic.com/mariadb-master-slave-replication

MariaDB, Master/Slave – Master/Slave-Replikation – Synchronisation der Binary Logs mit dem Storage ? – I

Datenbank-Replikationen sind nützlich und können in vielen Anwendungen einen Gleichstand von Daten über System- und Netzgrenzen hinweg ermöglichen. Es ist relativ einfach, eine Master-Slave-Replikation mit MariaDB oder MySQL zu implementieren. Ich verwende solche Replikationen inzwischen häufig, um Ergebnisdaten komplexer Berechnungen zwischen RDBMS-Serversystemen zu übertragen.

Je nachdem, wie groß

  • die Übertragungsrate des Netzwerkes zwischen den RDBMS-Servern ist,
  • wie groß die Transfergeschwindigkeit zum Storage-Sub-System auf jedem der Server ist
  • und wie die Parametrierung der Replikation erfolgt

kann man dabei Überraschungen mit den “CatchUp“-Zeiten erleben. Unter der CatchUp-Zeit verstehe ich hier die Zeit, die das Slave-System hinter dem Status seines Master-Systems hinterherhinkt.

Relevant werden diese Zeiten natürlich vor allem dann, wenn auf dem Master über einen längeren Zeitraum hinweg die Änderungsrate durch INSERTs und UPDATEs kontinuierlich hoch bleibt. Sprich: Wenn das RDBMS des Masters richtig unter Last steht und neben den eigentlichen SQL-Statements permanent Log-Einträge zum Slave-System geschaufelt werden müssen.

In einem Lastszenario mit Perioden dauerhafter Last muss man natürlich auch an die Fähigkeit zur Restaurierung des gesamten RDBMS-Verbundes denken. Dass man regelmäßige Backups braucht, ist sowieso klar. Es stellt sich aber auch die Frage, wie man die Replikation nach Crashes eines der beteiligten Systeme wieder aufsetzen kann.

Folgt man dem Standardwerk “High Performance MySQL” von Schwartz, Zaitsev, Tkachenko (O’Reilly Verlag, 3rd Ed.), so erhält man den Eindruck, dass man vor Crashes gehörigen Respekt haben sollte. Die Autoren empfehlen deshalb in mehreren Abschnitten (sehr von Vorsicht geprägte) Einstellungen zur Synchronisation von “Binary Log Files” und “Information Log Files” mit den Storage-Systemen – sowohl auf dem Master- wie auch auf dem Slave-System.

Es ist grundsätzlich interessant, sich das mal anzusehen. Ferner gilt: Replizierende Systeme haben nicht immer ein identisches Leistungsvermögen. Wie wirken sich SYNC-Einstellungen dann auf CatchUp-Zeiten aus? Bei einem Kunden ergab sich vor einiger Zeit zudem die Frage, wie es eigentlich mit einer “Master/Slave-Master/Slave”-Replikation aussieht. Gemeint waren hier gegenseitige Replikationen mit vertauschten Master/Slave-Rollen für zwei unterschiedliche Datenbanken; beide RDBMS-Systeme spielen dabei sowohl Master als auch Slave, nur eben für verschiedene Datenbanken (Schemata).

Zeit, mal einen Blick auf das grundsätzliche Replikationsverhalten für 2 Server in unserem LAN zu werfen. Im vorliegenden Artikel bespreche ich, wie man eine einfache Master/Slave-Replikation aufsetzt. Der Text ist also auch für Leute gedacht, die MySQL/MariaDB zwar nutzen, sich dem Thema Replikation aber noch nie genähert haben. Die angegebenen Kommandos sind einfach nachzustellen. Ein zweiter Artikel greift dann die komplexere “Master/Slave-Master/Slave”-Konstellation auf.

Eigentliches Ziel beider Artikel ist es aber, herauszuarbeiten, ob und wie man ggf. an SYNC-Einstellungen drehen kann, um die CatchUp-Zeit möglichst gering zu halten.

Testsituation Master/Slave – Master/Slave

Die nachfolgende Skizze zeigt den Testaufbau schematisch:

Wir haben zwei RDBMS-Serversysteme “histux” und “hertux“. Wir betrachten nachfolgend zunächst nur den oberen Teil der Skizze – also ein reines Master/Slave-Szenario bzgl. der
Datenbank “Kirk”. “hertux” fungiert dabei als Master, “histux” als Slave.

Im zweiten Artikel dieser Serie ergänzen wir dann das Master/Slave-Szenario mit umgekehrtem Vorzeichen für eine weitere Datenbank “Spock” (unterer Teil der Skizze). “histux” wird dann für die Datenbank “Spock” die Rolle des Masters übernehmen, “hertux” die des Slaves. Es entsteht so das dargestellte “Master/Slave – Master/Slave” Szenario. Beide Server spielen darin gleichzeitig sowohl Master, als auch Slave für jeweils eine der Datenbanken [DBen].

Ich verwende in meinem Setup übrigens Systeme mit einer MariaDB – und nicht mit einem originalen MySQL-RDBMS. In meinem Fall ist das “histux”-System etwas schwächer ausgelegt als das “hertux”-System; das betrifft den Prozessor, aber auch das Storage-System (einfache HD vs. einfache SSD; für Tests mit schnellen SSD-Raid-Verbänden hatte ich noch keine Zeit …).

Ich betrachte nachfolgend nur InnoDB-Tabellen, deren Änderungen (Inserts) mit einer sog. row-basierten Replikation (s.u.) auf die jeweiligen Slave-Server übertragen werden sollen. Um der Replikation eine Chance zu geben, werden die Änderungen (Inserts) durch echte Einzelstatements für jeden Record erzeugt. Inserts, Updates für mehrere Datensätze werden also nicht in einem SQL-Statement gebündelt.

Master/Slave: Konfiguration des Master-Servers

Die DB “Kirk” existiere zunächst als einzige DB in den RDBMS der Server “histux” und “hertux“. Die notwendigen Konfigurationsstatements für die RDBMS-Replikation sind dann recht einfach; wir tragen folgende Zeilen in die Datei “/etc/my.cnf” des Master-Systems “hertux” ein:

# Binary Log file / Log Method 
log_bin=/var/lib/mysql/mysql-bin
binlog_format=row
# binlog_format=mixed

# Syn des Logfiles auf die Platte 
sync_binlog=1

#ID des Servers 
server-id=2

Wir gehen kurz die drei Einstellungsgruppen durch:

Binary-Log-File und Log- bzw. Replikations-Verfahren
Transaktionen auf einem System werden in sog. “Binary Log”-Dateien protokolliert. Die ersten zwei Statements legen fest, wo das Binary-Log-File gelagert wird und welches Format des Loggings verwendet wird:

Eine Replikation kann (SQL-) statement-bezogen oder row-bezogen durchgeführt werden.
Im ersteren Fall werden SQL-Statements vom Master auf den Slave übertragen und dort nachgefahren. Im zweiten Fall werden Daten-Änderungen betroffener Tabellen-Rows übertragen. Je nach Art von (komplexen) SQL-Statements kann das Nachfahren solcher Statements auf dem Slave deutlich aufwändiger sein, als die Änderungen der betroffenen Datensätze selbst nachzuziehen. Andererseits gilt evtl. genau das Umgekehrte für Massenänderungen über viele Rows hinweg. Man sollte die Art des Loggings also an der Charakteristik seiner SQL-Anwendungen ausrichten. Das gilt im Grunde aber auch für den Einsatz von MyISAM vs. InnoDB-Tabllen. Im Kontext von InnoDB-Tabellen und Anwendungen mit Einzeländerungen verwende ich selbst oft eine row-basierte Replikation. Stehen dagegen Massenänderungen vieler numerischer Daten im Fokus einer Anwendung weiche ich oft auf MyISAM-Tabellen und statement-basierte Replikation aus. Pauschalisieren lässt sich das aber nicht.

Synchronisation mit dem Storage-Subsystem
Das Statement “sync_binlog=1” legt fest, dass das Binary Log File mit dem Storage-Systems des Servers (z.B. einer lokalen Harddisk) nach jedem Commit synchronisiert werden soll. Das sichert gegenüber Datenverlust während Systemcrashes ab; aber eine solche Synchronisation ist eine durchaus aufwändige Operation, die die Performance bei vielen Änderungen pro Sekunde
beeinträchtigen kann. In kleineren Firmen sind hier batteriegepufferte Caches von Raid-Controllern ggf. ein Ausweg.

Server-ID
Sind in einem Netzwerkverbund mehrere Server vorhanden, so sollte jedes RDBMS mit einer netzwerkweit eindeutigen Server-ID versehen werden. Die Festlegung einer eindeutigen ID der MySQL/MariaDB-RDBMS ist notwendig, um sog. “Globale Transaktions IDs” [GTIDs] zu unterstützen. In die Transaktions-IDs geht u.a. die eindeutige ID eines Servers mit ein.
Ich weise daraufhin, dass Format/Implementierung von GTIDs einer MariaDB (> Version 10.0.3) anders aussehen als bei einer herkömmlichen MySQL-Datenbank. Siehe hierzu:
https://mariadb.com/kb/en/library/gtid/#setting-up-a-new-slave-server-with-global-transaction-id.

Mit der bisherigen Einstellung werden Änderungen aller Datenbanken [DBen] des MariaDB RDBMS “hertux” im “Binary Log File” des Masters aufgezeichnet. Wir werden das im nächsten Artikel durch einen einfachen Filter für DBen abändern.

Alle anderen Einstellungen (u.a. bzgl. der IO-capacity und Anzahl IO Threads für InnoDB, ..) bleiben in meinem Test auf Standardwerten.

Master/Slave: Konfiguration des Slave-Servers

Die “/etc/my.cnf” des Slave-Systems “histux” sieht etwas erwartungsgemäß anders aus:

# Binary Log file / Log Method 
log_bin=/var/lib/mysql/mysql-bin
# binlog_format=mixed
binlog_format=row

# Relay Log File, automat. Starten der Replikation?   
relay_log=/var/lib/mysql/relay-bin
skip_slave_start

# Log der Updates
log_slave_updates=1

# Threads 
slave-parallel-threads=4

#ID des Servers 
server-id=3
# read-only=1

Hinweise zu den Einstellungen:

Relay-Log-File
Auf dem Slave ist die Festlegung des Relay-Log-Files erforderlich. Hierhin werden die durchzuführenden Transaktionen des Masters übertragen; in unserem einfachen Fall, in dem keine Änderungen auf dem Slave durchgeführt werden, ergibt sich letztlich eine Kopie des Binary-Logs des Masters.

Kein automatischer Start der Replikation
Wir schalten über “skip_slave_start” ein automatisches Starten der Replikation nach dem Starten des RDBMS ab. Das ist für Testsituationen OK; auf Produktiv-Systemen mag der Bedarf anders sein. Die Replikation lässt sich manuell immer zu einem geeigneten Zeitpunkt starten. Z.B., wenn man sicher ist, dass der Master auch aktionsbereit ist; s.u.. Über weitere Parameter (s. die MariaDB-Dokumentation) kann man steuern, wie oft und in welchem zeitlichen Abstand der Slave einen Verbindungsversuch zum Master unternehmen soll.)

Eintrag der Slave-Aktionen im eigenen Binary-Log?
“log_slave_updates=1” sorgt dafür, dass die Replikationstransaktionen im eigenen Binary Log des Slaves vermerkt werden. (Das kann wichtig sein, wenn der Slave selbst wieder Master gegenüber dritten Systemen spielen soll).

Mehrere Threads zum Nachfahren der übermittelten Änderungen
Wir stellen zudem mehrere Threads zur Verfügung, um die einlaufenden row-basierten Änderungen ggf. parallel in die Bank zu übertragen Dies betrifft ausschließlich die SQL-Ebene; s. https://mariadb.com/kb/en/library/parallel-replication/. Welche Anzahl von Threads sinnvoll ist, hängt von der Änderungsrate auf dem Master UND der Leistungsfähigkeit des Slave-Systems ab. Man muss testen, bis zu welcher Thread-Anzahl sich noch eine Performanceverbesserung ergibt.

Auf dem
Slave “histux” könnte die Nutzung global auch auf “read-only” gesetzt werden, wenn die Datenbankinhalte wirklich nur replizierte Inhalte beinhalten sollen. In unserem Fall ist dies wenig sinnvoll, da “histux” ja später Master für die zusätzliche DB “Spock” werden soll. Das entsprechende Statement wurde daher auskommentiert.

Was brauchen wir noch für eine funktionsgerechte Master-Slave-Replikation?

Auf dem Master müssen wir einem Datenbank-User (hier: “repl”) Replikationsrechte einräumen; das zugehörige SQL-Statement, das wir nach Einloggen in das Master-RDBMS am MySQL-Prompt absetzen, ist:

GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO repl@’192.168.0.%’ IDENTIFIED BY ‘MyReplPasswd’;

“repl” ist ein in priviligierter Account, der alle transaktionalen Änderungen auf dem RDBMS einsehen kann. Auch, wenn dieser Account an Datenbankeinträgen nicht direkt etwas ändern kann, können sich aus seinen Rechten dennoch sekundäre Sicherheitsprobleme ergeben. Also: Vorsicht! Der gleiche User sollte natürlich auch auf dem Slave angelegt werden.

Füllen des Masters

Nun führen wir auf dem Master-Server und seiner/n Tabelle/n einen Schwung von SQL-Statements aus. Ich benutze dazu immer PHP-Test-Files, die hunderttausende von Inserts vornehmen.

Wir prüfen dann auf dem Master Server den Status und damit gleichzeitig den genauen Namen des Binary-Log-Files ab:


MariaDB [Kirk]> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000007 | 16601394 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

 
Man sieht hier, dass auf dem Master schon Einiges passiert ist.

Starten der Replikation auf dem Slave

Wir starten nun unsere erste Replikation. Wir melden uns dazu als Datenbank-User “root” am Slave RDBMS von “histux” an (“mysql -u root -p”). Am MySQL-Prompt geben wir ein:

MariaDB [Kirk]> CHANGE MASTER TO MASTER_HOST='hertux.mynet.de',  MASTER_USER='repl', MASTER_PASSWORD='MyReplPasswd', MASTER_LOG_FILE='mysql-bin.000007;
MariaDB [Kirk]> CHANGE MASTER TO master_use_gtid=slave_pos;
MariaDB [Kirk]> START SLAVE;

 
Das erste Statement definiert den Master und seine Eigenschaften (dauerhaft) für das Slave-System! das zweite Statement setzt den Ausgangspunkt der Replikation auf die richtige Position im Binary File. Das ist im vorliegenden Fall natürlich die 0-Position. Das angegebene Statement

CHANGE MASTER TO master_use_gtid=slave_pos;

lässt sich im regulären Betrieb nach einem evtl. erfolgten Restart des Slaves oder einem Stop und Neustart der Replikation aber immer wieder einsetzen: Die Replikation soll ab der Position im Log-File ansetzen, zu der der Slave bislang gekommen war.

Die Master-Log-Files ändern im Lauf des Betriebs ihre Bezeichnung. Wir müssen uns im weiteren Normalbetrieb allerdings nicht mehr um die Angabe des richtigen Master-Log-Files kümmern. Der Slave erkennt dies in der Regel über GTIDs automatisch. Im Gegensatz zu früheren MariaDB-Varianten, in denen GTIDs nicht automatisch benutzt wurden, muss man sich nun im Normalbetrieb also keine Gedanken mehr zu Byte-bezogenen Positionen im binären Master-Log machen. Das Statement “CHANGE MASTER TO master_use_gtid=slave_pos;” sorgt dafür, dass der richtige Aufsetzpunkt für die Replikation im Verhältnis zum Status des Slaves gefunden wird.

Man kann den
Ablauf der Replikation auf dem Slave nun mit

MariaDB [Kirk]> SHOW SLAVE STATUS\G

verfolgen. Am Schluss des Nachfahrens aller bisherigen Einträge in unsere Test-DB “Kirk” erhält man dann etwas in der Art :

MariaDB [(none)]> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: hertux.mynet.de
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000007
          Read_Master_Log_Pos: 16601394
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 16601681
        Relay_Master_Log_File: mysql-bin.000007
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 16601394
              Relay_Log_Space: 16601972
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 2
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
                   Using_Gtid: Slave_Pos
                  Gtid_IO_Pos: 0-2-311024
1 row in set (0.00 sec)

 
Wer mag kann den korrekten Tabellenstatus ja mit PhpMyAdmin kontrollieren. Nebenbei: Es lohnt sich, bei Gelegenheit die Features von PhpMyAdmin für Replikationseinstellungen und die Einsichtnahme in zugehörige Parameter des RDBMS zu studieren.

Interessant ist der Unterschied zwischen der GTID-Position und der Byte-Position:

Gtid_IO_Pos: 0-2-311024
Exec_Master_Log_Pos: 16601394

Verschiedene Infos; gleiche Positionierung in den Binary-Logs!

Die aktuellen Positionen lassen sich auf Master und Slave übrigens jederzeit wie folgt abfragen:

Master

MariaDB [massa]> SELECT @@GLOBAL.gtid_binlog_pos;
+--------------------------+
| @@GLOBAL.gtid_binlog_pos |
+--------------------------+
| 0-2-331028               |
+--------------------------+
1 row in set (0.00 sec)
  
<strong>Slave</strong> 
MariaDB [massa]> SELECT @@GLOBAL.gtid_slave_pos;
+-------------------------+
| @@GLOBAL.gtid_slave_pos |
+-------------------------+
| 0-2-331028              |
+-------------------------+
1 row in set (0.00 sec)

Master/Slave: Test mit 10000 neuen Inserts am Master – ohne SYNC-Einstellungen am Slave

Für meinen Test zur CatchUP-Zeit verwende ich ein Skript, das fortlaufende Inserts in einer InnoDB-Tabelle vornimmt – und zwar Record/Row für Record/Row – inkl. paralleler Indexgenerierung. Ohne Prepared Statements. Es werden dabei mehrere Stringfelder eines neuen Datensatzes gefüllt.

Ich begrenze die Anzahl auf 10000 Inserts. Die Zeitdauer für meine Inserts beträgt 80 Sek..

Die Rate ist also nicht besonders hoch; das liegt u.a. an einer parallel stattfindenden Index-
Generierung und fehlender Optimierung. Die Insert-Rate lässt sich viel höher schrauben; allein eine Bündelung von Inserts in einem Statement und/oder die Nutzung von “prepared statements” würde Faktoren an Geschwindigkeit bringen. Aber es geht mir hier nicht um Optimierung; es kommt mir nur auf relative Anteile der CatchUp-Zeiten an.

Welche CatchUp-Zeit zieht eine solche Insert-Folge während der 80 Sekunden Laufzeit nach sich?

Wir greifen hierzu – während das Testprogramm mit den Inserts läuft – den Slave-Status am Slave ab:

 
MariaDB [massa]> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: histux.mynet.de
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000008
          Read_Master_Log_Pos: 1878830
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 1879117
        Relay_Master_Log_File: mysql-bin.000008
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1878830
              Relay_Log_Space: 1879408
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 2
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
                   Using_Gtid: Slave_Pos
                  Gtid_IO_Pos: 0-2-332342
1 row in set (0.00 sec)

 
Relevant ist die Zeile:

Seconds_Behind_Master: 0

Wunderbar! Offenbar kann der Slave unter den herrschenden Bedingungen [LAN, keine SYNC-Prozesse] locker mithalten – obwohl er schwächer ausgelegt ist als der Master!

Auf den Master hat der Datenaustausch für die Replikation übrigens kaum Auswirkungen: Die benötigte Gesamtzeit steigt dort von etwa 80 Sekunden auf 84 Sekunden an.

Master/Slave: Test mit 10000 neuen Inserts am Master – mit SYNCs auf die HD am Slave

Wir verändern die Einstellung des Slave-RDBMS bzgl. der Synchronisation von dortigen Log-Files zum Storage-System. Es gibt mehrere Dateien, die im Replikationsvorgang auf dem Slave-System fortgeschrieben werden (Relay-Log=> nachzufahrende Transaktionen / master.info-File: Infos über die Position des Masters / Relay_log.info-File => eigene Position im Relay-Log.) Wir folgen zunächst 1:1 den Empfehlungen des Buchs “High Performance MySQL”:

#sync_binlog=1
sync_master_info=1
sync_relay_log=1
sync_relay_log_info=1

Damit starten wir das MariaDB-RDBMS auf dem Slave-Server “histux” neu und loggen uns wieder mittels “mysql -u root -p” in das RDBMS ein. Am MySQL-Prompt verfolgen wir dann einen neuen Testlauf und fragen sukzessive den Slave-Status ab. Es zeigte für meine Systeme leider, dass die CatchUp-Zeit relativ zum Master-Status nun permanent und systematisch zunahm!:

 
MariaDB [(none)]> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Queueing master event to the relay log
                  Master_Host: histux.mynet.de
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000008
          Read_Master_Log_Pos: 6766074
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 5466
        Relay_Master_Log_File: mysql-bin.000008
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 5318184
              Relay_Log_Space: 1453647
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 131
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 2
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
                   Using_Gtid: Slave_Pos
                  Gtid_IO_Pos: 0-2-361783
1 row in set (0.12 sec)

 

Am Schluss erhielt ich als maximale Differenz:

Seconds_Behind_Master: 158 (Sekunden)

Es sieht also so aus, dass eine Synchronisation von Relay-Log-Dateien auf dem Slave sehr problematische Folgen haben kann: Immerhin ist der Zeitverlust gegenüber dem Master auf fast das Doppelte der für die DB-Transaktionen benötigten Zeit angewachsen!

In anderen Tests mit über 100000 Inserts wuchs der Zeitverlust weiter extrem an – auf über 3 Stunden!

Master/Slave: SYNC in größeren Transaktions-Abständen am Slave?

Kann man das obige verheerende Ergebnis irgendwie beseitigen? Ein wenig Experimentierfreude zeigt schnell, dass eine Änderung der Parameter auf

  
log_slave_updates=0
sync_master_info=0
sync_relay_log=1
sync_relay_log_info=0

leider gar nichts bringt. Der systematisch größer werdenden Abstand zwischen Slave und Master legt den Schluss nahe, dass der Slave vor lauter SYNC-Prozessen gar nicht dazu kommt, seine SQL-Arbeit im RDBMS durchzuführen. Daten müssen über Netz vom Master geholt werden, Informationen über die Positionen des Masters und des Slaves auf dem Slave in Dateien geschrieben werden. Jede Datenbank-Transaktion am Slave führt dann zu zusätzlichen SYNC-Vorgängen, die unabhängig von den anwachsenden Master-Transaktionen durchzuführen sind. Zudem werden die Files bei einmal wachsender CatchUp-Zeit automatisch immer größer! Das riecht förmlich danach, dass unser Slave bei hoher Taktung der Änderungen auf dem Master in einen Teufelskreis gerät …

Wenn dies Theorie stimmt, dann sollten wir den Datenbanktransaktionen mehr Zeit gegenüber Synchronisationsprozessen einräumen. Die “1” als Parameter bei den 3 Slave-SYNC-Einstellungen bedeutet ja nicht ein Einschalten im Sinne eines boolschen Flags. Vielmehr kann hier ein numerischer Parameter angegeben werden: Er legt fest, nach wieviel Änderungen das jeweilige File auf dem jeweiligen Status
auf die Platten geschrieben werden soll. Wir sollten also versuchen, die SYNC-Parameterwerte zu erhöhen.

Tatsächlich ergibt sich bei einer Einstellung

  
relay_log=/var/lib/mysql/relay-bin
skip_slave_start
log_slave_updates=1
slave-parallel-threads=4
sync_master_info=4
sync_relay_log=4
sync_relay_log_info=4

das Ergebnis :

sync_relay_log=4, sync_master_info=4, sync_relay_log_info=4 => CatchUp-Zeit: 0 Sekunden

Geht man mit den sync-Parametern danach weiter runter, so erhalten wir wieder ein Anwachsen des Delays, wenn auch moderater als beim Wert “1”:

  
sync_master_info=2
sync_relay_log=2
sync_relay_log_info=2

sync_relay_log=4 => CatchUp-Zeit: 54 Sekunden

Bei einem Wert von “3”:

sync_relay_log=3 => CatchUp-Zeit: 3 Sekunden => 0 Sekunden

Master/Slave: SYNC und Abhängigkeit von der Anzahl der Slave-Threads?

Wir können parallel auch mal die Anzahl der Slave-Threads erhöhen. So ergibt

slave-parallel-threads=10
sync_master_info=2
sync_relay_log=2
sync_relay_log_info=2

sync_relay_log=2 / slave-parallel-threads=10 => CatchUp-Zeit: max. 3 Sekunden => 0 Sekunden

Fazit

Schon in einer normalen Master-Slave-Replikation gilt: Durch Synchronisation von Replikations-Log-Files mit dem HD- oder SSD-System auf dem Slave kann sich die CatchUp-Zeit systematisch erhöhen,

  • der Takt der Änderungen auf dem Master konstant hoch ist
  • wenn die Frequenz der SYNC-Prozesse zu hoch gewählt wird,
  • und eine row-basierte Replikation für InnoDB-Tabellen konfiguriert wurde.

Im vorliegenden Fall erwies sich die Vorgabe, nach jeder Änderung alle Log-Files direkt auf die Platte zu schreiben einfach als zu ambitiös: Das Slave-System ist mehr mit SYNC-Prozessen beschäftigt als mit der eigentlichen Durchführung der Änderungen in der Datenbank. Gerät das System erst einmal außer Takt, wächst die CatchUp-Zeit des Slaves gegenüber dem Master bei einer kontinuierlichen Last kontinuierlich an. Relevant ist das vor allem für gekoppelte Systeme, die permanente Änderungsprozesse hoher Frequenz verkraften müssen.

Für replizierende MariaDB-Systeme ist es deshalb wichtig zu testen, ob nicht mehrere Änderungen (Commits) in der Bank abgewartet werden sollten, bevor ein Schreiben der Binary-Log- und Info-Files auf das Storage-System erfolgen soll. U.U. genügt hier schon die Wahl eines nur etwas erhöhten Wertes

sync_master_info=3 (oder 4)
sync_relay_log=3 (oder 4)
sync_relay_log_info=3 (oder 4)

um schon eine signifikante Verbesserung zu erreichen. Die Arbeit, nach einem Crash des Slaves, den richtigen Aufsetzpunkt für die Replikation zu finden, hält sich dann immer noch in relativ engen Grenzen.

Im kommenden Artikel betrachten wir die Parametrierung und die gleiche Situation für eine “Master/Slave – Master/Slave”-Konfiguration.

Links

https://mariadb.com/kb/en/library/setting-up-replication/

firejail firecfg – Problem mit dem KDE-Login unter Opensuse Leap 42.3 – .ssh-Dateien und ssh-agent als Ursache

Experimentiert man unbedarft mir neuen Dingen, muss man sich nicht wundern, wenn man sich Probleme schafft. Jetzt passierte mir das mit firejail.

Ich muss manchmal Skype benutzen. Zu meinem großen Ärger, da jede Art von Closed Source UDP-Streaming Applikation ein prinzipielles Sicherheitsrisiko darstellt. In einen UDP-Datenstrom können immer Pakete integriert werden, die ganz anderen Zwecken dienen als der Übertragung der eigentlichen Audio- und Videodaten. Und wenn man dann den Code nicht kennt … Neben dem Aufsetzen eines speziell konfigurierten Containers ist die Nutzung von Firejail eine Gegenmaßnahme, solchen Applikationen das Vordringen ins System zu erschweren.

Opensuse 42.3 bietet im Repository “Virtualization
ein RPM-Paket firejail 0.9.5 zum Download an. Das habe ich installiert. nach der Installation war zunächst auch ein kein Problem feststellbar.

Aber dann habe ich ein wenig in der Dokumentation gestöbert. Auf der Seite https://firejail.wordpress.com/documentation-2/ findet man dann unter dem Titel “I’ve just installed Firejail, now what?!” Hinweise zu bestimmten Kommandos, um “pulseaudio” [PA] zu korrigieren (wundert mich nicht) und auch das Kommando “firecfg” auszuführen:

$ firecfg –fix-sound
$ sudo firecfg

Beides hat u.U. aber unangenehme Nebenwirkungen:

1) Pulseaudio zunächst nicht mehr deaktivierbar
Das erste Kommando korrigiert “pulseaudio”-Konfigurationsdateien zwar; es sorgt aber auch dafür, dass man unter Opensuse PA nicht mehr einfach über YaST und die dortige Audio-Konfiguraiton abschalten kann. Bekanntermaßen verwende ich PA nur, wenn nicht umgehbar. So erzwangen etwa frühere Skype Versionen für Linux ( u.a. die Version 4.3) die Nutzung von PA. Das ist beim aktuellen “skypeforlinux” (Beta) nicht der Fall; das kooperiert auch direkt mit Alsa.

Das ist auf meinem Laptop auch gut so, denn PA erzeugt dort ein dauerhaftes unangenehmes Hintergrundsgeräusch (niederfrequenter Pfeifton; keine Rückkopplung) auf meinem eingebauten Mikrophon (unabhängig von Skype). Das ließ sich auch durch Ändern der Empfindlichkeit und der Regelung von Verstärkungsfaktoren unter dem PA-eigenen “pavucontrol” nie beseitigen. Ein solches Geräusch tritt bei mir im reinen Alsa-Betrieb dagegen nicht auf.

Beseitigt habe ich die Aktivierung von PA dann durch Umbenennen/Verschieben der Datei “~/.pulseaudio” und anschließende erneute Deaktivierung von PA über YaST.

2) Kein KDE-Login und kein X11-Start mehr für bestimmte Accounts möglich
Schlimmer ist dagegen eine Auswirkung des zweiten Kommandos: Es erzeugt eine Liste von Links unter dem Verzeichnis von “/usr/local/bin“, die alle auf firejail verweisen. Normalerweise führt das dazu, dass viele Programme/Anwendungen über firejail gestartet und geschützt werden. Leider ist die Liste der Profile für Anwendungen aber keineswegs vollständig. Wird für eine Anwendung nichts gefunden, dann kommt wohl ein “default.profile” zum Einsatz. Letzteres verhindert aber den Zugriff u.a. auf ~/.ssh und ~/.gnupg-Verzeichnisse und dortige Dateien. Das wird aber unter Umständen unter Opensuse zu einem Megaproblem beim Start von KDE aus SDDM oder KDM heraus:

Ich konnte mich unter bestimmten Accounts nach dem Absetzen von firecfg nicht mehr von KDM oder SDDM aus in KDE (Plasma 5) einloggen. X11 wurde nicht gestartet; man landet nach ca. 1 Sekunde wieder auf dem KDM oder SDDM-Login-Schirm.

Die Fehlermeldungen hierzu waren unzureichend. Nach mühsamen Experimenten mit Konfigurationsdateien stieß ich schließlich darauf, dass allein die Existenz eines “~/.ssh“-Verzeichnisses zu Fehlern beim KDE-Start
führte. Entfernte ich das Verzeichnis komplett, ließen sich KDE und X11 wieder regulär starten.

Wer oder was will im Start “~/.ssh” auslesen? Mir fiel dazu zunächst nichts ein. Dann stieß ich auf ssh-agent. Und tatsächlich ergab sich unter Opensuse Leap 42.3 folgendes Bild:

mytux:~ # ps aux | grep ssh
root      1574  0.0  0.0  53492  5816 ?        Ss   13:30   0:00 /usr/sbin/
sshd -D
myself       4065  0.0  0.0  20136  1868 ?        S    13:30   0:00 /usr/bin/dbus-launch --sh-syntax --exit-with-session /usr/bin/ssh-agent /usr/bin/gpg-agent --sh --daemon --keep-display --write-env-file /home/myself/.gnupg/
agent.info-mytux.mydomain.de:0 /etc/X11/xinit/xinitrc
myself       4067  0.0  0.0  13312   332 ?        Ss   13:30   0:00 /usr/bin/ssh-agent /usr/bin/gpg-agent --sh --daemon --keep-display --write-env-file /home/myself/.gnupg/agent.info-mytux.mydomain.de:0 /etc/X11/xinit/xinitrc

Offenbar klappt diese Art des X-Starts nicht mit dem komplett gefüllten “/usr/local/bin” (genauer mit den dortigen Links). Ich sehe die Ursache – wie gesagt – im “default.profile”.

Die Link-Orgie unter “/usr/local/bin” beseitigt man übrigens mit

firecfg –clean

Danach klappt der Login in das X11/KDE-Gespann alles wieder. Meine Strategie ist im Moment, die Profile für verschiedene Anwendungen zu checken und “/usr/local/bin” langsam und systematisch mit Links zu füllen, die nur bestimmte Anwendungen betreffen.

Bei manchen alten Accounts habe ich zudem festgestellt, dass die Anlage der Links unter /usr/local/bin” auch dazu führt, dass jeglicher Netzwerkzugriff unterbunden ist. Hier bin ich noch an der Ursachenforschung.

Merke: Nicht gleich alles machen, was Manuals vorschlagen, wenn man von einer neuen Anwendung noch zu wenig versteht.

Upgrade Laptop to Opensuse 42.3, Probleme mit Bumblebee und VMware WS 12.5, Workarounds

Gestern war ein Upgrade meines nun schon in die Jahre gekommenen Laptops von Opensuse Leap 42.2 auf Leap 42.3 fälllig.
Ich bin dabei gem. der schönen Anleitung in
https://kamarada.github.io/en/2017/08/03/how-to-upgrade-from-opensuse-leap-422-to-423/
vorgegangen. Zu der Anleitung gibt es nichts weiter zu sagen; die ist perfekt. Im Upgrade hatte ich nur die Standardrepositories (inkl. Update-Repository) für Leap 42.3 benutzt.

Mein Laptop hat eine Nvidia-Karte (Optimus-System). Das ursprüngliche Leap 42.2 lief auf dem Laptop deshalb mit einer Bumblebee-Installation; das funktionierte einwandfrei. Zudem nutzte ich auf dem Laptop VMware WS 12.5. Nach dem Leap-Upgrade hatte ich jedoch sowohl mit Bumblebee als auch VMware-Workstation Probleme – obwohl auch Leap 42.3 nur einen Kernel der nun doch schon recht alten Version 4.4 aufweist! nach dem Ugrade war bei mir 4.4.92-31 aktiv; bei der Leap_42.3 war dagegen der Kernel 4.4.76 der Default-Kernel.

Nebenbei: Bzgl. der Kernelversionen hat der SLES-Unterbau von Opensuse Leap plötzlich den unangenehmen Nebeneffekt, dass man an älteren Kernelversionen kleben bleibt … Von SUSEs Seite müssen ggf. Back-Portierungen aus neuen Kernelversionen zu älteren Versionen vorgenommen werden. Das kann Nebeneffekte zeitigen (s.u.). Bin mal gespannt wie Opensuse mit diesem Thema in Zukunft umgehen will …

Wiederholte Modul-Einträge in der Datei “/etc/sysconfig/kernel”

Das erste Problem war, dass die Datei “/etc/sysconfig/kernel” nach dem Neustart mehrfache Einträge zum Laden von nvidia-Modulen enthielt. Woher immer das stammte; vielleicht hatte ich das ja schon früher von Experimenten mit Bumblebee drin. Vielleicht wurden die Einträge aber auch im Upgrade hinzugefügt. Jedenfalls mal checken, dass in dieser Datei nach dem Upgrade kein überflüssiger Unsinn drinsteht.

Bumblebee-Installation wieder zum Laufen bringen

Bumblebee lief nach dem Upgrade nicht mehr. Ok, dachte ich, also die für Leap 42.3 passenden Repositories aktivieren und diverse Bumblebee-Pakete aktualisieren. Es gibt jedoch mehrere Repositories mit Bumblebee-Paketen für Opensuse Leap, u.a.
http://download.opensuse.org/repositories/home:/Bumblebee-Project:/nvidia:/3xx.xx/OpenSUSE_Leap_42.3.
Unter Leap 42.1/42.2 hatte ich etliche Pakete aus diesen Repositories benutzt.

Für Leap 42.3 gilt (nach meiner Erfahrung): Zu nutzen ist
http://download.opensuse.org/repositories/X11:/Bumblebee/openSUSE_Leap_42.3
und sonst gar nichts! Auch nicht das Nvidia-Community-Repository!

Die im “X11:Bumblebee”-Repository vorhandenen Pakete – inklusive der Pakete mit dem proprietären Nvidia-Treiber – kann und sollte man dagegen (bis auf eines) installieren; das Paket “primus” habe ich mir allerdings aus dem 42.3-Update-Repository geholt.

Ergänzung 02.12.2017: Wichtige Ausnahme:
bbswitch sollte man nicht installieren. Es reicht bbswitch-kmp-default! Und nur letzteres hat bei mir funktioniert – und zwar ohne dkms-Service.

Die Installation von bbswitch aktiviert den “dkms”-Service; waren sowohl “bbswitch-kmp-default” und “bbswitch” installiert, so führte dies bei mir anhand von Statusanzeigen erkennbar zu einem wechselseitigen An- und Abschalten der Graka im Bootprozess; sie wird danach von den Treibern nicht mehr erkannt.

(Auf die anderen Repositories zu unterschiedlichen Nvidia-Treibern sollte man wirklich nur im Notfall zurückgreifen, und zwar dann, wenn ihr für eure Graka zwingend einen älteren Nvidia-Treiber benötigt; aber auch dann nur x11-video-nvidia installieren. Nicht dagegen das Paket “dkms-nvidia”!)

Zu beachten ist also auch folgender Hinweis: Falls ihr früher einen laufenden dkms-Service hattet: Unbedingt deaktivieren! Und zwar nach der Installation der Pakete, aber schon vor einem anschließenden Neustart des Systems.

systemctl disable dkms

Das steht im Gegensatz zu den Anweisungen in der Anleitung
https://de.opensuse.org/SDB:NVIDIA_Bumblebee
absolut notwendig! Zumindest auf meinem Laptop … Fragt mich bitte nicht, warum der dkms-Service zu Problemen führt.

Der Bumblebee-Dämon “bumblebeed” dagegen muss über den zuständigen Service aktiviert werden

systemctl enable bumblebeed

Zudem checken, dass der User, unter dem ihr mit einer grafischen Oberfläche arbeitet, Mitglied der Gruppen “video” und “bumblebee” ist. Ggf. mittels “usermod -G video,bumblebee USERNAME” korrigieren.

Dann Neustart des Systems. Die Kommandos

optirun glxspheres
vblank_mode=0 primusrun glxspheres
optirun -b none nvidia-settings -c :8

sollten danach alle einwandfrei funktionieren.

Sollte das nicht der Fall sein und immer noch eine Meldung kommen, dass die Graka nicht vorhanden sei und der “nvidia”-Treiber nicht geladen werden könne:

Alle Pakete aus dem Nvidia-(Community)-Repository (Treiber nvidia-gfx-GL04 und ähnliche), aus dem Nvidia-Bumblebee-Repository und dem oben angegebenen Standard-Bumblebee-Repository löschen. Danach nur die Pakete aus dem oben angegebenen Standard-Repository http://download.opensuse.org/repositories/X11:/Bumblebee/openSUSE_Leap_42.3
mit Ausnahme von bbswitch (!) installieren. Den dkms-Service dann prophylaktisch deaktivieren! Neustart.

Ein probeweiser Start des dkms-Service führt nach einem vorhergehenden Erfolg mit “primusrun” in jedem Fall wieder in die Katastrophe:

Danach kommen in Logfiles Fehlermeldungen, dass es kein passendes Grafik Device gäbe. Am Terminal erscheint: “Cannot access secondary GPU …”. Das ließ sich durch ein anschließendes normales Stoppen des dkms-Service nicht mehr beheben. Bumblebee funktionierte auch nach dem Stoppen des dkms-Service nicht mehr ordnungsgemäß; nvidia Module ließen sich selbst manuell nicht mehr laden. Da half nur ein Reboot – natürlich bei deaktiviertem dkms-Service.

Ich habe leider keine Zeit, der genauen Ursache auf den Grund zu gehen. Bei künftigen Änderungen des Kernels muss man ohne korrekt funktionierendes dkms ggf. halt ein Update für die nvidia- und bbswitch-Module aus dem Bumblebee-Repository erzwingen und damit (zumindest bzgl. nvidia) eine Neukompilation durchführen lassen. Interessant ist, dass für den bei mir nach dem Leap-Upgrade aktiven Kernel 4.4.92-31 ein Link von
/lib/modules/4.4.92-31-default/weak-updates/updatesbbswitch.ko -> /lib/modules/4.4.676-1-default/updates/bbswitch.ko
angelegt wurde. Der funktioniert offenbar. Irgendwas am Kernel 4.4.92 missfällt womöglich dkms beim Versuch, für den neueren Kernel das passende Modul zu definieren. Der 4.4.92-Kernel führt aufgrund von Rückportierungen, die die SuSE-Leute wohl vorgenommen haben, auch noch in anderem Kontext – nämlich bzgl. der VMware WS – zu Schwierigkeiten.

Probleme mit der VMware Workstation 12.5. unter Leap 42.3 beheben

Meine unter Leap 42.2 installierte VM WS 12.5.1 lief nach dem Leap-Upgrade nicht mehr. Auch ein Upgrade der Workstation-SW auf die aktuelle Version 12.5.8 endete beim ersten Startversuch mit Kompilierungsfehlern. Die konnte ich mir im Detail zwar ansehen; wie man aber die problematischen Stellen im Quellcode der VMware-Module beheben hätte müssen, lag jenseits meiner Kenntnisse und Fähigkeiten.

Hier half aber der Beitrag eines offenbar Kernel-Kundigen im VMware Community Forum:
https://communities.vmware.com/message/2693257#2693257
Dort suche man nach dem Beitrag von “hendrikw84“! Herzlichen Dank an diesen Herrn! Seine Vorgaben zur Korrektur diverser Codezeilen funktionieren nämlich einwandfrei. (Ursache der Probleme sind offenbar Rückwärtsportierungen von Features des Kernels 4.10 in den Code des Kernels 4.4. Was immer die SuSE-Leute dabei gedacht haben …)

[ Warum allerdings die eine vorgeschlagene Korrektur-Zeile

retval = retval = get_user_pages((unsigned long)uvAddr, numPages, 0, ppages, NULL);

nicht gleich zu

retval = get_user_pages((unsigned long)uvAddr, numPages, 0, ppages, NULL);

verkürzt werden kann, ist mir etwas schleierhaft. Typo? Die letzte Zeile für retval klappt für den Code von hostif.c unter vmmon-only/linux nämlich auch.]

Nach Durchführung der Korrekturen ließen sich die VMware-Codes jedenfalls anstandslos für Kernel “4.4.9-31-default” kompilieren – und die nötigen Kernelmodule wurden fehlerfrei erzeugt. Meine zwei lokalen (non shared) virtuellen Maschinen für Windows-Installationen liefen damit bislang einwandfrei.

Ob es – wie in der Diskussion im VMware Community Forum angedeutet, Probleme mit “shared VMs” auf Servern gibt, habe ich nicht getestet. Auf Servern verwende ich KVM-Installaionen mit spice oder X2GO.

Viel Spaß denn mit Opensuse 42.3 auf dem Laptop!

Fun with veth-devices, Linux bridges and VLANs in unnamed Linux network namespaces – VI

I continue my excursion into virtual networking based on network namespaces, veth devices, Linux bridges and virtual VLANs.

  1. Fun with veth-devices, Linux bridges and VLANs in unnamed Linux network namespaces – I
    [Commands to create and enter (unnamed) network namespaces via shell processes]
  2. Fun with …. – II [Suggested experiments for virtual networking between network namespaces/containers]
  3. Fun with … – III[Connecting network namespaces (or containers) by veth devices and virtual Linux bridges]
  4. Fun with … – IV[Virtual VLANs for network namespaces (or containers) and VLAN tagging at Linux bridge ports based on veth (sub-) interfaces]
  5. Fun with … – V[Creation of two virtual VLANs for 2 groups of network namespaces/containers by a Linux bridge]

Although we worked with Linux network namespaces only, the basic setups, commands and rules discussed so far are applicable for the network connection of (LXC) containers, too. Reason: Each container establishes (at least) its own network namespace – and the latter is where the container’s network devices operate. So, at its core a test of virtual networking between the containers means a test of networking between different network namespaces with appropriate (virtual) devices. We do not always require full fledged containers; often the creation of network namespaces with proper virtual Ethernet devices is sufficient to check the functionality of a virtual network and e.g. packet filter rules for its devices.

Virtual network connectivity (of containers) typically depends on veth devices and virtual bridges/switches. In this post we look at virtual VLANs spanning 2 bridges.

Our achievements so far

We know already the Linux commands required to create and enter simple (unnamed) network namespaces and give them individual hostnames. We connected these namespaces directly with veth devices and with the help of a virtual Linux bridge. But namespaces/containers can also be arranged in groups participating in a separate isolated network environment – a VLAN. We saw that the core setup of virtual VLANs can be achieved just by configuring virtual Linux bridges appropriately: We define one or multiple VLANs by assigning VIDs/PVIDs to Linux bridge ports. The VLAN is established inside the bridge by controlling packet transport between ports. Packet tagging outside a bridge is not required for the creation of simple coexisting VLANs.

However, the rules governing the corresponding packet tagging at bridge ports depend on the port type: We, therefore, listed up rules both for veth sub-interfaces and trunk interfaces attached to bridges – and, of course, for incoming and outgoing packets. The tagging rules discussed in post IV allow for different setups of more complex VLANs – sometimes there are several solutions with different advantages and disadvantages.

Our first example in the last post were two virtual VLANs defined by a Linux bridge. Can we extend this simple scenario such that the VLANs span several hosts and/or several bridges on the same host? Putting containers (and their network namespaces) into separate VLANs which integrate several hosts is no academic exercise: Even in small environments we may find situations, where containers have to be placed on different hosts with independent HW resources.

Simulating the connection of two hosts

In reality two hosts, each with its own Linux bridge for network namespaces (or containers), would be connected by real Ethernet cards, possibly with sub-interfaces, and a cable. Each Ethernet card (or their sub-interfaces) would be attached to the local bridge of each host. Veths give us the functionality of 2 Ethernet devices connected by a cable. In addition, one can split each veth interfaces into sub-interfaces (see the last post!). So we can simulate all kinds of host connections by bride connections on one and the same host. In our growing virtual test environment (see article 2) we construct the area encircled with the blue dotted line:

Different setups for the connection of two bridges

Actually, there are two different ways how to connect two virtual bridges: We can attach VLAN sensitive sub-interfaces of Ethernet devices to the bridges OR we can use the standard interfaces and build “trunk ports“.

Both variants work – the tagging of the Ethernet packets, however, occurs differently. The different ways of tagging become important in coming experiments with hosts belonging to 2 VLANs. (The differences, of course, also affect packet filter rules for the ports.) So, its instructive to cover both solutions.

Experiment 5.1 – Two virtual VLANs spanning two Linux bridges connected by (veth) Ethernet devices with sub-interfaces

We study the solution based on veth sub-interfaces first. Both virtual bridges shall establish two VLANs: “VLAN 1” (green) and “VLAN 2” (pink). Members of the green VLAN shall be able to communicate with each other, but not with members of the pink VLAN. And vice versa.

To enable such a solution our veth cable must transport packets tagged differently – namely according to their VLAN origin/destination. The following graphics displays the scenario in more detail:

PVID assignments to ports are indicated by dotted squares, VID assignments by squares with a solid border. Packets are symbolized by diamonds. The border color of the diamonds correspond to the tag color (VLAN ID).

Note that we also indicated some results of our tests of “experiment 4” in the last post:

At Linux bridge ports, which are based on sub-interfaces and which got a PVID assigned, any outside packet tags are irrelevant for the tagging inside the bridge. Inside the bridge a packet gets a tag according to the PVID of the port through which the packet enters the bridge!

If we accept this rule then we should be able to assign tags (VLAN IDs) to packets moving through the veth cable different from the tags used inside the bridges. Actually, we should even be able to use altogether different VIDs/PVIDs inside the second bridge, too, as long as we separate the namespace groups correctly. But let us start simple …

Creating the network namespaces, Linux bridges and the veth sub-interfaces

The following command list sets up the environment including two bridges brx (in netns3) and bry (in netns8). Scroll to see all commands and copy it to a root shell prompt …

unshare --net --uts /bin/bash &
export pid_netns1=$!
nsenter -t $pid_netns1 -u hostname netns1
unshare --net --uts /bin/bash &
export pid_netns2=$!
unshare --net --uts /bin/bash &
export pid_netns3=$!
unshare --net --uts /bin/bash &
export pid_netns4=$!
unshare --net --uts /bin/bash &
export pid_netns5=$!
unshare --net --uts /bin/bash &
export pid_netns6=$!
unshare --net --uts /bin/bash &
export pid_netns7=$!
unshare --net --uts /bin/bash &
export pid_netns8=$!

# assign different hostnames  
nsenter -t $pid_netns1 -u hostname netns1
nsenter -t $pid_netns2 -u hostname netns2
nsenter -t $pid_netns3 -u hostname netns3
nsenter -t $pid_netns4 -u hostname netns4
nsenter -t $pid_netns5 -u hostname netns5
nsenter -t $pid_netns6 -u hostname netns6
nsenter -t $pid_netns7 -u hostname netns7
nsenter -t $pid_netns8 -u hostname netns8

#set up veth devices in netns1 to netns4 with connection to netns3  
ip link add veth11 netns $pid_netns1 type veth peer name veth13 netns $pid_netns3    
ip link add veth22 netns $pid_netns2 type veth peer name veth23 netns $pid_netns3
ip link add veth44 netns $pid_netns4 type veth peer name veth43 netns $pid_netns3
ip link add veth55 netns $pid_netns5 type veth peer name veth53 netns $pid_netns3

#set up veth devices in netns6 and netns7 with connection to netns8   
ip link add veth66 netns $pid_netns6 type veth peer name veth68 netns $pid_netns8
ip link add veth77 netns $pid_netns7 type veth peer name veth78 netns $pid_netns8    

# Assign IP addresses and set the devices up 
nsenter -t $pid_netns1 -u -n /bin/bash
ip addr add 192.168.5.1/24 brd 192.168.5.255 dev veth11
ip link set veth11 up
ip link set lo up
exit
nsenter -t $pid_netns2 -u -n /bin/bash
ip addr add 192.168.5.2/24 brd 192.168.5.255 dev veth22
ip link set veth22 up
ip link set lo up
exit
nsenter -t $pid_netns4 -u -n /bin/bash
ip addr add 192.168.5.4/24 brd 192.168.5.255 dev veth44
ip link set veth44 up
ip link set lo up
exit
nsenter -t $pid_netns5 -u -n /bin/bash
ip addr add 192.168.5.5/24 brd 192.168.5.255 dev veth55
ip link set veth55 up
ip link set lo up
exit
nsenter -t $pid_netns6 -u -n /bin/bash
ip addr add 192.168.5.6/24 brd 192.168.5.255 dev veth66
ip link set veth66 up
ip link set lo up
exit
nsenter -t $pid_netns7 -u -n /bin/bash
ip addr add 192.168.5.7/24 brd 192.168.5.255 dev veth77
ip link set veth77 up
ip link set lo up
exit

# set up bridge brx and its ports 
nsenter -t $pid_netns3 -u -n /bin/bash
brctl addbr brx  
ip link set brx up
ip link set veth13 up
ip link set veth23 up
ip link set veth43 up
ip link set veth53 up
brctl addif brx veth13
brctl addif brx veth23
brctl addif brx veth43
brctl addif brx veth53
exit

# set up bridge bry and its ports 
nsenter -t $pid_netns8 -u -n /bin/bash
brctl addbr bry  
ip link set bry up
ip link set veth68 up
ip link set veth78 up
brctl addif bry veth68
brctl addif bry veth78
exit

Set up the VLANs

The following commands configure the VLANs by assigning PVIDs/VIDs to the bridge ports (see the last 2 posts for more information):

# set up 2 VLANs on each bridge 
nsenter -t $pid_netns3 -u -n /bin/bash
ip link set dev brx type bridge vlan_filtering 1   
bridge vlan add vid 10 pvid untagged dev veth13
bridge vlan add vid 10 pvid untagged dev 
veth23
bridge vlan add vid 20 pvid untagged dev veth43
bridge vlan add vid 20 pvid untagged dev veth53
bridge vlan del vid 1 dev brx self
bridge vlan del vid 1 dev veth13
bridge vlan del vid 1 dev veth23
bridge vlan del vid 1 dev veth43
bridge vlan del vid 1 dev veth53
bridge vlan show
exit
nsenter -t $pid_netns8 -u -n /bin/bash
ip link set dev bry type bridge vlan_filtering 1   
bridge vlan add vid 10 pvid untagged dev veth68
bridge vlan add vid 20 pvid untagged dev veth78
bridge vlan del vid 1 dev bry self
bridge vlan del vid 1 dev veth68
bridge vlan del vid 1 dev veth78
bridge vlan show
exit

We have a whole bunch of network namespaces now. Use “lsns” to get an overview. See the first 2 articles of the series, if you need an explanation of the commands used above and additional commands to get more information about the created namespaces and processes.

Note that we used VID 10, PVID 10 on the bridge ports to establish VLAN1 (green) and VID 20, PVID 20 to establish VLAN2 (pink). Note in addition that there is NO VLAN tagging required outside the bridges; thus the flag “untagged” to enforce Ethernet packets to leave the bridges untagged. Consistently, no sub-interfaces have been defined in the network namespace 1, 2, 4, 5, 6, 7. Note also, that we removed the PVID/VID = 1 default values from the ports.

The bridges are not connected, yet. Therefore, our next step is to create a connecting veth device with VLAN sub-interfaces – and to attach the sub-interfaces to the bridges :

# Create a veth device to connect the two bridges 
ip link add vethx netns $pid_netns3 type veth peer name vethy netns $pid_netns8    
nsenter -t $pid_netns3 -u -n /bin/bash
ip link add link vethx name vethx.50 type vlan id 50   
ip link add link vethx name vethx.60 type vlan id 60
brctl addif brx vethx.50
brctl addif brx vethx.60
ip link set vethx up
ip link set vethx.50 up
ip link set vethx.60 up
bridge vlan add vid 10 pvid untagged dev vethx.50
bridge vlan add vid 20 pvid untagged dev vethx.60
bridge vlan del vid 1 dev vethx.50
bridge vlan del vid 1 dev vethx.60
bridge vlan show
exit

nsenter -t $pid_netns8 -u -n /bin/bash
ip link add link vethy name vethy.50 type vlan id 50
ip link add link vethy name vethy.60 type vlan id 60
brctl addif bry vethy.50
brctl addif bry vethy.60
ip link set vethy up
ip link set vethy.50 up
ip link set vethy.60 up
bridge vlan add vid 10 pvid untagged dev vethy.50
bridge vlan add vid 20 pvid untagged dev vethy.60
bridge vlan del vid 1 dev vethy.50
bridge vlan del vid 1 dev vethy.60
bridge vlan show
exit

Note that we have used VLAN IDs 50 and 60 outside the bridge! Note also the VID/PVID settings and the flag “untagged” at our bridge ports vethx.50, vethx.60, vethy.50, vethy.60. The bridge internal tags of outgoing packets are first removed; afterwards the veth sub-interfaces re-tag outgoing packets automatically with tags for VLAN IDs 50,60.

However, we have kept up consistent tagging histories for packets propagating between the bridges and along the vethx/vethy line:

“10=>50=>10”

and

“20=>60=>20”

So, Ethernet packets nowhere cross the borders of our separated VLANs – if our theory works correctly.

Routing? 2 or 4 VLANs?

Routes for 192.168.5.0/24 were set up automatically in the network namespaces netns1, 2, 4, 5, 6, 7. You may check this by entering the namespaces with a shell (nsenter command) and using the command “route“.

Note that we have chosen all IP address to be in the same class. All our virtual devices work on the network link layer (L1/2 of the OSI model). Further IP routing across the bridges is not required on this level. The correct association of IP addresses and MAC addresses across the bridges and all VLANs is instead managed by the ARP protocol.

Our network namespaces should be able to get into contact – as long as they belong to the “same” VLAN.

Note: Each bridge sets up its own 2 VLANs; so, actually, we have built 4 VLANs!. But the bridges are connected in such a way that packet transport works across these 4 VLANs as if they were only two VLANs spanning the bridges.

Tests

We first test whether netns7 can communicate with e.g. netns5, which it should. On the other side netns7 should not be able to ping e.g. netns1. It is instructive to open several terminal windows from our original terminal (on KDE e.g. by “konsole &>/dev/null &”) and to enter different namespaces there to get an impression of what happens.

mytux:~ # nsenter -t $pid_netns7 -u -n /bin/bash
netns7:~ # ping 192.168.5.1 -c2
PING 192.168.5.1 (192.168.5.1) 56(84) bytes of data.
From 192.168.5.7 icmp_seq=1 Destination Host Unreachable
From 192.168.5.7 icmp_seq=2 Destination Host Unreachable

--- 192.168.5.1 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1008ms   
pipe 2
netns7:~ # ping 192.168.5.5 -c2
PING 192.168.5.5 (192.168.5.5) 56(84) bytes of data.
64 bytes from 192.168.5.5: icmp_seq=1 ttl=64 time=0.170 ms
64 bytes from 192.168.5.5: icmp_seq=2 ttl=64 time=0.087 ms

--- 192.168.5.5 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.087/0.128/0.170/0.043 ms
netns7:~ # 

And at the same time inside bry in netns8 :

mytux:~ # nsenter -t $pid_netns8 -u -n /bin/bash
netns8:~ # tcpdump -n -i bry  host 192.168.5.1 -e
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on bry, link-type EN10MB (Ethernet), capture size 262144 bytes
14:38:48.780367 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28   
14:38:49.778559 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28
14:38:50.778574 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28    
^C
3 packets captured
3 packets received by filter
0 packets dropped by kernel
netns8:~ # tcpdump -n -i bry  host 192.168.5.5 -e
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on bry, link-type EN10MB (Ethernet), capture size 262144 bytes
14:39:30.045117 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 192.168.5.5 tell 192.168.5.7, length 28
14:39:30.045184 2e:75:26:04:a9:70 > 8a:1e:62:e8:f3:c3, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Reply 192.168.5.5 is-at 2e:75:26:04:a9:70, length 28
14:39:30.045193 8a:1e:62:e8:f3:c3 > 2e:75:26:04:a9:70, ethertype 802.1Q (0x8100), length 102: vlan 20, p 0, ethertype IPv4, 192.168.5.7 > 192.168.5.5: ICMP echo request, id 21633, seq 1, length 64    
14:39:30.045247 2e:75:26:04:a9:70 > 8a:1e:62:e8:f3:c3, ethertype 802.1Q (0x8100), length 102: vlan 20, p 0, ethertype IPv4, 192.168.5.5 > 192.168.5.7: ICMP echo reply, id 21633, seq 1, length 64   
14:39:31.044106 8a:1e:62:e8:f3:c3 > 2e:75:26:04:a9:70, ethertype 802.1Q (0x8100), length 102: vlan 20, p 0, ethertype IPv4, 192.168.5.7 > 192.168.5.5: ICMP echo request, id 21633, seq 2, length 64   
14:39:31.044165 2e:75:26:04:a9:70 > 8a:1e:62:e8:f3:c3, ethertype 802.1Q (0x8100), length 102: vlan 20, p 0, ethertype IPv4, 192.168.5.5 > 192.168.5.7: ICMP echo reply, id 21633, seq 2, length 64  
14:39:35.058576 2e:75:26:04:a9:70 > 8a:1e:62:e8:f3:c3, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 192.168.5.7 tell 192.168.5.5, length 28
14:39:35.058587 8a:1e:62:e8:f3:c3 > 2e:75:26:04:a9:70, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Reply 192.168.5.7 is-at 8a:1e:62:e8:f3:c3, length 28
^C
8 packets captured
8 packets received by filter
0 packets dropped by kernel
netns8:~ # 

And parallel at vethx in netns3 :

mytux:~ # nsenter -t $pid_netns3 -u -n /bin/bash
netns3:~ # tcpdump -n -i vethx  host 192.168.5.1 -e
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vethx, link-type EN10MB (Ethernet), capture size 262144 bytes
14:38:48.780381 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 60, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28
14:38:49.778582 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 60, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28
14:38:50.778594 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 60, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28
^C
3 packets captured
3 packets received by filter
0 packets dropped by kernel
netns3:~ # tcpdump -n -i vethx  host 192.168.5.5 -e
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vethx, link-type EN10MB (Ethernet), capture size 262144 bytes
14:39:30.045131 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 60, p 0, ethertype ARP, Request who-has 192.168.5.5 tell 192.168.5.7, length 28
14:39:30.045182 2e:75:26:04:a9:70 > 8a:1e:62:e8:f3:c3, ethertype 802.1Q (0x8100), length 46: vlan 60, p 0, ethertype ARP, Reply 192.168.5.5 is-at 2e:75:26:04:a9:70, length 28
14:39:30.045210 8a:1e:62:e8:f3:c3 > 2e:75:26:04:a9:70, ethertype 802.1Q (0x8100), length 102: vlan 60, p 0, ethertype IPv4, 192.168.5.7 > 192.168.5.5: ICMP echo request, id 21633, seq 1, length 64   
14:39:30.045246 2e:75:26:04:a9:70 > 8a:1e:62:e8:f3:c3, ethertype 802.1Q (0x8100), length 102: vlan 60, p 0, ethertype IPv4, 192.168.5.5 > 192.168.5.7: ICMP echo reply, id 21633, seq 1, length 64
14:39:31.044123 8a:1e:62:e8:f3:c3 > 2e:75:26:04:a9:70, ethertype 802.1Q (0x8100), length 102: vlan 60, p 0, ethertype IPv4, 192.168.5.7 > 192.168.5.5: ICMP echo request, id 21633, seq 2, length 64    
14:39:31.044163 2e:75:26:04:a9:70 > 8a:1e:62:e8:f3:c3, ethertype 802.1Q (0x8100), length 102: vlan 60, p 0, ethertype IPv4, 192.168.5.5 > 192.168.5.7: ICMP echo reply, id 21633, seq 2, length 64   
14:39:35.058573 2e:75:26:04:a9:70 > 8a:1e:62:e8:f3:c3, ethertype 802.1Q (0x8100), length 46: vlan 60, p 0, ethertype ARP, Request who-has 192.168.5.7 tell 192.168.5.5, length 28
14:39:35.058589 8a:1e:62:e8:f3:c3 > 2e:75:26:04:a9:70, ethertype 802.1Q (0x8100), length 46: vlan 60, p 0, ethertype ARP, Reply 192.168.5.7 is-at 8a:1e:62:e8:f3:c3, length 28
^C
8 packets captured
8 packets received by filter
0 packets dropped by kernel
netns3:~ # 
 

How does netns7 see the world afterwards?

netns7:~ # ip a s
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
 
      valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: veth77@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000      
    link/ether 8a:1e:62:e8:f3:c3 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.5.7/24 brd 192.168.5.255 scope global veth77
       valid_lft forever preferred_lft forever
    inet6 fe80::881e:62ff:fee8:f3c3/64 scope link 
       valid_lft forever preferred_lft forever
netns7:~ # arp -a
? (192.168.5.1) at <incomplete> on veth77
? (192.168.5.5) at 2e:75:26:04:a9:70 [ether] on veth77    
netns7:~ #                 

We have a mirrored situation on netns6 with respect to netns1 and netns5. netns6 can reach netns1, but not netns5.

These results prove what we have claimed:

  • We have a separation of the VLANs across the bridges.
  • Inside the bridges only the ports’ PVID-settings determine the VLAN tag (here 20) of incoming packets.
  • Along the veth “cable” we have a completely different tag (here 60 for packets which originally got tag 20 inside bry).

Let us cross check for netns2:

mytux:~ # nsenter -t $pid_netns2 -u -n /bin/bash
netns2:~ # ping 192.168.5.7 -c2
PING 192.168.5.7 (192.168.5.7) 56(84) bytes of data.
From 192.168.5.2 icmp_seq=1 Destination Host Unreachable
From 192.168.5.2 icmp_seq=2 Destination Host Unreachable

--- 192.168.5.7 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 999ms
pipe 2
netns2:~ # ping 192.168.5.6 -c2
PING 192.168.5.6 (192.168.5.6) 56(84) bytes of data.
64 bytes from 192.168.5.6: icmp_seq=1 ttl=64 time=0.154 ms
64 bytes from 192.168.5.6: icmp_seq=2 ttl=64 time=0.092 ms

--- 192.168.5.6 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.092/0.123/0.154/0.031 ms
netns2:~ # 

And how do the bridges see the world?

In netns8 and netns3 we have a closer look at the bridges:

netns8:~ # ip a s
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: veth68: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master bry state UP group default qlen 1000
    link/ether 0a:5b:60:31:7a:bd brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::85b:60ff:fe31:7abd/64 scope link 
       valid_lft forever preferred_lft forever
3: veth78@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master bry state UP group default qlen 1000    
    link/ether 3e:f3:4b:26:02:46 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::3cf3:4bff:fe26:246/64 scope link 
       valid_lft forever preferred_lft forever
4: bry: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 0a:5b:60:31:7a:bd brd ff:ff:ff:ff:ff:ff
    inet6 fe80::30a5:8dff:fe54:987e/64 scope link 
       valid_lft forever preferred_lft forever
5: vethy@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 7a:86:31:14:57:2a brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::7886:31ff:fe14:572a/64 scope link 
       valid_lft forever preferred_lft forever
6: vethy.50@vethy: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master bry state UP group default qlen 1000   
    link/ether 7a:86:31:14:57:2a brd ff:ff:ff:ff:ff:ff
    inet6 fe80::7886:31ff:
fe14:572a/64 scope link 
       valid_lft forever preferred_lft forever
7: vethy.60@vethy: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master bry state UP group default qlen 1000  
    link/ether 7a:86:31:14:57:2a brd ff:ff:ff:ff:ff:ff
    inet6 fe80::7886:31ff:fe14:572a/64 scope link 
       valid_lft forever preferred_lft forever
netns8:~ # bridge vlan show
port    vlan ids
veth68   10 PVID Egress Untagged      
                                                                                                
veth78   20 PVID Egress Untagged                                        
                                                        
bry     None
vethy.50 10 PVID Egress Untagged

vethy.60 20 PVID Egress Untagged
netns8:~ # brctl showmacs bry 
port no mac addr                is local?       ageing timer   
  1     0a:5b:60:31:7a:bd       yes                0.00
  1     0a:5b:60:31:7a:bd       yes                0.00
  4     2e:75:26:04:a9:70       no                 3.62
  2     3e:f3:4b:26:02:46       yes                0.00
  2     3e:f3:4b:26:02:46       yes                0.00
  4     7a:86:31:14:57:2a       yes                0.00
  3     7a:86:31:14:57:2a       yes                0.00
  3     7a:86:31:14:57:2a       yes                0.00
  3     7a:86:31:14:57:2a       yes                0.00
  2     8a:1e:62:e8:f3:c3       no                 3.62

 

netns3:~ # ip a s
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: veth13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master brx state UP group default qlen 1000
    link/ether 52:9b:43:56:37:df brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::509b:43ff:fe56:37df/64 scope link 
       valid_lft forever preferred_lft forever
3: veth23@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master brx state UP group default qlen 1000   
    link/ether 06:81:88:12:5d:dc brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::481:88ff:fe12:5ddc/64 scope link 
       valid_lft forever preferred_lft forever
4: veth43@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master brx state UP group default qlen 1000   
    link/ether 56:d6:b2:80:9a:de brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::54d6:b2ff:fe80:9ade/64 scope link 
       valid_lft forever preferred_lft forever
5: veth53@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master brx state UP group default qlen 1000   
    link/ether 12:58:a6:73:6c:6e brd ff:ff:ff:ff:ff:ff link-netnsid 3
    inet6 fe80::1058:a6ff:fe73:6c6e/64 scope link 
       valid_lft forever preferred_lft forever
6: brx: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 06:81:88:12:5d:dc brd ff:ff:ff:ff:ff:ff
    inet6 fe80::8447:28ff:fe22:7a90/64 scope link 
       valid_lft forever preferred_lft forever
7: vethx@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether b6:e9:ef:3d:1c:b7 brd ff:ff:ff:ff:ff:ff link-netnsid 4
    inet6 fe80::b4e9:efff:fe3d:1cb7/64 scope link 
       valid_lft forever preferred_lft forever
8: vethx.50@vethx: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master brx state 
UP group default qlen 1000
    link/ether b6:e9:ef:3d:1c:b7 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::b4e9:efff:fe3d:1cb7/64 scope link 
       valid_lft forever preferred_lft forever
9: vethx.60@vethx: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master brx state UP group default qlen 1000   
    link/ether b6:e9:ef:3d:1c:b7 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::b4e9:efff:fe3d:1cb7/64 scope link 
       valid_lft forever preferred_lft forever
netns3:~ # bridge vlan show
port    vlan ids
veth13   10 PVID Egress Untagged

veth23   10 PVID Egress Untagged

veth43   20 PVID Egress Untagged

veth53   20 PVID Egress Untagged

brx     None       
vethx.50 10 PVID Egress Untagged   
                                                             
vethx.60 20 PVID Egress Untagged
netns3:~ # brctl showmacs brx
port no mac addr                is local?       ageing timer  
  2     06:81:88:12:5d:dc       yes                0.00
  2     06:81:88:12:5d:dc       yes                0.00
  4     12:58:a6:73:6c:6e       yes                0.00
  4     12:58:a6:73:6c:6e       yes                0.00
  4     2e:75:26:04:a9:70       no                 3.49
  1     52:9b:43:56:37:df       yes                0.00
  1     52:9b:43:56:37:df       yes                0.00
  3     56:d6:b2:80:9a:de       yes                0.00
  3     56:d6:b2:80:9a:de       yes                0.00
  6     8a:1e:62:e8:f3:c3       no                 3.49
  5     b6:e9:ef:3d:1c:b7       yes                0.00
  6     b6:e9:ef:3d:1c:b7       yes                0.00
  5     b6:e9:ef:3d:1c:b7       yes                0.00
  5     b6:e9:ef:3d:1c:b7       yes                0.00

And:

netns8:~ # brctl showmacs bry
port no mac addr                is local?       ageing timer    
  1     0a:5b:60:31:7a:bd       yes                0.00
  1     0a:5b:60:31:7a:bd       yes                0.00
  4     2e:75:26:04:a9:70       no                 7.37
  2     3e:f3:4b:26:02:46       yes                0.00
  2     3e:f3:4b:26:02:46       yes                0.00
  4     7a:86:31:14:57:2a       yes                0.00
  3     7a:86:31:14:57:2a       yes                0.00
  3     7a:86:31:14:57:2a       yes                0.00
  3     7a:86:31:14:57:2a       yes                0.00
  2     8a:1e:62:e8:f3:c3       no                 7.37
  3     96:e8:d1:2c:b8:ad       no                 3.84
  1     ce:48:c6:8c:ee:1a       no                 3.84
netns8:~ # 

 

netns3:~ # brctl showmacs brx
port no mac addr                is local?       ageing timer   
  2     06:81:88:12:5d:dc       yes                0.00
  2     06:81:88:12:5d:dc       yes                0.00
  4     12:58:a6:73:6c:6e       yes                0.00
  4     12:58:a6:73:6c:6e       yes                0.00
  4     2e:75:26:04:a9:70       no                12.48
  1     52:9b:43:56:37:df       yes                0.00
  1     52:9b:43:56:37:df       yes                0.00
  3     56:d6:b2:80:9a:de       yes                0.00
  3     56:d6:b2:80:9a:de       yes                0.00
  6     8a:1e:62:e8:f3:c3       no                12.48
  2     96:e8:d1:2c:b8:ad       no                 8.94
  5     b6:e9:ef:3d:1c:b7       yes                0.00
  6     b6:e9:ef:3d:1c:b7       yes                0.00
  5     b6:e9:ef:3d:1c:b7       yes                0.00
  5     b6:e9:ef:3d:1c:b7       yes                0.00
  5     ce:48:
c6:8c:ee:1a       no                 8.94
netns3:~ # 

Obviously, our bridges learn during pings …

Check of the independence of VLAN definitions on Bry

Just for fun: Let us change the PVID/VID setting on bry:

# Changing PVID/VID in bry 
nsenter -t $pid_netns8 -u -n /bin/bash
bridge vlan add vid 36 pvid untagged dev veth68
bridge vlan add vid 46 pvid untagged dev veth78
bridge vlan add vid 36 pvid untagged dev vethy.50   
bridge vlan add vid 46 pvid untagged dev vethy.60   
bridge vlan del vid 10 dev vethy.50
bridge vlan del vid 10 dev veth68
bridge vlan del vid 20 dev vethy.60
bridge vlan del vid 20 dev veth78
bridge vlan show
exit

This leads to:

netns8:~ # bridge vlan show
port    vlan ids
veth68   36 PVID Egress Untagged

veth78   46 PVID Egress Untagged

bry     None
vethy.50         36 PVID Egress Untagged    

vethy.60         46 Egress Untagged

But still:

netns2:~ # ping 192.168.5.7 -c2
PING 192.168.5.7 (192.168.5.7) 56(84) bytes of data.
From 192.168.5.2 icmp_seq=1 Destination Host Unreachable   
From 192.168.5.2 icmp_seq=2 Destination Host Unreachable

--- 192.168.5.7 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1009ms    
pipe 2
netns2:~ # ping 192.168.5.6 -c2
PING 192.168.5.6 (192.168.5.6) 56(84) bytes of data.
64 bytes from 192.168.5.6: icmp_seq=1 ttl=64 time=0.120 ms
64 bytes from 192.168.5.6: icmp_seq=2 ttl=64 time=0.094 ms

--- 192.168.5.6 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms   
rtt min/avg/max/mdev = 0.094/0.107/0.120/0.013 ms
netns2:~ # 

 

Experiment 5.2 – Two virtual VLANs spanning two Linux bridges connected by a veth based trunk line between trunk ports

Now let us look at another way of connecting the bridges. This time we use a real trunk connection without sub-interfaces. We then have to attach vethx directly to brx and vethy directly to bry. NO PVIDs must be used on the respective ports; however the flag “tagged” is required. And compared to the last settings in bry we have to go back to the PVID/VID values of 10, 20.

Our new connection model is displayed in the following graphics:

We need to change the present bridge and bridge port definitions accordingly. The commands, which you can enter at the prompt of your original terminal window are given below:

# Change vethx to trunk like interface in brx   
nsenter -t $pid_netns3 -u -n /bin/bash
brctl delif brx vethx.50
brctl delif brx vethx.60
ip link del dev vethx.50
ip link del dev vethx.60
brctl addif brx vethx  
bridge vlan add vid 10 tagged dev vethx   
bridge vlan add vid 20 tagged dev vethx
bridge vlan del vid 1 dev vethx
bridge vlan show
exit 

And

# Change vethy to trunk like interface in brx   
nsenter -t $pid_netns8 -u -n /bin/bash
brctl delif bry vethy.50
brctl delif bry vethy.60
ip link del dev vethy.50
ip link del dev vethy.60
brctl addif bry vethy
bridge vlan add vid 10 tagged dev vethy
bridge vlan add vid 20 tagged dev vethy
bridge vlan del vid 1 dev vethy
bridge vlan add vid 10 pvid untagged dev veth68  
bridge vlan add vid 20 pvid untagged dev veth78  
bridge vlan del vid 36 dev veth68
bridge vlan del vid 46 dev veth78
bridge vlan show
exit 

We get the following bridge/VLAN configurations:

netns8:~ # bridge vlan show            
           
port    vlan ids
veth68   10 PVID Egress Untagged   

veth78   20 PVID Egress Untagged

bry     None
vethy    10
         20

and

netns3:~ # bridge vlan show
port    vlan ids
veth13   10 PVID Egress Untagged    

veth23   10 PVID Egress Untagged

veth43   20 PVID Egress Untagged

veth53   20 PVID Egress Untagged

brx     None
vethx    10
         20

Testing 2 VLANs spanning two bridges/Hosts with a trunk connection

We test by pinging from netns7:

netns7:~ # ping 192.168.5.1 -c2
PING 192.168.5.1 (192.168.5.1) 56(84) bytes of data.
From 192.168.5.7 icmp_seq=1 Destination Host Unreachable    
From 192.168.5.7 icmp_seq=2 Destination Host Unreachable

--- 192.168.5.1 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 999ms     
pipe 2
netns7:~ # 

This gives at the bridge device bry in netns8:

netns8:~ # tcpdump -n -i bry  host 192.168.5.1 -e
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on bry, link-type EN10MB (Ethernet), capture size 262144 bytes
15:31:15.527528 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28   
15:31:16.526542 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28   
15:31:17.526576 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28   
^C
3 packets captured
3 packets received by filter
0 packets dropped by kernel
netns8:~ # 

At the outer side of vethx in netns3 we get :

netns3:~ # tcpdump -n -i vethx  host 192.168.5.1 -e
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vethx, link-type EN10MB (Ethernet), capture size 262144 bytes
15:31:15.527543 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28   
15:31:16.526561 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28   
15:31:17.526605 8a:1e:62:e8:f3:c3 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 192.168.5.1 tell 192.168.5.7, length 28   
^C
3 packets captured
3 packets received by filter
0 packets dropped by kernel
netns3:~ # 

You see, how the packet tags have changed now: Due to the missing PVIDs at the ports for vethx, vethy and the flag “tagged” we get packets on the vethx/vethy connection line, which carry the original 20 tag they had inside the bridges.

So :

netns7:~ # ping 192.168.5.5 -c2
PING 192.168.5.5 (192.168.5.5) 56(84) bytes of data.
64 bytes from 192.168.5.5: icmp_seq=1 ttl=64 time=0.042 ms    
64 bytes from 192.168.5.5: icmp_seq=2 ttl=64 time=0.092 ms

--- 192.168.5.5 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms   
rtt min/avg/max/mdev = 0.042/0.067/0.092/0.025 ms
netns7:~ # 

Obviously, we can connect our bridges with a trunk line between trunk ports, too.

Exactly 2 VLANs spanning 2 bridges with a trunk connection

Note that we MUST provide identical PVID/VID values inside the bridges bry and brx when we use a trunk like connection! VLAN filtering at all bridge ports works in both directions – IN and OUT. As the Ethernet packets keep their VLAN tags
when they leave or enter a bridge, we can not choose the VID/PVID values to be different in bry from brx. So, in contrast to the connection model with the sub-interfaces, we have no choices for PVID/VID assignments; we deal with exactly 2 and not 4 coupled VLANs.

Still, packets leave veth68, 78 and veth13, 23, 43, 53 untagged! The VLANs get established by the bridge and their connection line, alone.

Which connection model is preferable?

The connection model based on trunk port configurations looks simpler than the model based on veth sub-interfaces. However, the connection model based on sub-interfaces allows for much more flexibility and freedom! In addition, it may make it easier to define port related iptables filtering rules.

So, you have the choice how to extend (virtual) VLANs over several bridges/hosts.
Unfortunately, I have not yet tested for any performance differences.

VLANs spanning hosts with Linux bridges

Our test examples were tested on just one host. Is there any major difference when we instead look at 2 hosts, each with a virtual Linux bridge? Not, really. Our devices vethx and vethy would then be two real Ethernet cards like ethx and ethy. But you could make them slaves of the bridges, too, and you could split them into sub-interfaces.

So, our VLANs based on Linux bridge configurations would also work, if the bridges were located on different hosts. For both connection models …

Conclusion

Network namespaces or containers can become members of virtual VLANs. The configuration of bridge ports determines the VLAN setup. We can easily extend such (virtual) VLANs from one bridge to other bridges – even if the bridges are located on different hosts. In addition, we have the choice whether we base the connection on ports based on sub-interfaces or pure trunk ports. This gives us a maximum of flexibility.

But: Our VLANs were strictly separated so far. In reality, however, we may find situations in which a host/container must be member of two VLANs (VLAN1 and VLAN2). How do the veth connections from/to a network namespace look like, if a user in this intermediate network namespace shall be able to talk to all containers/namespaces in VLAN1 and VLAN2?

This is the topic of the next post.

Fun with veth-devices, Linux bridges and VLANs in unnamed Linux network namespaces – VII

Again, there will be 2 different solutions ….