QoS-orientierte Kommunikation über Ethernet für

Transcription

QoS-orientierte Kommunikation über Ethernet für
Fachhochschule Wiesbaden
Fachbereich Informatik
Diplomarbeit
zur Erlangung des akademischen Grades
Diplom-Informatiker (FH)
QoS-orientierte Kommunikation über
Ethernet für verteilte, Linux-basierte
Automatisierungsanwendungen
vorgelegt von: Marco Kosinski
am:
25.04.2005
Referent:
Korreferent:
Prof. Dr. Reinhold Kröger
Prof. Dr. Martin Gergeleit
II
Erklärung
Hiermit erkläre ich an Eides statt, daß ich die vorliegende Diplomarbeit selbständig
und nur unter Verwendung der angegebenen Hilfsmittel und Literaturquellen verfaßt
habe.
Wiesbaden, 25.04.2005
Marco Kosinski
Hiermit erkläre ich mein Einverständnis mit den im Folgenden aufgeführten Verarbeitungsformen dieser Diplomarbeit:
Verarbeitungsform
Einstellung der Arbeit in die
Bibliothek der FHW
Veröffentlichung des Titels
der Arbeit im Internet
Veröffentlichung der Arbeit
im Internet
Wiesbaden, 25.04.2005
ja
nein
√
√
√
Marco Kosinski
i
ii
Inhaltsverzeichnis
1 Einführung
1
2 Grundlagen
5
2.1
2.2
2.3
Quality of Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2.1.1
Klassifizierung . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
2.1.2
Paket Scheduling, Traffic Shaping und Policing . . . . . . . . . 10
2.1.2.1
Strict Priority Queueing . . . . . . . . . . . . . . . . 11
2.1.2.2
Weighted Round Robin Queueing . . . . . . . . . . . 12
2.1.2.3
Token Bucket Algorithmus . . . . . . . . . . . . . . . 13
Ethernet im Echtzeitbetrieb . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.1
Lastreduzierung . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.2
Time Devision Multiple Access . . . . . . . . . . . . . . . . . 15
2.2.3
Einsatz von Switches . . . . . . . . . . . . . . . . . . . . . . . 16
2.2.4
Fazit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Linux
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.3.1
Packet-Sockets . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.3.2
802.1Q VLAN Modul . . . . . . . . . . . . . . . . . . . . . . . 20
2.3.3
2.3.2.1
Aufbau und Funktionsweise . . . . . . . . . . . . . . 20
2.3.2.2
Konfiguration . . . . . . . . . . . . . . . . . . . . . . 21
Queueing Disziplinen . . . . . . . . . . . . . . . . . . . . . . . 24
2.3.3.1
Funktionsweise . . . . . . . . . . . . . . . . . . . . . 24
2.3.3.2
Aufbau . . . . . . . . . . . . . . . . . . . . . . . . . 26
iii
3 Analyse
3.1
3.2
3.3
3.4
29
Anforderungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.1.1
Anfordern von QoS . . . . . . . . . . . . . . . . . . . . . . . . 30
3.1.2
Steuern und Regeln . . . . . . . . . . . . . . . . . . . . . . . . 30
3.1.3
Alarm-Signalisierung . . . . . . . . . . . . . . . . . . . . . . . 31
3.1.4
Datei-Download / Upload . . . . . . . . . . . . . . . . . . . . 31
3.1.5
Human-Machine-Interface . . . . . . . . . . . . . . . . . . . . 31
3.1.6
Sonstige Anforderungen . . . . . . . . . . . . . . . . . . . . . 32
3.1.6.1
Entwicklung unter Linux . . . . . . . . . . . . . . . . 32
3.1.6.2
Portierbarkeit . . . . . . . . . . . . . . . . . . . . . . 33
3.1.6.3
Modularität . . . . . . . . . . . . . . . . . . . . . . . 33
3.1.6.4
Performanz-Optimierung auf Senden und Empfangen 33
Kommunikationsformen und ihre QoS-Anforderungen . . . . . . . . . 33
3.2.1
Steuern und Regeln . . . . . . . . . . . . . . . . . . . . . . . . 33
3.2.2
Alarm-Signalisierung . . . . . . . . . . . . . . . . . . . . . . . 34
3.2.3
Datei-Download / Upload . . . . . . . . . . . . . . . . . . . . 34
3.2.4
Human-Machine-Interface . . . . . . . . . . . . . . . . . . . . 35
Einflussnahme auf die QoS-Parameter . . . . . . . . . . . . . . . . . . 35
3.3.1
Service Availability . . . . . . . . . . . . . . . . . . . . . . . . 38
3.3.2
Packet Loss Rate . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.3.3
Delay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.3.3.1
Delay im Sendeknoten . . . . . . . . . . . . . . . . . 39
3.3.3.2
Delay auf dem Medium . . . . . . . . . . . . . . . . 42
3.3.3.3
Delay im Empfangsknoten . . . . . . . . . . . . . . . 43
3.3.4
Jitter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.3.5
Throughput . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
API der Linux-Queueing-Disziplinen . . . . . . . . . . . . . . . . . . 44
3.4.1
Kommunikation über Netlink-Sockets . . . . . . . . . . . . . . 44
3.4.2
Addressierung der Netlink-Messages . . . . . . . . . . . . . . . 45
3.4.3
Aufbau der Netlink-Messages . . . . . . . . . . . . . . . . . . 46
3.4.3.1
3.4.4
Traffic-Control-Messages . . . . . . . . . . . . . . . . 48
Verfügbare Queueing Disziplinen . . . . . . . . . . . . . . . . 50
iv
3.4.5
3.4.4.1
First-In-First-Out (bfifo, pfifo, pfifo fast) . . . . . . . 50
3.4.4.2
Stochastical Fair Queueing (sfq) . . . . . . . . . . . . 51
3.4.4.3
Prio (prio) . . . . . . . . . . . . . . . . . . . . . . . 52
3.4.4.4
Hierarchical Token Bucket (htb)
Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.4.5.1
3.5
. . . . . . . . . . . 52
Der U32-Filter . . . . . . . . . . . . . . . . . . . . . 57
Designentscheidungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.5.1
Statische Verkehrscharakteristik . . . . . . . . . . . . . . . . . 60
3.5.2
Linux ohne Echtzeiterweiterung . . . . . . . . . . . . . . . . . 60
3.5.3
Einsatz von Switches . . . . . . . . . . . . . . . . . . . . . . . 60
4 Konzept
61
4.1
Grobentwurf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
4.2
Die Konfiguration (chConfRead) . . . . . . . . . . . . . . . . . . . . . 64
4.3
Die Bibliotheksschnittstelle (chContr) . . . . . . . . . . . . . . . . . . 66
4.4
Der Kanalendpunkt (chDescr) . . . . . . . . . . . . . . . . . . . . . . 72
4.5
Prozesszugriffsverwaltung (chAvailContr/
chAvail) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.6
Netzwerk-Device (chDev) . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.7
QoS-Controller (chQoSContr) . . . . . . . . . . . . . . . . . . . . . . 78
5 Implementierung
85
5.1
Implementierungsumgebung . . . . . . . . . . . . . . . . . . . . . . . 86
5.2
chConfRead . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
5.3
chContr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
5.4
chDescr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5.5
chAvailContr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
5.6
chDev . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
5.7
chQoSContr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5.8
Testapplikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
5.9
Gesamtaufwand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
5.10 Kompilierung und Installation . . . . . . . . . . . . . . . . . . . . . . 104
5.11 Aufgetretene Probleme . . . . . . . . . . . . . . . . . . . . . . . . . . 105
v
6 Bewertung
107
6.1
Messumgebung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
6.2
Messgrößen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
6.3
Instrumentierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
6.3.1
Ende-zu-Ende Propagation . . . . . . . . . . . . . . . . . . . . 108
6.3.2
Delay durch sendto-Systemcall und QDisc . . . . . . . . . . . 108
6.4
Lastmodell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
6.5
Lastquelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
6.6
Messergebnisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
6.7
Fazit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
7 Zusammenfassung und Ausblick
117
8 Literaturverzeichnis
119
A Prioritätentabelle
123
B Diagramme
125
B.1 HTB/Prio QDisc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
B.2 HTB/Prio End-to-End . . . . . . . . . . . . . . . . . . . . . . . . . . 127
B.3 Prio QDisc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
B.4 Prio End-to-End . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
B.5 FIFO QDisc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
B.6 FIFO End-to-End . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
B.7 HTB/Prio QDisc variierender Burst-Parameter
. . . . . . . . . . . . 135
B.8 Ein Prio 1 Kanal ohne Störlast . . . . . . . . . . . . . . . . . . . . . 136
B.9 Ein Prio 1 Kanal mit Störlast . . . . . . . . . . . . . . . . . . . . . . 137
B.10 Ein Prio 7 Kanal ohne Störlast . . . . . . . . . . . . . . . . . . . . . 138
B.11 Ein Prio 7 Kanal mit Störlast . . . . . . . . . . . . . . . . . . . . . . 139
C Inhalt der CD
141
vi
Abbildungsverzeichnis
2.1
IEEE 802.1Q VLAN Tag . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.2
Beispiel: Strict Priority Queueing . . . . . . . . . . . . . . . . . . . . 11
2.3
Beispiel: Weighted Round Robin Queueing . . . . . . . . . . . . . . . 12
2.4
Beispiel: Token Bucket Algorithmus . . . . . . . . . . . . . . . . . . . 14
2.5
Aufbau eines Switch . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.6
Aufbau der VLAN-Devices . . . . . . . . . . . . . . . . . . . . . . . . 20
2.7
Funktionsweise von Queueing Disziplinen . . . . . . . . . . . . . . . . 25
2.8
Aufbau von Queueing Disziplinen . . . . . . . . . . . . . . . . . . . . 27
3.1
Use-Case Diagramm . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.2
Service- und Ankunftskurve . . . . . . . . . . . . . . . . . . . . . . . 37
3.3
Netlink-Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.4
Traffic-Control-Message . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.5
Attribute einer Traffic-Control-Message . . . . . . . . . . . . . . . . . 50
4.1
Konzeptionelles Klassenmodell . . . . . . . . . . . . . . . . . . . . . . 62
4.2
Übersicht Klassendiagramm . . . . . . . . . . . . . . . . . . . . . . . 64
4.3
Übersicht Klassendiagramm . . . . . . . . . . . . . . . . . . . . . . . 65
4.4
Kollaborationsdiagramm zu initChannels() . . . . . . . . . . . . . . 67
4.5
Kollaborationsdiagramm zu closeChannels() . . . . . . . . . . . . . . 68
4.6
Kollaborationsdiagramm zu chOpen() . . . . . . . . . . . . . . . . . . 69
4.7
Kollaborationsdiagramm zu chClose() . . . . . . . . . . . . . . . . . 70
4.8
Kollaborationsdiagramm zu chOpen() . . . . . . . . . . . . . . . . . . 71
4.9
Kollaborationsdiagramm zu chRecv() . . . . . . . . . . . . . . . . . . 72
4.10 chDesrc-Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4.11 Konzept für den gepufferten Empfang . . . . . . . . . . . . . . . . . . 74
vii
4.12 chAvailContr- und chAvail-Klasse . . . . . . . . . . . . . . . . . . . . 75
4.13 registerChannel-Methode . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.14 Die chDev-Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.15 Die chQoSContr-Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . 78
4.16 Basis-QDisc-Konfiguration . . . . . . . . . . . . . . . . . . . . . . . . 80
4.17 Best-Effort-QDisc-Konfiguration . . . . . . . . . . . . . . . . . . . . . 81
4.18 QDisc-Konfiguration für Kanäle . . . . . . . . . . . . . . . . . . . . . 82
5.1
Semaphore für Prozess- und Threadsynchronisation . . . . . . . . . . 89
5.2
Speichermodell für chDescr-Objekte . . . . . . . . . . . . . . . . . . . 90
B.1 QDisc 200Byte HTB/Prio . . . . . . . . . . . . . . . . . . . . . . . . 125
B.2 QDisc 500Byte HTB/Prio . . . . . . . . . . . . . . . . . . . . . . . . 126
B.3 QDisc 1496Byte HTB/Prio . . . . . . . . . . . . . . . . . . . . . . . . 126
B.4 End-to-End 200Byte HTB/Prio . . . . . . . . . . . . . . . . . . . . . 127
B.5 End-to-End 500Byte HTB/Prio . . . . . . . . . . . . . . . . . . . . . 128
B.6 End-to-End 1496Byte HTB/Prio . . . . . . . . . . . . . . . . . . . . 128
B.7 QDisc 200Byte Prio . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
B.8 QDisc 500Byte Prio . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
B.9 QDisc 1496Byte Prio . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
B.10 End-to-End 200Byte Prio . . . . . . . . . . . . . . . . . . . . . . . . 130
B.11 End-to-End 500Byte Prio . . . . . . . . . . . . . . . . . . . . . . . . 131
B.12 End-to-End 1496Byte Prio . . . . . . . . . . . . . . . . . . . . . . . . 131
B.13 QDisc 200Byte FIFO . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
B.14 QDisc 500Byte FIFO . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
B.15 QDisc 1496Byte FIFO . . . . . . . . . . . . . . . . . . . . . . . . . . 133
B.16 End-to-End 200Byte FIFO . . . . . . . . . . . . . . . . . . . . . . . . 133
B.17 End-to-End 500Byte FIFO . . . . . . . . . . . . . . . . . . . . . . . . 134
B.18 End-to-End 1496Byte FIFO . . . . . . . . . . . . . . . . . . . . . . . 134
B.19 QDisc 500Byte HTB/Prio cburst+1000 . . . . . . . . . . . . . . . . . 135
B.20 QDisc 500Byte HTB/Prio Minburst-1000 . . . . . . . . . . . . . . . . 135
B.21 QDisc 500Byte HTB/Prio Minburst-500 . . . . . . . . . . . . . . . . 136
B.22 QDisc Kanal Prio 1 ohne Störlast . . . . . . . . . . . . . . . . . . . . 136
viii
B.23 End-to-End Kanal Prio 1 ohne Störlast . . . . . . . . . . . . . . . . . 137
B.24 QDisc Kanal Prio 1 mit Störlast . . . . . . . . . . . . . . . . . . . . . 137
B.25 End-to-End Kanal Prio 1 mit Störlast . . . . . . . . . . . . . . . . . . 138
B.26 QDisc Kanal Prio 7 ohne Störlast . . . . . . . . . . . . . . . . . . . . 138
B.27 End-to-End Kanal Prio 7 ohne Störlast . . . . . . . . . . . . . . . . . 139
B.28 QDisc Kanal Prio 7 mit Störlast . . . . . . . . . . . . . . . . . . . . . 139
B.29 End-to-End Kanal Prio 7 ohne Störlast . . . . . . . . . . . . . . . . . 140
ix
x
Tabellenverzeichnis
2.1
Integrated Services Klassen . . . . . . . . . . . . . . . . . . . . . . .
7
2.2
Service Klassen im Automatisierungskontext . . . . . . . . . . . . . .
7
2.3
Abbildung der User-Priority-Werte auf Traffic-Klassen
2.4
Zuteilung der Traffic Klassen pro Anzahl der Ausgangsqueues . . . . 17
2.5
VLAN ioctl Kommandos . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.6
Namensgebung des VLAN Device . . . . . . . . . . . . . . . . . . . . 24
3.1
RTNetlink-Kommandos . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.2
Flags für Netlink-Messages . . . . . . . . . . . . . . . . . . . . . . . . 47
3.3
Flags für Netlink-Messages (forts.) . . . . . . . . . . . . . . . . . . . 48
5.1
Implementierungsaufwand chConfRead . . . . . . . . . . . . . . . . . 87
5.2
Implementierungsaufwand chContr . . . . . . . . . . . . . . . . . . . 92
5.3
Implementierungsaufwand chDescr . . . . . . . . . . . . . . . . . . . 94
5.4
Implementierungsaufwand chAvailContr . . . . . . . . . . . . . . . . 95
5.5
Implementierungsaufwand chDev . . . . . . . . . . . . . . . . . . . . 96
5.6
Implementierungsaufwand chQoSContr . . . . . . . . . . . . . . . . . 102
5.7
Implementierungsaufwand Testapplikation . . . . . . . . . . . . . . . 103
5.8
Implementierungsaufwand chQoSContr . . . . . . . . . . . . . . . . . 104
6.1
Implementierungsaufwand Instrumentierung . . . . . . . . . . . . . . 111
6.2
Lastkonfigurationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
6.3
Genutzte Bandbreite der Lastkonfigurationen . . . . . . . . . . . . . 112
6.4
Maximaler Delay der Kanäle in der Queueing Disziplin . . . . . . . . 112
6.5
Mittlerer Delay für Prio/HTB-Konfiguration . . . . . . . . . . . . . . 114
6.6
Maximaler Delay für Prio/HTB-Konfiguration . . . . . . . . . . . . . 114
6.7
Mittlerer Delay für Prio-Konfiguration . . . . . . . . . . . . . . . . . 114
xi
. . . . . . . . 10
6.8
Maximaler Delay für Prio-Konfiguration . . . . . . . . . . . . . . . . 114
6.9
Mittlerer Delay für FIFO-Konfiguration . . . . . . . . . . . . . . . . . 114
6.10 Maximaler Delay für FIFO-Konfiguration . . . . . . . . . . . . . . . . 115
A.1 Übersicht über alle prioritätsbezogenen Werte . . . . . . . . . . . . . 123
xii
Verzeichnis der Quelltexte
2.1
Der socket()-Systemcall für Packet-Sockets . . . . . . . . . . . . . . 19
2.2
Der ioctl()-Systemcall . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3
Die vlan_ioctl_args Struktur . . . . . . . . . . . . . . . . . . . . . . 22
3.1
Erforderliche Header Dateien für Netlink-Kommunikation . . . . . . . 44
3.2
Die msghdr Struktur . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.3
Die iovec Struktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.4
Die sockaddr_nl Struktur . . . . . . . . . . . . . . . . . . . . . . . . 45
3.5
Die nlmsghdr Struktur . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.6
Die tcmsg Struktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.7
Die tc_sfq_qopt Struktur . . . . . . . . . . . . . . . . . . . . . . . . 51
3.8
Die tc_prio_qopt Struktur . . . . . . . . . . . . . . . . . . . . . . . . 52
3.9
Die tc_htb_glob Struktur . . . . . . . . . . . . . . . . . . . . . . . . 54
3.10 Die tc_ratespec Struktur . . . . . . . . . . . . . . . . . . . . . . . . 55
3.11 Die tc_htb_opt Struktur . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.12 Die tc_u32_sel Struktur . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.13 Die tc_u32_key Struktur . . . . . . . . . . . . . . . . . . . . . . . . . 59
4.1
Document Type Definition der Konfigurationsdatei . . . . . . . . . . 64
5.1
Fehlerrückgabewerte . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
5.2
Zuweisung der Kommunikationmethoden . . . . . . . . . . . . . . . . 88
5.3
Setzen der Socket-Priotität . . . . . . . . . . . . . . . . . . . . . . . . 89
5.4
Makros zur Umrechnung der Indizes in chContain . . . . . . . . . . . 91
5.5
Stufenweises Allokieren in chContain . . . . . . . . . . . . . . . . . . 91
5.6
Die chDescr-Struktur . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5.7
Suchschleife in chAvailContr . . . . . . . . . . . . . . . . . . . . . . . 94
5.8
Abruf der Shm-Statistiken . . . . . . . . . . . . . . . . . . . . . . . . 94
xiii
5.9
Filter-Selector für Prio-QDisc . . . . . . . . . . . . . . . . . . . . . . 97
5.10 Hinzufügen der Prio-QDisc . . . . . . . . . . . . . . . . . . . . . . . . 98
5.11 User-Priority auf Prio-QDisc Mapping . . . . . . . . . . . . . . . . . 98
5.12 Basis-QDiscs und Filter . . . . . . . . . . . . . . . . . . . . . . . . . 98
5.13 Hinzufügen der Best-Effort-Klasse . . . . . . . . . . . . . . . . . . . . 99
5.14 Setzen der QDisc-Basis-Parameter . . . . . . . . . . . . . . . . . . . . 100
5.15 Generieren der Netlink-Message . . . . . . . . . . . . . . . . . . . . . 100
5.16 Versenden der Netlink-Message . . . . . . . . . . . . . . . . . . . . . 101
5.17 Hinzufügen von Attributen . . . . . . . . . . . . . . . . . . . . . . . . 101
5.18 Generieren einer Netlink-Message für eine HTB-Klasse . . . . . . . . 101
6.1
Die msrFrm-Struktur . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
6.2
testModeSend()-Funktion . . . . . . . . . . . . . . . . . . . . . . . . . 109
6.3
Instrumentierung an der enqueue()-Funktion . . . . . . . . . . . . . . 110
xiv
Kapitel 1
Einführung
Mit Beginn der Industrialisierung versuchte der Mensch immer mehr Arbeitsabläufe
(Prozesse) zu automatisieren. Dies geschah zunächst nur durch Einsatz rein mechanischer Mittel.
Mit der Entwicklung der Transistortechnik hielten Computer Einzug in die Industrie. Mit den Rechnern war es möglich an industriellen Fertigungsanlagen sowohl
Zustände zu erfassen, als auch deren Verhalten zu steuern und zu regeln. Prozessund Steuerwerte wurden mittels analoger Spannungs- oder Stromwerte übertragen.
Der baldige Anstieg in der Komplexität der Anlagen forderte die Entwicklung von
dezentraler Peripherie, die über eine gewisse Eigenintelligenz verfügte. Über eine
Anlage verteilte Sensoren und Aktoren gaben Prozesswerte nicht mehr nur als analoge Signale weiter, sondern übermittelten diese digitalisiert. Dies ebnete den Weg
zum Austausch von Sensor- und Steuerdaten, sowie Statusmeldungen und Diagnoseinformationen.
Um diese Art der Kommunikation zu ermöglichen, wurden Bussysteme entwickelt.
Sie waren echtzeitfähig, was heißt, dass für alle Daten, die über den Bus gesendet
wurden, garantiert wurde, dass sie nach einer maximalen Verzögerungszeit an ihrem
Ziel eintreffen [Kop97]. Über die typischen Zweidrahtleitungen der Feldbusse findet
immer eine Master-Slave-Kommunikation statt, bei der das Automationssystem zyklisch alle Slave-Komponenten (Peripherie) nach Daten abfragt (Polling) und an sie
gerichtete Daten sendet.
Heute existieren über 50 verschiedene Feldbusssysteme.
Durch den weiter stetigen Komplexitätsanstieg der Industrianlagen, genügte bald ein
zentraler Rechner zu deren Steuerung nicht mehr. Die Verteilung der Steuerungs-
1
Kapitel 1. Einführung
aufgaben auf mehrere Rechner war eine eindeutige Konsequenz. Dadurch konnten
wiederum kleinere, kostengünstigere, spezialisierte Microcontroller eingesetzt werden, was die Wartung der Anlagen günstiger machte, da einzelne Komponenten
ausgetauscht werden konnten. Dadurch erhöhte sich weiterhin die Komplexität in
der Kommunikation, da gleichberechtigte Steuereinheiten Daten miteinander austauschen mussten. Eine reine Master-Slave-Architektur war nun nicht mehr anwendbar;
es musste eine Master-zu-Master-Kommunikation ermöglicht werden.
Die vertikale Integration macht Mechanismen erforderlich, die sicher stellen, dass
echtzeitkritischer Datenverkehr mit Protokollen wie FTP oder HTTP störungsfrei
koexistieren. Weiterhin hat dies höhere Anforderungen an die zur Verfügung stehende Bandbreite zur Folge, denen die auf kleine Datenmengen optimierten Feldbusse
nicht gewachsen sind [Jas02].
Als eine Alternative zu Feldbussen dafür hat sich Ethernet herauskristallisiert. Es
bietet günstige, standardisierte Hardware mit hoher Geschwindigkeit, einfache Verkabelung und die Nutzung standardisierter Protokolle zur vertikalen Integration.
Doch da Ethernet nicht für die Automatisierungsumgebung entwickelt wurde, lässt
es sich dort nicht ohne Anpassungen integrieren.
Es sind einige, zum Teil sehr erfolgreiche, proprietäre Lösungen entwickelt worden,
die die Integration von Ethernet ermöglichen, wie z.B. PROFINET [eH]. Jedoch sind
offene Lösungen, welche heute auch immer mehr im Office und Home-Computing
Bereich Einzug halten, bisher die Ausnahme.
Als ein offenes Betriebssystem bietet Linux die Möglichkeit, mit ihm eine offene
Lösung für die Problematik, die Ethernet im Automatisierungskontext stellt, zu
entwickeln. Linux ist kostengünstig und bietet große Flexibilität, da es durch Modularität den jeweiligen Anforderungen einer Automationsanlage angepasst werden
kann.
Diese Arbeit ist eingebettet in das Forschungsprojekt ”Real-Time Data Propagation in Distributed Environments”, des Labors für verteilte System der FH Wiesbaden. Dieses sieht eine mehrschichtige Architektur vor, deren unterste Schicht eine
Quality-of-Service-orientierte Kommunikation über Ethernet herstellen soll, basierend auf den von Linux gebotenen Möglichkeiten. Ziel dieser Arbeit ist es diese
Kommunikationsschicht zu entwickeln, unter Berücksichtigung der Anforderungen,
die eine Automatisierungsumgebung an diese stellt.
In Kapitel 2 werden die Grundlagen erläutert, die zum Verständnis des Themas notwendig sind. Abschnitt 2.1 beschreibt was unter Quality of Service zu verstehen ist
2
Kapitel 1. Einführung
und gibt einen Überblick über die in diesem Kontext eingesetzten Mechanismen. In
Abschnitt 2.2 werden Aspekte von Ethernet betrachtet, die der Erlangung von Echtzeitfähigkeit im Wege stehen. Dabei wird ein Überblick über die bisher eingesetzten
Lösungen zur Beseitigung dieser Aspekte gegeben. Abschnitt 2.3 erklärt die Implementierung der in Abschnitt2.1 erläuterten Mechanismen im Linux Kernel. Hierbei
werden die Funktionsweise und Programmierschnittstelle zu den jeweiligen Modulen
aufgezeigt.
In Kapitel 3 werden die Anforderungen und Randbedingungen analysiert, die sich
aus der Automationsumgebung ergeben. Abschnitt 3.1 geht auf die Anforderungen
verschiedener Anwendugsfälle ein, die in der verteilten Automation auftreten. In
Abschnitt 3.2 werden die einzelnen Kommunikationsformen in Bezug zu deren Anforderungen an QoS-Parameter beleuchtet. Wie diese Parameter beeinflusst werden
können wird in Abschnitt 3.3 analysiert. Die Analyse der in der Arbeit zu verwendenden Queueing-Disziplinen wird in 3.4 vorgenommen. Zuletzt werden einige
Designentscheidungen getroffen, die in Abschnitt 3.5 beschrieben werden.
In Kapitel 4 wird ein Software-Design zur Lösung der Problemstellung konzipiert.
In Abschnitt 4.1 wird zunächst ein Grobkonzept vorgestellt, das in den Abschnitten
4.2 bis 4.7 für jedes Subsystem verfeinert wird.
Kapitel 5 zeigt, wie das in Kapitel 4 erstellte Konzept in die Implementierung umgesetzt wurde. Abschnitt 5.1 beschreibt kurz die Entwicklungsumgebung und die
Hilfsmittel, die zur Erstellung der Software genutzt wurde. Die Abschnitte 5.2 bis
5.7 gehen näher auf die Implementierungsaspekte der einzelnen Module ein. In Abschnitt 5.8 wird eine Applikation beschrieben, die zum Testen der Grundfunktionen
der Implementierung genutzt werden kann. Der Abschnitt 5.10 erklärt die Kompilierung und Installation der implementierten Software. In Abschnitt 5.11 werden
Probleme behandelt, die im Laufe der Implementierung aufgetreten sind.
In Kapitel 6 wird eine Bewertung der Implementierung anhand von Messungen
durchgeführt. Abschnitt 6.1 beschreibt die Rechner- und Switchkonfiguration in der
gemessen wurde. Abschnitt 6.2 geht auf die einzelnen Messgrößen ein. Die vorgenommene Instrumentierung wird in Abschnitt 6.3 beschrieben. Abschnitt 6.4 stellt
das Lastmodell vor, dessen Implementierung in Abschnitt 6.5 beschrieben wird. In
Abschnitt 6.6 werden die besprochen und dazu in 6.7 ein Fazit dazu gegeben.
Die Arbeit wird Kapitel 7 zusammengefasst und es wird ein Ausblick mögliche Weiterentwicklungen gegeben.
3
Kapitel 1. Einführung
4
Kapitel 2
Grundlagen
2.1
Quality of Service
Der Begriff Quality of Service, oder Dienstqualität [Tan02] ist in der Fachwelt nicht
klar definiert [Jas02]. Ursprünglich stammt er aus der Multimediakommunikation.
Bei der Übertragung von Video- oder Audiosignalen über ein Datennetzwerk treten
gewöhnlich Verzögerungen auf. Überschreiten diese Verzögerungen einen bestimmten Grenzwert, so sind Verluste in der Qualität des Signals deutlich erkennbar. Um
dies zu vermeiden und damit die Qualität des Services zu gewährleisten, wurden
diverse Mechanismen entworfen, die unter dem Begriff Quality of Service (QoS) zusammengefasst wurden. Heute weitet sich deren Anwendung auf verschiedene andere
Gebiete aus, unter anderem auf die Industrieautomation, wo sie eingesetzt werden,
um harte Echtzeitanforderungen durchzusetzen.
Der QoS-Begriff wird durch eine Reihe von Parametern bestimmt, die Einfluss auf
die Qualität eines Dienstes haben. Mit ihnen können Anforderungen beschrieben
werden, die ein Dienst stellt, um die benötigte Qualität aufrecht zu erhalten. Die
Parameter sind nach [Fur03]:
Service Availability (Dienstverfügbarkeit) Service Availability beschreibt die
Zeit, die ein Service in einem Netzwerk zur Verfügung steht. Diese wird als
Prozentsatz der Zeit angegeben, die ein Service innerhalb der Gesamtzeit verfügbar ist.
Paket Loss Rate (Paketverlustrate) Fällt an einem Netzwerkknoten mehr Datenverkehr an als verarbeitet werden kann, so müssen unter Umständen Pakete
5
2.1. Quality of Service
Kapitel 2. Grundlagen
verworfen werden. Die Paketverlustrate gibt den prozentualen Anteil der Pakete an, die auf dem Weg durch das Netzwerk verloren gehen.
Delay, Latency (Latenz) Der Delay ist die Propagationszeit zwischen dem Senden und Empfangen eines Pakets. Der Delay eines Pakets bewegt sich immer
zwischen einem Worst-Case-Delay und einem Best-Case-Delay. Er besteht aus
einem konstanten und einem variablen Teil. Der konstante Teil setzt sich aus
der Verarbeitung der Daten durch die Hardware und der Signallaufzeiten in
den Kabeln zusammen. Der variable Teil entsteht durch die Verzögerungen und
Wartezeiten in den Betriebssystemen, Treibern und Firmware jedes passierten
Netzwerkknotens.
Jitter Werden Pakete in festen Zeitintervallen (isochron) gesendet, so kommt es
beim Empfänger durch Unregelmäßigkeiten in der Latenz zu einer Varianz in
den Intervallen. Der Jitter beschreibt diese Varianz im Delay in Form einer
vorzeichenbehafteten Variablen, deren Wert negativ ist, wenn ein Paket früher
als erwartet eintrifft und positiv, wenn es später eintrifft.
Troughput(Durchsatz) Throughput beschreibt den Datendurchsatz im Netz, gemessen in Bytes oder Paketen pro Sekunde.
Um QoS in einem Netzwerk durchsetzen zu können, müssen zwei Anforderungen
erfüllt sein: Die Pakete, die ein QoS-orientiertes Netzwerk passieren, müssen klassifizierbar sein. Jeder Netzwerkknoten, den ein klassifiziertes Paket passiert, muss in
der Lage sein, das Paket entsprechend seiner Klassifizierung zu verarbeiten.
2.1.1
Klassifizierung
Um Pakete klassifizieren zu können, müssen zunächst verschiedene Klassen definiert
werden. In RFC 1633 werden drei Dienstklassen vorgeschlagen, die in Tabelle 2.1
erläutert werden: Guaranteed Service, Predictive Service und Best-Effort-Service.
6
Kapitel 2. Grundlagen
2.1. Quality of Service
Dienstklasse Eigenschaften
Guaranteed
Pakete werden innerhalb einer festgelegten Verzögerungszeit ausgeliefert. Um den Jitter zu minimieren können Pakete, die zu früh
eintreffen, beim Empfänger gepuffert werden.
Predictive
Pakete dieser Klasse haben keine festgelegten maximalen Verzögerungszeiten, dennoch werden sie bevorzugt behandelt um ihre
Ankunftszeit grob vorhersagbar zu halten. Ihr Verhalten sollte
Best-Effort-Verkehr widerspiegeln, der auf einem unbelasteten
Netz stattfindet.
Best-Effort
Normaler, unprivilegierter Netzwerkverkehr
Tabelle 2.1: Integrated Services Klassen
Die Eigenschaften dieser Klassen sind ursprünglich für die Multimediakommunikation konzipiert und nur grob umrissen. In [Fur03] werden diese Klassen in den
Automatisierungskontext gebracht und um angemessene Werte in Bezug auf die
restlichen QoS-Parameter erweitert (Tabelle 2.2).
Dienstklasse Anw. i.d. Automation
QoS-Parameter
Guaranteed
Echtzeitanwendung
Synchronisation
Fehlerbehandlung
Verfügbarkeit: sehr hoch
Verlustrate: sehr tief
Verzögerung: niedrig+konstant
Jitter: sehr klein
Durchsatz: konstant
Predictive
Download
Produktionsdaten
Programmierung
Debugging
Monitoring
Verfügbarkeit: sehr hoch
Verlustrate: sehr tief
Verzögerung: kontrolliert
Jitter: kontrolliert
Durchsatz: kontrolliert
Best-Effort
Bedienen & Beobachten
Internet-Zugriff
Extranet-Anbindung
Verfügbarkeit: hoch
Verlustrate: tief
Verzögerung: unspezifiziert
Jitter: unspezifiziert
Durchsatz: unspezifiziert
Tabelle 2.2: Service Klassen im Automatisierungskontext
[Fur03]
7
2.1. Quality of Service
Kapitel 2. Grundlagen
Der Guaranteed Service soll für echtzeitkritische Anwendungen, wie Synchronisation
und Fehlerbehandlung, eingesetzt werden. Der Predictive Service übernimmt Aufgaben wie Download, Programmierung der Peripherie, sowie Debugging und Monitoring. Der restliche Verkehr wird vom Best-Effort-Service bedient. Dies trifft auf
Anwendungen wie Internet-Zugriff und Extranet-Anbindung zu.
Auf IP-Ebene existieren zwei Ansätze zur Klassifizierung von Paketen : Integrated Services und Differentiated Services. Das in RFC 1633 beschriebene Integrated
Services (IntServ) teilt den Netzwerkverkehr in einzelne Paketströme, sogenannte
Flows, ein. Diesen Flows wird jeweils eine Serviceklasse zugeordnet. Damit jedes
Netzwerkelement auf dem Pfad das Paket erkennen und ihm Resourcen zuteilen
kann, wird das Resource Reservation Protokoll (RSVP) eingesetzt, das in RFC 2205
beschrieben ist. Jedes Netzwerkelement muss sich eine Tabelle halten, die die Flows
und ihre zugehörige Klasse verwaltet.
Das in RFC 2475 beschriebene Differentiated Services (DiffServ) verfolgt einen anderen Ansatz. Jedes Paket erhält entsprechend seiner Klasse eine Markierung. Dies
geschieht durch die Zuweisung eines Wertes (DS-Wert), der seine Klasse identifiziert.
Dieser Wert wird vom Paket mitgeführt und von den Netzwerkknoten innerhalb einer
DS-Domäne zwecks Klassifizierung ausgelesen. Das schont die Resourcen der Netzwerkknoten, da keine Tabelle mehr im Speicher gehalten werden muss, und macht
somit den Einsatz von RSVP unnötig. Allerdings müssen alle Netzwerkknoten innerhalb der DS-Domäne die Resourcen schon statisch für jede Klasse vorkonfiguriert
haben. Für den DS-Wert muss ein Feld im Protokoll-Header existieren, das zu diesem Zweck verwendet werden kann. Da das Type-of-Service-Feld im IP-Header nur
selten Verwendung fand, wird es mit Einführung von DiffServ als DS-Feld genutzt.
Für Ethernet existiert ein ähnlicher Ansatz, bei dem wie bei DiffServ das Paket
selbst markiert wird. Der Standard IEEE 802.1p (seit 2004 integriert in IEEE 802.1D
[IEE04]) beschreibt die Möglichkeit einem 802.3 Ethernet Frame eine Priorität zuzuweisen. Dies geschieht durch den sogenannten User Priority Wert, für den jedoch im
klassischen Ethernet-Header kein Feld vorgesehen ist. Daher wird von IEEE 802.1p
vorgeschlagen diesen Wert aus einem Feld in einer höheren Protokollschicht, wie
dem DS-Feld im IP-Header, zu berechnen oder das im 802.1Q-Standard beschriebene User-Priority-Feld im VLAN-Tag zu verwenden.
Der Standard IEEE 802.1Q [IEE03] beschreibt die Aufteilung eines physischen, von
einem Switch vermittelten Local Area Network, in mehrere virtuelle LANs. Um das
zu erreichen, wird zwischen der Zieladresse und dem Type-Feld ein 4 Byte langes
8
Kapitel 2. Grundlagen
2.1. Quality of Service
VLAN-Tag eingefügt (Abbildung 2.1).
Abbildung 2.1: IEEE 802.1Q VLAN Tag
Eingeleitet wird das Tag durch den Tag Protocol Identifier (TPID), der immer den
Wert 0x8100 hat. Darauf folgt die Tag Control Information (TCI), die aus dem 3Bit User Priority Feld, dem 1-Bit Canonical Format Indicator (CFI) und der 12-Bit
VLAN-ID (VID) besteht. Frames mit unterschiedlicher VID werden vom Switch wie
Frames in physikalisch voneinander getrennten LANs behandelt. Drei der VIDs sind
reserviert.
VID 0 VID 0 bezeichnet einen Priority Tagged Frame. Ein solcher Frame besitzt
keine VLAN-Zugehörigkeit; das Tag wird nur genutzt, um den Frame über das
User-Priority-Feld klassifizieren zu können.
VID 1 Jeder Switch muss über die Funktion verfügen, einem Frame ein Tag hinzuzufügen, sofern er noch keins besitzt. Die VID, die dem Frame zugewiesen
wird, wird Port-VID (PVID) genannt. Als Default PVID legt 802.1Q die VID
1 fest.
VID 0xFFF Diese VID ist für Implementationszwecke reserviert und sollte niemals
verwendet werden.
Mit dem User-Priority-Feld kann die Priorität eines Frames angegeben werden, wodurch der Frame für alle Netzwerkknoten auf seinem Pfad klassifizierbar ist. Zu
diesem Zweck definiert IEEE 802.1D [IEE04] acht Verkehrsklassen, auf die der Wert
des User-Priority-Feldes abgebildet wird. Tabelle 2.3 zeigt diese Klassen.
9
2.1. Quality of Service
Kapitel 2. Grundlagen
Priorität
User-Priority
Akronym
Verkehrsklasse
hoch
7
6
5
4
3
0
2
1
NC
VO
VI
CL
EE
BE
BK
Network Control
Voice
Video
Controlled Load
Excellent Effort
Best Effort
Nicht belegt
Background
niedrig
Tabelle 2.3: Abbildung der User-Priority-Werte auf
Traffic-Klassen
Die Priorität der einzelnen Verkehrsklassen entspricht ihrem Wert im User-PriorityFeld, d.h. 7 entspricht der höchsten Priorität, 6 der nächst niedrigeren, usw. Grundsätzlich wird davon ausgegangen, dass ein Frame ohne Tag der Best-Effort-Klasse
angehört. Wird einem Frame ein Tag hinzugefügt, und seine Klasse ist nicht ersichtlich, wird ihm eine User-Priority von 0 zugewiesen. Der Standard IEEE 802.1p
definiert jedoch zwei Klassen, die eine niedrigere Priorität aufweisen als Best-EffortVerkehr. Aus diesem Grund wurde dem User-Priority-Wert 0 eine höhere Priorität
zugewiesen, als den User-Priority-Werten 1 und 2. Dies geschah laut [Jas02] aus
Kompatibilitätsgründen.
2.1.2
Paket Scheduling, Traffic Shaping und Policing
Kann ein Paket klassifiziert werden, muss gewährleistet sein, dass jeder Netzwerkknoten auf dem Pfad in der Lage ist, es entsprechend seiner Klasse zu verarbeiten.
Paket Scheduling Algorithmen legen die Art und Weise fest, wie ein Knoten ein Paket verarbeitet. Sie haben die Aufgabe die Ausgangsqueue eines Netzwerkknotens
neu zu ordnen und somit bestimmten Paketen den Vorrang vor anderen Paketen zu
geben.
Eine andere Maßnahme, wie man den Verkehr in einem Netzwerk beeinflussen kann,
stellt dass Traffic Shaping dar. Hier wird der Durchsatz eines Datenstroms begrenzt,
um die Bandbreite für andere Datenströme freizuhalten. Pakete, die die Bandbreitenbegrenzung überschreiten würden, werden in einer Queue gehalten, bis wieder
genügend Bandbreite zu Verfügung steht. Eine Umordnung der Pakete wird grund-
10
Kapitel 2. Grundlagen
2.1. Quality of Service
sätzlich nicht berücksichtigt, ist jedoch nicht ausgeschlossen. Werden Pakete verworfen, anstatt sie in einer Queue zwischen zu lagern, so spricht man von Traffic
Policing.
Alle diese Algorithmen stellen nicht-preemptive Scheduling-Algorithmen dar, da die
Übertragung eines Paketes nicht abgebrochen werden kann, selbst wenn ein Paket
höherer Priorität zum Senden eintrifft.
Es existieren unzählige Algorithmen, die auf verschiedene Arten und mit teils unterschiedlichen Zielen diese Aufgaben erledigen. Hier sollen nur die besprochen werden,
die für diese Arbeit Relevanz haben. Als relevant werden die Algorithmen eingestuft,
die unter Linux oder in Switches implementiert sind und auch mit reinem Ethernet
einwandfrei genutzt werden können.
2.1.2.1
Strict Priority Queueing
Unter Strict Priority Queueing versteht man die Umsortierung streng nach Priorität.
Zu versendende Pakete werden bei diesem Algorithmus entsprechend ihrer Priorität
in verschiedene Ausgangsqueues sortiert. Zuerst werden die Pakete aus der Queue
mit der höchsten Priorität verschickt. Ist diese Queue leer, werden die Pakete aus der
Queue mit der nächst niedrigeren Priorität versendet usw. Die Pakete in einer Queue
müssen immer so lange warten, bis die Queues mit höherer Priorität keine Pakete
mehr enthalten. Innerhalb einer Queue werden die Pakete nach FIFO abgearbeitet.
Abbildung 2.2: Beispiel: Strict Priority Queueing
11
2.1. Quality of Service
Kapitel 2. Grundlagen
Abbildung 2.2 zeigt ein Beispiel für Strict Priority Queueing, in dem drei Queues mit
den Prioritäten 1 bis 3 verwendet werden, wobei Priorität 1 die höchste darstellt.
Das Paket aus der Prio 1 Queue wird bedient (1). Da die Prio 1 Queue leer ist,
wird das erste Paket aus der Prio 2 Queue verschickt. Während dessen trifft ein
weiteres Paket in der Prio 1 Queue ein, das Versenden des Pakets in der Prio 2
Queue kann jedoch nicht unterbrochen werden(2). Die verbleibenden Pakete werden
in Reihenfolge ihrer Priorität verschickt (3)-(6).
2.1.2.2
Weighted Round Robin Queueing
Dieser Scheduling Algorithmus baut auf dem Round Robin Algorithmus auf, bei dem
eine bestimmte Menge von Queues existiert. Unter diesen wird die gesamte Bandbreite aufgeteilt, womit jede Queue ein sogenanntes Quantum an Bandbreite erhält.
Beim Weighted Round Robin lässt sich das Quantum gewichten. So ist es möglich,
einer Queue mit hoher Priorität ein größeres Quantum an Bandbreite zukommen
zu lassen, als einer mit niedriger Priorität. Jede Queue nimmt die Bandbreite seines
Quantums in Anspruch, unabhängig davon, ob sie genutzt werden kann.
Abbildung 2.3: Beispiel: Weighted Round Robin Queueing
Das in Abbildung 2.3 gezeigte Beispiel für den Weighted Round Robin Algorithmus
zeigt drei Queues, mit den Quanten 1, 2 und 3. Die Queue mit Quantum 3 kann alle
enthaltenen Pakete versenden (1). In der Queue mit Quantum 2 werden nur zwei
der drei Pakete verschickt(2) und die Queue mit Quantum 1 bedient ihr einziges
12
Kapitel 2. Grundlagen
2.2. Ethernet im Echtzeitbetrieb
Paket (3). Die Queue mit Quantum 3 hat keine Pakete mehr zu versenden, nimmt
aber trotzdem ihre Zeiteinheiten in Anspruch (4). Die Queue mit Quantum 2 hat
zwar nur ein Paket zu versenden, nimmt aber auch ihre die Zeit von zwei Quanten
in Anspruch.
2.1.2.3
Token Bucket Algorithmus
Der Token Bucket Algorithmus stellt eine Traffic Shaping Methode dar. Der Algorithmus sieht einen Container (Bucket) vor, in dem mit einer festgelegten Rate
Token generiert werden. Jedes Token entspricht dabei einer festgelegten Anzahl Bytes. Soll ein Paket verschickt werden, muss eine Anzahl Token, entsprechend der
Größe des Pakets, aus dem Container entfernt werden. Sind nicht genug Token im
Container, muss das Paket warten, bis genügend Token generiert wurden. Die Rate,
in der die Token generiert werden, entspricht somit der Bandbreite, die einem Datenstrom zur Verfügung steht. Die Kapazität des Containers gibt die Anzahl Bytes
an, die in einem Burst verschickt werden können, soweit entsprechend viele Token
generiert werden konnten. Die Kapazität muss mindestens so groß gewählt werden,
wie ein maximal großes Paket, da sonst nie ausreichend Token im Container vorhanden wären, um ein solches Paket zu verschicken, und es die Queue blockieren
würde.
Das in Abbildung 2.4 gezeigte Beispiel zeigt einen Bucket mit einer Kapazität von
acht Token. Es wird in dem Beispiel davon ausgegangen, dass ein Paket beim Senden
drei Token verbraucht. In (1) ist der Bucket komplett gefüllt. Vier Pakete treffen ein,
von denen zwei sofort als Burst versandt werden können. Die zwei übrig gebliebenen
Token, reichen zum Versenden eines weiteren Pakets nicht aus (2). Abhängig von
der eingestellten Rate wird ein weiteres Token generiert, womit das dritte Paket
bedient werden kann(3). Das letzte Paket wartet auf weitere drei Token (4)+(5), bis
es an der Reihe ist. Solange keine weiteren Pakete in der Queue eintreffen, wird der
Bucket in der eingestellten Rate wieder bis zu seiner Kapazität gefüllt(6).
2.2
Ethernet im Echtzeitbetrieb
IEEE 802.3 Ethernet ist grundsätzlich nicht echtzeitfähig konzipiert worden und
kann in seiner ursprünglichen Form nicht als Feldbusersatz eingesetzt werden [Fel00].
Das größte Problem dabei ist das nicht-deterministische Medienzugriffsverfahren
13
2.2. Ethernet im Echtzeitbetrieb
Kapitel 2. Grundlagen
Abbildung 2.4: Beispiel: Token Bucket Algorithmus
CSMA/CD [Tan02, Hal96]. Da Kollisionen von CSMA/CD nur erkannt und nicht
verhindert werden, müssen Übertragungen abgebrochen und deren Neusendung initiiert werden. Diese kann bei hoher Last wiederum zu weitern Kollisionen führen,
die somit zu unbestimmbaren Verzögerungen führen. Im wesentlichen existieren drei
Ansätze, wie Kollisionen im Ethernet verhindert werden können: Lastreduzierung,
TDMA und der Einsatz von Switches.
2.2.1
Lastreduzierung
Der erste Ansatz Lastreduzierung ist von rein probabilistischer Natur und zielt darauf ab, die genutzte Bandbreite weit unter der verfügbaren zu halten [JL04]. Damit
wäre eine statistische Garantie für die Einhaltung von Delay-Grenzen gegeben. Da
es sich aber nur um eine statistische Garantie handelt, kann dieser Ansatz harten Echtzeitanforderungen nicht gerecht werden. Zugleich würde diese Lösung einer
Konfiguration mit hoher Anzahl an Knoten nicht mehr standhalten, da die zur Verfügung stehende Bandbreite dafür kaum ausreichen würde. Somit würde dabei die
Wahrscheinlichkeit des Auftretens von Kollisionen wieder ansteigen.
14
Kapitel 2. Grundlagen
2.2.2
2.2. Ethernet im Echtzeitbetrieb
Time Devision Multiple Access
Der zweite Ansatz sieht ein TDMA-Verfahren vor, bei dem jedem Knoten auf dem
Medium ein Zeitschlitz zugewiesen ist, während dessen er senden darf. Die Zuteilung der Zeitschlitze wird statisch oder durch einen Master-Knoten bestimmt. Die
Synchronisation wird durch den Einsatz einer fein granularen Uhr und eines Zeitprotokolls wie PTP [IEE] durchgesetzt. Die festen Delay-Grenzen werden von der
gewählten Zykluszeit bestimmt. Durch die Wahl einer geringen Zykluszeit entsteht
ein geringer Delay, jedoch wird auch die zur Verfügung stehende Bandbreite verringert. Durch die festen Zeitabstände entsteht ein geringer Jitter. Da nicht jeder
Knoten in seinem Zeitschlitz sendebereit ist, bleibt Bandbreite teilweise ungenutzt,
die für Best-Effort-Verkehr hätte genutzt werden können.
Dieses Verfahren wird in Zusammenhang mit Ethernet unter anderem von RTnet
[KS04] eingesetzt, welches die Nutzung der Echtzeiterweiterung RTAI unter Linux
vorsieht. RTNet implementiert einen kompletten, echtzeitfähigen UDP/IP-Stack,
der durch ein BSD-Socket-Interface erschlossen wird. Es setzt ein geschlossenes und
durch einen Hub verschaltetes Netz voraus, in dem sich alle Teilnehmer an das
TDMA-Protokoll halten und ein Masterknoten für die Synchronisierung der Stationen sorgt. Der Stack der beteiligten Rechner wird durch einen modifizierten LinuxTreiber an Ethernet angebunden. Eine Fernkonfiguration dieser Rechner ist durch
ein eigenes, vom RTNet-Protokoll unabhängiges Protokoll namens RTcfg möglich.
Die vertikale Integration erfolgt durch Tunnelung der betroffenen Protokolle über
einen Gatewayknoten.
Ein weiteres Beispiel für TDMA ist Profinet IRT (Isochronous Real Time) [eH].
Dieses teilt das Medium zunächst in einen deterministischen und einen offenen Zeitschlitz auf. Im offenen Zeitschlitz wird der gesamte Best-Effort-Verkehr, sowie der
Verkehr mit weichen Echtzeitanforderungen abgewickelt. Die weiche Echtzeit wird
durch Priorisierung nach IEEE 802.1p durchgesetzt. Der deterministische Zeitschlitz
ist in weitere Zeitschlitze unterteilt, in denen Kommunikation nach harten Echtzeitanforderungen abläuft. Die Reservierung der Zeitschlitze erfolgt über einen speziell für diesen Zweck entwickelten Chip, der in die verwendeten Switches integriert
ist.
Im Zusammenhang mit TDMA soll noch das Token-Passing-Verfahren genannt werden. Auch hier wird das Medium in Zeitschlitze aufgeteilt, jedoch ist das Synchronisieren der Uhren in den Knoten nicht notwendig. Die Sendeberechtigung wird durch
ein Token zugeteilt, das in Form eines Pakets zyklisch unter den Stationen ausge-
15
2.2. Ethernet im Echtzeitbetrieb
Kapitel 2. Grundlagen
tauscht wird. Der Besitzer des Tokens sendet seine Daten und reicht dann das Token
an den nächsten weiter.
2.2.3
Einsatz von Switches
Ein Switch ist ein Vermittlungselement zwischen Netzen, welches auf der MACTeilschicht der in IEEE 802 Standard [IEE01] beschriebenen Architektur arbeitet.
Die Funktionsweise wird im Standard IEEE 802.1D [IEE04] festgelegt. Durch den
Einsatz eines in Voll-Duplex-Modus arbeitenden Switches ist es möglich, Kollisionsdomänen zu segmentieren. Durch Microsegmentierung, d.h Zuweisung eines Ports
für jeden Rechner, sind Kollisionen ausgeschlossen, was ein vollkommen deterministisches Verhalten von Ethernet zur Folge hat [Jas02]. Im Folgenden sollen die
Funktionsweise und der Aufbau anhand der Abbildung 2.5 erläutert werden.
Abbildung 2.5: Aufbau eines Switch
Ein Switch besitzt mindestens zwei Ports, die sowohl unterschiedliche Datenraten,
16
Kapitel 2. Grundlagen
2.2. Ethernet im Echtzeitbetrieb
als auch Duplex-Modi aufweisen können. Die Vermittlung zwischen den einzelnen
Ports wird durch eine Vermittlungseinheit vorgenommen. Diese verwaltet eine Tabelle mit MAC-Adressen, die jeweils einem Port zugeordnet sind. Trifft ein Frame
an einem Port ein, so wird er im Shared Memory des Switches abgelegt. Dort wird
die Zieladresse des Frames ausgelesen und durch die Vermittlungseinheit mit den
Adressen in der MAC-Tabelle verglichen. Gehört diese Adresse zu dem Port, auf
dem der Frame empfangen wurde, wird der Frame verworfen. Ansonsten wird ein
Zeiger auf die Speicheradresse des Frames in die Ausgangsqueue des entsprechenden
Ports zwecks Weiterleitung eingereiht. Für den Fall, dass die Adresse nicht in der
Tabelle enthalten ist, leitet er den Frame an alle Ports weiter (Flooding). Sobald der
adressierte Rechner antwortet, kann die Vermittlungseinheit die MAC-Adresse dem
Port zuordnen, auf dem er empfangen wurde, und sie in die Tabelle eintragen.
Der Frame verweilt so lange im Shared Memory des Switches, bis die Ausgangsqueue auf die Position des zugehörigen Zeigers abgearbeitet ist und der Frame verschickt werden kann. Die Ausgangsqueues der Ports weisen in der Regel FIFOCharakteristik auf; um jedoch User-Prioritäten nach 802.1p berücksichtigen zu können, sieht der Standard 802.1D [IEE04] auch die Ausstattung der Ports mit mehr
als einer Queue vor. Da dort nicht zwingend acht Queues vorgesehen ,sind erfolgt
eine Zuteilung der Verkehrsklassen aus Tabelle 2.3 aufgrund von Tabelle 2.4. Diese
Queues werden in der Regel dann nach dem Strict Priority Algorithmus abgearbeitet, können auf den einzelnen Switches aber auch per Weighted Round Robin
bedient werden.
Anzahl Queues
Traffic Klasse
1
BE
2
BE
3
BE
VO
4
BK
BE
5
BK
BE
6
BK
BE
7
BK
8
BK
–
CL
VO
CL
VO
CL
VI
VO
EE
CL
VI
VO
BE
EE
CL
VI
VO
NC
BE
EE
CL
VI
VO
NC
Tabelle 2.4: Zuteilung der Traffic Klassen pro Anzahl der
Ausgangsqueues [IEE04]
17
2.2. Ethernet im Echtzeitbetrieb
Kapitel 2. Grundlagen
Durch die gezielte Verteilung der Frames an ihre Zielnetze, werden die Netzwerke
bzw. die zugehörigen Ports nicht belastet und es kommt nicht so schnell zu Überläufen und damit zu Paketverlust. Durch den Einsatz von Multicasts [IEE01] macht
man diesen Vorteil zunichte, da diese, wie Broadcasts, über alle Ports gesendet werden. Um diesen Vorteil auch mit Multicasts nutzen zu können, wird in IEEE 802.1p
[IEE04] das GARP Multicast Registration Protocol (GMRP) vorgestellt. Ein Switch
der GMRP unterstützt leitet grundsätzlich erst einmal keine Multicast-Frames weiter. Empfängt er ein GMRP Paket mit der Information, dass eine Station Frames
einer Multicast-Gruppe empfangen möchte, so wird diese in die MAC-Adresstabelle
eingetragen. Das bewirkt, dass diese Frames über diesen Port weitergeleitet werden.
Genauso ist es auch möglich, Multicast-Gruppen per GMRP zu deregistrieren.
Managebare Switches, die kein GMRP unterstützen, lassen oft auch zu, die MACAdresstabelle für den Multicastbetrieb manuell zu konfigurieren.
Switches, die über mehrere Ausgangsqueues pro Port verfügen und den IEEE 802.1p
Standard unterstützen, werden unter anderem von Cisco (Catalyst 2950 mit 4 Queues) und Siemens (ELS TP40M mit 2 Queues) hergestellt.
2.2.4
Fazit
Die vorgestellten Verfahren zur Erlangung von Determinismus unter Ethernet haben
jeweils ihre Vorteile, jedoch auch ihre Einschränkungen. So ist Lastreduzierung zur
Erlangung einer statistischen Kollisionsfreiheit in einem kleinen Netzwerk mit wenigen Teilnehmern eine günstige Lösung, jedoch skaliert diese nicht bei ansteigender
Zahl der beteiligten Knoten.
TDMA ist sehr aufwendig in der Umsetzung und setzt eine Anpassung des ProtokollStacks oder die Verwendung angepasster Hardware voraus. Dafür bietet es harte
Echtzeitfähigkeit mit kontrolliertem Jitter.
Der Einsatz von Switches bietet Determinismus durch Microsegmentierung des Netzwerks. Darüber hinaus kann QoS durch standardisierte Protokollerweiterungen durchgesetzt werden, wenn der Switch diese unterstützt und über geeignete Hardware
verfügt. Ob sich dadurch harte Echtzeitanforderungen durchsetzen lassen, hängt
von den Anforderungen des technischen Prozesses ab. Bei geeigneter Topologie und
konfigurierter Last, können Transaktionszeiten im Millisekunden-Bereich garantiert
werden [Jas02].
18
Kapitel 2. Grundlagen
2.3
2.3. Linux
Linux
Linux bietet als freies Betriebssystem diverse Einstellmöglichkeiten für Quality of
Service, auf die im Folgenden eingegangen wird. In dieser Arbeit soll der LinuxKernel ab Version 2.6 betrachtet werden, dessen System-Timer seit der Version 2.4
einen Granularitätsanstieg um den Faktor 10 auf 1000Hz erfahren hat.
2.3.1
Packet-Sockets
Ein Packet-Socket ist eine direkte Schnittstelle zur Kommunikation über Ethernet.
Bei den durch einen Packet-Socket versendeten Daten, wird nur der Ethernet-Header
hinzugefügt, wodurch der TCP/UDP/IP-Stack umgangen wird.
Der Packet-Socket ist zwar kein explizites QoS-Werkzeug, doch durch seinen Einsatz
können Delay und Jitter implizit reduziert werden.
Die Konfiguration erfolgt auf die gleiche Weise, wie die eines INET-Socket, durch den
Aufruf des Systemcalls socket().
Quelltext 2.1: Der
socket()-Systemcall
für Packet-Sockets
packet_socket = socket ( PF_PACKET , int socket_type , int protocol ) ;
Gibt man für den Parameter socket_type den Wert SOCK_DGRAM an, so wird der
Header des Frames beim Versand durch das Betriebssystem generiert und beim
Empfang automatisch wieder entfernt. Gibt man SOCK_RAW, an müssen diese von
dem aufrufenden Prozess bereitgestellt bzw. entfernt werden.
Der Parameter protocol nimmt den Protokolltyp auf, den der Socket empfangen soll.
Der verwendete Wert wird in Network-Byte-Order übergeben und ist im EthernetHeader im Type-Feld wiederzufinden. In der Header-Datei linux/if ether.h sind die
allgemein bekannten Protokolle, wie ETH_P_IP (0x8000) oder auch ETH_P_8021Q (0x8200)
definiert. Es ist jedoch auch möglich ein eigenes Protokoll zu definieren, wobei darauf
geachtet werden sollte, dass es nicht mit den reservierten Protokollen kollidiert.
Zur Adressierung wird die sockaddr_ll-Struktur genutzt, die bei Aufrufen von sendto
() übergeben wird. Die Struktur wird ausführlich auf der Manpage packet(7) besprochen. Dort wird auch erklärt, wie ein Paket-Socket für den Empfang von EthernetMulticast-Frames eingerichtet wird.
19
2.3. Linux
2.3.2
Kapitel 2. Grundlagen
802.1Q VLAN Modul
Die Virtual LAN Funktionalität wird unter Linux von dem Modul 8021q gewährleistet. Um das Modul nutzen zu können, muss es entweder dynamisch geladen oder
fest in den Kernel kompiliert werden. Die dafür erforderliche Kernel-Option für Kernel 2.6 ist unter ”Device Drivers/Networking support/Networking options/802.1Q
VLAN Support” zu finden.
2.3.2.1
Aufbau und Funktionsweise
Wird ein neues VLAN konfiguriert, so wird dafür ein neues logisches NetzwerkDevice erstellt. Normalerweise repräsentiert ein logisches Device unter Unix/Linux
ein in Hardware vorhandenes Netzwerkinterface. Das für das VLAN erstellte Device
repräsentiert keine Hardware. Vielmehr ist es einem realen, logischen NetzwerkDevice vorgeschaltet und wird als virtuelles Gerät bezeichnet(Abbildung 2.6). Der
Name des virtuellen Devices ist abhängig von der Konfiguration des Moduls. Tabelle 2.6 zeigt hierfür alle Möglichkeiten der Konfiguration auf, sowie deren DefaultEinstellung. Normalerweise wird das Device, über das Pakete verschickt werden,
durch den Routing-Prozess ermittelt. Daher ist es empfehlenswert, die Devices verschiedenen Subnetzen zuzuordnen oder die Sockets durch Socket-Optionen an das
jeweilige Device zu binden. Ansonsten ist nicht eindeutig, auf welchem der Devices
ein Paket gesendet werden soll.
Jedem Device können bis zu 4093 VLANs (212 − 3) zugewiesen werden.
Abbildung 2.6: Aufbau der VLAN-Devices
20
Kapitel 2. Grundlagen
2.3. Linux
Wird ein Paket über ein VLAN verschickt, muss das über das dazugehörige virtuelle
Device geschehen. Dort wird das VLAN-Tag mit der entsprechenden VID in das
Paket eingefügt und an das reale Device weitergegeben. Umgekehrt werden am realen
Device empfangene Pakete, die VLAN-gekennzeichnet sind, an das entsprechende
virtuelle Device weitergereicht. Dort wird das Tag entfernt und über den ProtokollStack an den Empfängerprozess weitergegeben.
Das Setzen des Wertes im User-Priority-Feld wird durch zwei Priority-Maps erreicht:
der Egress-Priority-Map und der Ingress-Priority-Map. Die Egress-Priority-Map bildet beim Senden eines Pakets die Priorität dessen Socket-Buffers auf den Wert im
User-Priority-Feld ab. Der Socket-Buffer ist eine Struktur im Linux Kernel, mit der
die zu sendenden und empfangenen Pakete durch den Protokoll-Stack nach unten
bzw. nach oben weitergereicht werden. Desweiteren enthält die Egress-Priority-Map
weitere Flags und Werte, u.a. Socket-Priority, die mit dem zugehörigen Socket assoziiert werden.
Für die Möglichkeit, die User-Priority auf die Socket-Priority zurück zu rechnen,
ist die Ingress-Priority-Map zuständig. Diese wird aber nur für den Fall benötigt,
dass Linux Bridging-Funktionen übernehmen soll. Die Priorität aller Socket-BufferStrukturen, die durch einen Socket gesendet werden, kann über eine Socket-Option
gesetzt werden. Ansonsten wird der Wert des DS-Feldes im IP-Header auf die Priorität abgebildet. Die Prioritäten des User-Priority-Feld können mit dem 802.1Q Modul
zwar gesetzt werden, jedoch wird die Einhaltung der Prioritäten nicht durchgesetzt.
Dazu ist der Einsatz von Paket Scheduling Algorithmen nötig, die die Pakete nach
dem User-Priority-Feld klassifizieren und entsprechend bedienen.
2.3.2.2
Konfiguration
Die Konfiguration der VLANs und deren Parameter erfolgt durch das Open-Source
Tool-vconfig, welches in jeder größeren Linux Distribution enthalten ist. Weitere
Informationen sind der Manpage des Programms zu entnehmen.
Möchte man die Konfiguration aus einem C-Programm vornehmen, so empfiehlt es
sich, dass Application Programming Interface (API) zu nutzen, das auch von vconfig
verwendet wird.
Das Wissen über die Funktionalität des API wurde hauptsächlich aus dem Quellcode
des vconfig-Tools und dem 8021q Kernelmodul hergeleitet. Daher wird nicht der
Anspruch auf Vollständigkeit erhoben.
21
2.3. Linux
Kapitel 2. Grundlagen
Die dafür erforderlichen Header-Dateien sind:
# include < sys / ioctl .h >
# include < linux / if_vlan .h >
Der Systemcall ioctl() (Listing 2.2) dient als Schnittstelle zum 8021q Kernelmodul.
Für die Handhabung der Funktion sei wiederum auf die entsprechende Manpage
verwiesen.
Quelltext 2.2: Der
ioctl()-Systemcall
int ioctl ( int d , int request , void * argp ) ;
Für den ”request”-Parameter wird der definierte Wert ”SIOCSIFVLAN” verwendet. Um
die Anfrage näher zu spezifizieren, ist in if_vlan.h die Struktur struct vlan_ioctl_args
definiert. Im Folgenden soll nun deren Aufbau und Funktion anhand des QuelltextListings 2.3 beschrieben werden.
Quelltext 2.3: Die
1
2
3
4
5
6
7
8
9
10
11
12
13
vlan_ioctl_args
Struktur
struct vlan_ioctl_args {
int
cmd ;
char device [24]
union {
char
device2 [24];
int
VID ;
unsigned int skb_priority ;
unsigned int name_type ;
unsigned int bind_type ;
unsigned int flag ;
} u;
short vlan_qos ;
};
Das Datenmember cmd (Zeile 2) dient der Spezifizierung des Kommandos, das an
das Kernel-Modul abgesetzt werden soll. Abhängig von den Kommandos (Tabelle
2.5) werden weitere Member-Argumente genutzt.
Für jeden Befehl wird der den Namen des Devices, das konfiguriert werden soll in
device (Zeile 3) gespeichert. Um ein virtuelles Device mit dem Kommando ADD_VLAN
_CMD anzulegen, wird der Name des realen Device angegeben, an dem das virtuelle
konfiguriert werden soll. Alle anderen Kommandos haben den Namen des zu konfigurierenden, virtuellen Devices als Argument.
Das Member device2 (Zeile 5) der Union u dient der Übergabe eines zweiten DeviceNamens. Bisher ist kein Kommando definiert, welches dies nutzt.
VID (Zeile 6) wird beim Kommando ADD_VLAN_CMD genutzt, um die gewünschte VID
an das Kernel-Modul zu übergeben.
22
Kapitel 2. Grundlagen
2.3. Linux
Mit skb_priority (Zeile 7) wird die Priorität eines Socket-Buffers übergeben, die
auf einen Wert im User-Priority-Feld eines Frames abgebildet werden soll. Dieses Member wird von den Kommandos SET_VLAN_INGRESS_PRIORITY_MAP_CMD und
SET_VLAN_EGRESS_PRIORITY_MAP_CMD genutzt.
name_type (Zeile 8) bestimmt die Art, wie die virtuellen Devices benannt werden. Ta-
belle 2.6 beschreibt die in if_vlan.h dafür definierten Werte und deren Auswirkung
auf die Namensgebung der virtuellen Devices.
In bind_type (Zeile 9) wird bestimmt, ob eine VID für den gesamten Kernel oder
für jedes reale Device eindeutig ist. Zur Zeit der Erstellung dieser Arbeit existiert
kein Kommando, das dieses Member nutzt.
flag (Zeile 10) nimmt den Key für ein Flag auf, das gesetzt werden soll, wenn für cmd
(Zeile 2) das Kommando SET_VLAN_FLAG_CMD gesetzt wurde. Zur Zeit dieser Arbeit
existiert nur das REORDER_HDR Flag, das angibt, ob der Header neu geordnet werden
soll. Dies soll die Kompatibilität zu diversen Programmen wahren, bedeutet aber
auch Performance-Einbußen. Wenn die Option nicht unbedingt erforderlich ist, wird
empfohlen, sie nicht zu nutzen.
Das Datenmember vlan_qos (Zeile 12) hat zwei Funktionen: Hauptsächlich wird es
genutzt, um bei den Kommandos SET_VLAN_INGRESS_PRIORITY_MAP_CMD und SET_VLAN
_EGRESS_PRIORITY_MAP_CMD den User-Priority-Wert anzugeben, auf den ein Prioritätswert der Socket-Buffer abgebildet wird. Zusätzlich wird es beim Kommando
SET_VLAN_FLAG_CMD genutzt, um einen optionalen Wert für das in flag angegebene
Flag aufzunehmen.
Kommando
Bedeutung
Argumente (Zeilennr.)
ADD_VLAN_CMD
Erstelle ein VLAN
VID (3)
DEL_VLAN_CMD
Entferne ein VLAN
SET_VLAN_INGRESS-
Setze ein Socket-/User-Priority
Wertepaar für Ingress-Priority-Map
skb_priority (8)
Setze ein Socket-/User-Priority
Wertepaar für Egress-Priority-Map
skb_priority (8)
_PRIORITY_MAP_CMD
SET_VLAN_EGRESS_PRIORITY_MAP_CMD
GET_VLAN_INGRESS_PRIORITY_MAP_CMD
GET_VLAN_EGRESS_PRIORITY_MAP_CMD
Wird zur Zeit der Arbeit nicht
unterstützt
Wird zur Zeit der Arbeit nicht
unterstützt
23
vlan_qos (13)
vlan_qos (13)
2.3. Linux
Kapitel 2. Grundlagen
name_type (9)
_TYPE_CMD
Setze die Namensgebung des
virtuellen Interfaces
SET_VLAN_FLAG_CMD
Setze ein Flag
flag (11)
SET_VLAN_NAME-
vlan_qos (13)
Tabelle 2.5: VLAN ioctl Kommandos
Wert
Namensbildung
Beispiel
VLAN_NAME_TYPE-
vlan<4 Stellen VID>
vlan0002
<Device Name>.<4 Stellen VID>
eth0.0002
vlan<VID>
vlan2
<Device Name>.<VID>
eth0.2
_PLUS_VID
VLAN_NAME_TYPE_RAW_PLUS_VID
VLAN_NAME_TYPE_PLUS_VID_NO_PAD
VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD
(default)
Tabelle 2.6: Namensgebung des VLAN Device
2.3.3
Queueing Disziplinen
Queueing Disziplinen (QDiscs) sind die Implementierung von Paket Scheduling Algorithmen unter Linux. Jedem Netzwerk-Device ist eine QDisc zugeordnet.
2.3.3.1
Funktionsweise
QDiscs sind zwischen dem jeweiligen Netzwerktreiber und den höheren Protokollschichten angeordnet (Abbildung 2.7). Ist vor dem realen Device ein virtuelles geschaltet, liegen zwischen dem Treiber und den höheren Protokollschichten zwei QDiscs.
Die Funktionsweise einer QDisc ist aus der Sicht der angrenzenden Protokollschichten absolut transparent. Für sie existieren nur vordefinierte QDisc-Methoden. Die
wichtigsten sind enqueue(), dequeue() und requeue().
Alle Informationen und die Funktionalitäten eines Netzwerk-Devices werden in der
net_device-Struktur gehalten, die in netdevice.h definiert ist. Hier wird auch ein
24
Kapitel 2. Grundlagen
2.3. Linux
Abbildung 2.7: Funktionsweise von Queueing Disziplinen
Zeiger auf die QDisc des Devices gehalten.
Wird ein Paket über ein Netzwerk-Device verschickt, so ruft die höhere Protokollschicht die Funktion dev_queue_xmit() in der Struktur auf. Diese übergibt den
Socket-Buffer des Pakets an die enqueue()-Funktion der QDisc. Daraufhin startet dev_queue_xmit() die Funktion qdisc_run(), die dafür sorgt, dass die Funktion
qdisc_restart() zyklisch ausgeführt wird. Bevor die beiden Abbruchbedingungen
dieser Schleife erläutert werden, wird näher auf die Funktion qdisc_restart() eingegangen.
qdisc_restart() ruft die dequeue()-Funktion der QDisc auf. Wird ein Paket von der
QDisc zurückgeliefert, so wird das Paket mit der Funktion hard_start_xmit() an
den Treiber übergeben und über die Hardware versendet. Im Falle eines virtuellen
Devices wird das Paket mit der Funktion dev_queue_xmit() an das reale Device
übergeben. Ist das Netzwerk-Interface nicht bereit ein Paket entgegen zu nehmen,
blockiert es. In diesem Fall wird das Paket mit der Funktion requeue() wieder in
die QDisc an der ursprünglichen Position eingefügt. Das Blockieren des NetzwerkInterfaces gilt als eine Abbruchbedingung für die Schleife in qdisc_run().
Die zweite Abbruchbedingung betrifft den Fall, dass die Queueing Disziplin kein Paket zurück liefert. Das heißt nicht, dass sich kein Paket in der Queue befindet. Je nach
Bedingung des verwendeten Algorithmus könnte die QDisc enthaltene Pakete noch
zurückhalten, um z.B. die Bandbreite zu begrenzen. Gibt die QDisc ein zurückgehaltenes Paket zum Senden frei oder kehrt das Device aus einem blockierten Zustand
25
2.3. Linux
Kapitel 2. Grundlagen
zurück, kann nicht auf das Anstoßen von qdisc_run() durch das Eintreffen eines weiteren Pakets in der QDisc gewartet werden. Hierzu existiert der Software-Interrupt
NET_TX_SOFTIRQ, der die Funktion aufruft. Ausgelöst wird der Interrupt zum einen
durch den Jiffies-Timer, der den Kernel-Takt von 1ms erzeugt, und zum anderen
durch den Übergang des Hardware-Devices vom blockierten in den unblockierten
Zustand.
Die Granularität des Jiffies-Timers beträgt im Linux-Kernel 2.6 1ms, der auf 1µs
heruntergerechnet wird. Bei der Kernel-Konfiguration stehen Alternativen zum JiffiesTimer zur Verfügung, die im Folgenden genannt werden.
Auf Architekturen, die über ein CPU-Cycle-Counter verfügen, kann dieser als Timer
für das QoS-Modul konfiguriert werden. Er weist eine weit höhere Granularität als
1µs auf, die dann auf 1µs hochgerechnet wird. Es wird empfohlen diesen zu nutzen
falls er zur Verfügung steht, allerdings kann es zu Problemen auf Mehrprozessorsystemen kommen oder bei Prozessoren, die Frequenzwechsel unterstützen.
Die zweite Alternative ist die Funktion gettimeofday(), die eine Granularität von
genau 1µs aufweist. Es wird jedoch von dieser Möglichkeit abgeraten, da sie zu viel
CPU-Zeit verbraucht.
2.3.3.2
Aufbau
Queueing-Disziplinen unterscheiden sich untereinander in ihrem internen Aufbau
(Abbildung 2.8). Grundsätzlich lassen sie sich in zwei Kategorien einordnen: die klassenlosen und die klassenbehafteten Queueing Disziplinen. Die klassenlosen QDiscs
sind Implementierungen von Paket-Scheduling-Algorithmen, deren interner Aufbau
nicht weiter konfigurierbar ist. Sie besitzen eine in Grenzen konfigurierbare Funktionalität und sind nicht erweiterbar. Die Art, wie Daten klassifiziert werden, ist fest
vorgegeben und lässt sich nicht verändern.
Klassenbehaftete Queueing Disziplinen sind modular aufgebaut [WPR+ 02]. Intern
lassen sich Klassen konfigurieren, die jeweils verschiedene Eigenschaften, wie z.B.
Prioritäten, besitzen. Mit diesen Klassen lassen sich Baumstrukturen herstellen,
deren Aufbau jedoch von der jeweiligen Queueing Disziplin abhängt. So kann die
Klassenhierarchie bei bestimmten QDiscs nicht in die Tiefe wachsen.
Klassen halten selbst keine Daten, ihnen muss eine QDisc zugeordnet werden, die
die Daten auffängt. Dies kann sowohl eine klassenlose als auch eine klassenbehaftete
QDisc sein, was wiederum eine weitere Verästelung der Baumstruktur zur Folge hat.
26
Kapitel 2. Grundlagen
2.3. Linux
Abbildung 2.8: Aufbau von Queueing Disziplinen
Das Verhalten der Blatt-QDiscs nimmt durch ihr eigenes Verhalten Einfluss auf das
Verhalten ihrer Eltern-QDisc.
Um Pakete den Klassen zuzuordnen, bringen viele QDiscs ihren eigenen Klassifizierer mit, die auf ihr Verhalten zugeschnitten sind. Um höhere Flexibilität beim
Klassifizieren der Pakete zu erreichen, stehen eine Reihe von individuellen Filtern
zur Verfügung, deren Funktionalität vom einfachen Erkennen eines Feldes im IPHeader (dsmark), über die Auswertung von Routinginformationen (route, fw), bis
hin zur kompletten Mustererkennung im gesamten Paket (u32) reicht. Wird ein
Filter an einer QDisc oder Klasse angebracht, überschreibt er deren eigenen Klassifizierer. Existieren mehrere Filterregeln nebeneinander, kann die Reihenfolge, in der
sie abgefragt werden, durch einen Prioritätswert bestimmt werden.
Wird ein Klasse oder QDisc gelöscht, so werden automatisch alle ihre Kindklassen
und deren QDiscs mitgelöscht. Jedoch kann eine Klasse nur gelöscht werden, wenn
kein Filter mehr auf diese Klasse verweist.
Vom Linux-Kernel werden alle Elemente des Baums über 32-Bit Handles verwaltet.
Diese sind zu jeweils 16-Bit in eine Major- und eine Minor-Nummmer aufgeteilt,
welche nichts mit den Major- und Minor-Nummern der Linux-Gerätedateien zu tun
haben. Die Handles sind für jedes Device eindeutig, können sich somit über alle
Devices wiederholen.
Die Minor-Nummer von Queueing Disziplinen ist stets null. Ausnahme davon sind
die Root Queueing Disziplin und die Ingress Queueing Disziplin. Das Handle der
27
2.3. Linux
Kapitel 2. Grundlagen
Root QDisc ist FFFF:FFFF und als TC_H_ROOT definiert. Für die Ingress QDisc
ist das Handle FFFF:FFF1 reserviert, welches als TC_H_INGRESS definiert ist. Beide
beschreiben keine Queueing Disziplin im eigentlichen Sinne, sondern sind vielmehr
Andockpunkte für die Wurzel-QDisc. Queueing Disziplinen, die an der Ingress QDisc
angebracht werden, können nur für Traffic Policing genutzt werden. Nicht alle Queueing Disziplinen sind dazu geeignet.
Beim Hinzufügen einer QDisc kann der Benutzer die Major-Nummer aus einem
Intervall von 0x0001 bis 0x7FFF selbst wählen. Wird kein Handle vom Benutzer
übergeben, weist der Kernel der QDisc eine Major-Nummer zwischen 0x8000 und
0xFFFF zu.
Die Major-Nummer einer Klasse entspricht immer der Major-Nummer der QDisc,
der sie angehört. Die Minor-Nummer hat einen zur Major-Nummer eindeutigen Wert
im Intervall von 0x0001 bis 0xFFFF.
Zur Konfiguration der Queueing Disziplinen steht das Programm tc zur Verfügung,
dass im Paket iproute2 enthalten ist. Möchte man jedoch die QDiscs von einem
Programm heraus konfigurieren, so existiert hierfür die Netlink-Socket-Schnittstelle.
Deren Dokumentation ist jedoch sehr spärlich bis gar nicht vorhanden, so dass sie
im Rahmen dieser Arbeit analysiert werden musste. Aus diesem Grund wird sie im
Kapitel 3.4 beschrieben.
Zu näheren Information über die Konfiguration der Queueing Disziplinen mit tc, sei
[Hub03] empfohlen.
28
Kapitel 3
Analyse
3.1
Anforderungen
Abbildung 3.1: Use-Case Diagramm
29
3.1. Anforderungen
3.1.1
Kapitel 3. Analyse
Anfordern von QoS
Es gibt zwei Möglichkeiten, wie QoS-Eigenschaften für einen Kommunikationspfad
angefordert werden können.
Zunächst kann ein Prozess versuchen, die QoS-Eigenschaften zur Laufzeit zu reservieren. Ein Modul, dass die Resourcen verwaltet, entscheidet dann, ob sie diese für
den Prozess reservieren kann. Voraussetzung dafür ist, dass das Modul die Topologie des Netzes kennt, da sonst QoS-Parameter, wie Ende-zu-Ende-Verzögerung,
nicht ermittelbar sind.
Die zweite Möglichkeit ist, mit einer Scheduability-Analyse zu bestimmen, ob die benötigten QoS-Parameter für die Kommunikationspfade bereitgestellt werden können.
Dies findet meistens in der Industrieautomation Anwendung, denn dort findet man
gewöhnlich statische Konfigurationen vor. Die Konfiguration der QoS-Parameter
lässt sich dadurch schon vor der Inbetriebnahme der Anlage vornehmen und muss
nicht erst von den einzelnen Knoten beantragt werden.
3.1.2
Steuern und Regeln
In einer automatisierten Anlage treten sich zyklisch wiederholende Prozesse auf.
Zur Steuerung einer solchen Anlage müssen Stellgrößen jeweils einmal pro Zyklus
an die entsprechenden Aktoren übertragen werden. Desweiteren werden auch die
Prozesszustände von den Sensoren für jeden Zyklus erfasst. Dies resultiert in isochron
propagierten Datagrammen, die an jeden Knoten gerichtet sind, der sie benötigt.
Damit der sendende Knoten nicht die Adressen aller Knoten halten muss, die seine Informationen benötigen, und kein Overhead durch mehrfach gesendete Daten
an verschiedene Knoten entsteht, wird für jede Nachrichtenklasse eine MulticastGruppe eingerichtet. Somit können die Knoten, die bestimmte Daten benötigen,
sich diese aus dem Verkehr herausgreifen.
Diese Form der Kommunikation tritt meistens im hohen bis mittleren Prioritätsspektrum auf. So werden für die Prozesssteuerung kritischen Mess- und Steuerdaten
mit hoher Priorität verteilt, während Messdaten, die einer statistischen Erfassung
dienen, eine mittlere Priorität aufweisen.
Die Stationen, die eine Anlage steuern, befinden sich in der Regel in einem Netzwerksegment, dessen Topologie statisch ist. Da alle Adressen bekannt sind, wird die
30
Kapitel 3. Analyse
3.1. Anforderungen
Nutzung der höheren Protokollschichten unnötig. Daher besteht der Protokoll-Stack
in der Automation meist nur aus Layer 1, 2 und 7 [Fur03].
Dies hat mehrere Vorteile: Zum einen verringern sich der Delay und der Jitter im
Stack, da weniger Code ausgeführt werden muss und zeitaufwendige Protokolle wie
ARP nicht mehr zur Anwendung kommen.
Zum anderen haben Mess- und Steuerdaten in der Regel nur eine geringe Größe.
Durch Aussparen der höheren Protokolle wird ein massiver Overhead durch die
Protokoll-Header verhindert.
3.1.3
Alarm-Signalisierung
Kommt es in einer automatisierten Anlage zu Fehlerzuständen, Unfällen oder anderen unvorhersehbaren Ereignissen, muss die Anlage sofort gestoppt werden können,
um schwere Verletzungen oder eine Beschädigung der Anlage zu verhindern. Um das
zu erreichen, muss eine Nachricht höchster Priorität an alle Knoten der Anlage gesandt werden, um sie von dem Fehlerzustand unterrichten. Diese stellen den Betrieb
ein und lassen die Anlage in einen sicheren Zustand zurückkehren.
3.1.4
Datei-Download / Upload
Durch vertikale Integration ist es möglich, von einem dedizierten Rechner Dateien von bzw. auf einen Automationsrechner zu laden. Dies wird genutzt, um z.B
Firmware-Updates auf eine Steuerungseinheit zu laden oder eine lokal gespeicherte
Log-Datei bzw. Messdaten von einem Automationsrechner herunterzuladen.
Um große Datenmengen zu transferieren, ist die Nutzung klassischer Netzwerkprotokolle, wie FTP oder HTTP in Verbindung mit TCP/IP empfehlenswert. TCP/IP
spaltet selbstständig große Dateien auf und stzt sie nach Ankunft am Empfänger
wieder aus den einzelnen Paketen zusammen. Das Bestreben ist es, möglichst große
Pakete zu bilden, um einem zu großen Overhead durch die Protokoll-Header entgegenzuwirken. Datenverkehr dieser Art hat meist eine niedrige Priorität.
3.1.5
Human-Machine-Interface
Die Überwachung einer Anlage geschieht meist von einem Rechner durch ein HumanMachine-Interface (HMI), welches den laufenden Prozess visualisiert und die Abfragemöglichkeiten von Mess- und Statusinformationen bietet. Weiterhin kann mit dem
31
3.1. Anforderungen
Kapitel 3. Analyse
HMI in einen Automatisierungsprozess eingegriffen werden, um z.B. Regelgrößen zu
justieren oder einen Nothalt auszulösen. Auch der Datei-Download bzw. -Upload
kann darüber angestoßen werden.
Die Informationen, die für die Überwachung eines Prozesses gebraucht werden, können sowohl nach dem Push, als auch nach dem Pull-Modell erfolgen. Ersteres kommt
hauptsächlich bei der Visualisierung zum Einsatz, wo zyklische Updates von Daten
nötig sind. Teilweise werden die Steuer- und Messdaten genutzt, die im Netz schon
für die Steuerung und Regelung des Systems propagiert werden. Rein für die Visualisierung benötigte Daten, werden in der Regel in größeren Intervallen mit niedrigerer
Priorität verteilt.
Einzelne Statusabfragen erfolgen in der Regel nach dem Pull-Modell, da diese nur
sporadisch benötigt werden. Als Reaktion auf eine Statusabfrage wird eine einzelne
Aktualisierung der letzten Statusinformationen erwartet.
Wird eine Visualisierung nicht durchgängig benötigt, so kann die Verteilung der rein
für diesen Zweck benötigten Daten nach dem Publish-Subscriber-Modell angestoßen
bzw. abgemeldet werden um Netzressourcen zu schonen.
Eingriffe in den Ablauf des Automationsprozesses erfolgt wiederum durch einzelne
Nachrichten, die an einzelne Rechner oder Rechnergruppen im Netz gerichtet sind.
3.1.6
Sonstige Anforderungen
Aufgrund des Automatisierungskontextes in dem diese Arbeit steht, ergeben sich
weitere Anforderungen an die Entwicklung der Kommunikationsschicht, die im Folgenden erläutert werden.
3.1.6.1
Entwicklung unter Linux
Die Entwicklung unter dem offenen Betriebssystem Linux wird aufgrund der Einbettung der Arbeit in ein Forschungs- und Entwicklungs-Thema des Labors für Verteilte
Systeme der FH Wiesbaden vorausgesetzt. Das Thema ”Real-Time Data Propagation in Distributed Environments” sieht eine Netzwerk-Kommunikationsschicht mit
QoS-Fähigkeit auf Basis des Linux-QoS-Frameworks vor.
32
Kapitel 3. Analyse
3.1.6.2
3.2. Kommunikationsformen und ihre QoS-Anforderungen
Portierbarkeit
In der Automation kommt eine Vielzahl von Embedded-PC-Architekturen zum Einsatz. Die Kommunikationsschicht sollte auf den meisten dieser Architekturen lauffähig sein. Dies kann gewährleistet werden, indem die von Linux gebotenen, Hardwareunabhängigen Schnittstellen genutzt werden. Damit würden alle Architekturen, die
Linux unterstützt, von der Kommunikationsschicht mit unterstützt werden.
Obwohl das Ziel der Arbeit eindeutig auf Ethernet ausgerichtet ist, soll auch eine
Portierung der Kommunikationsschicht auf andere Layer-2-Protokolle, wie Firewire
oder PPP, so einfach wie möglich sein.
3.1.6.3
Modularität
Die zu entwickelnde Software soll modular aufgebaut sein. Damit soll eine einfache
Portierung und Weiterentwicklung gewährleistet werden.
3.1.6.4
Performanz-Optimierung auf Senden und Empfangen
Für die Einhaltung von QoS ist ein reibungsloses und schnelles Senden bzw. Empfangen nötig. Daher muss bei der Entwicklung der Software eine Optimierung der
Performanz in Bezug auf den Sende- und Empfangsbetrieb vorgenommen werden.
3.2
Kommunikationsformen und ihre QoS-Anforderungen
Die in Abschnitt 3.1 vorgestellten Kommunikationsmuster stellen unterschiedliche
Anforderungen an die in Kapitel 2.1 definierten QoS-Parameter. In diesem Abschnitt
werden diese Anforderungen für die betreffenden Use-Cases erkläutert.
3.2.1
Steuern und Regeln
Mess- und Steuerwerte sind meist kritische Daten, bei deren Verlust der Zustand einer Anlage nicht definierbar ist. Daher stellt die Form der Kommunikation höchste
33
3.2. Kommunikationsformen und ihre QoS-Anforderungen
Kapitel 3. Analyse
Anforderungen an Dienstverfügbarkeit und Paketverlustrate. Die Dienstverfügbarkeit sollte so hoch wie möglich sein, wohingegen die Paketverlustrate bei Null liegen
sollte.
Um die Aktualität der Daten zu wahren, ist ein sehr geringer Delay notwendig, der
in vielen Fällen harten Echtzeitanforderungen standhalten muss. Handelt es sich
dabei um Daten mittlerer Priorität, ist auch ein höherer Delay tolerierbar.
Da es sich um isochron propagierte Daten handelt, wird ein geringer Jitter angestrebt, damit die Synchronität von Abläufen gewährleistet werden kann.
Die Anforderung an den Durchsatz eines isochron propagierten Datenstroms hängt
von der Paketgröße und dem Sende-Intervall ab. Jedoch sind diese Anforderungen
eindeutig bestimmbar, da die Paketgröße und das Sendeintervall in der Regel bekannt sind.
3.2.2
Alarm-Signalisierung
Für die Alarm-Signalisierung sind die Anforderungen an die Verfügbarkeit höher, als
die für Steuern und Regeln. Denn, fällt die Propagation von Mess- und Steuerdaten
aus, kann der Schaden durch schnelles Signalisieren eines Alarms noch begrenzt
werden, nicht jedoch, wenn gleichzeitig auch der Service für die Alarmsignalisierung
ausfällt. Genauso verhält es sich für die Paketverlustrate.
Um einen schnellstmöglichen Stop aller Vorgänge zu gewährleisten, muss die geringstmögliche Verzögerung erzielt werden, daher sind die Anforderungen an den
Delay sehr hoch.
Da es sich bei der Alarm-Signalisierung nur um die Propagation einzelner Pakete
handelt, bestehen praktisch keine Anforderungen an Jitter oder Durchsatz.
3.2.3
Datei-Download / Upload
Ein Datei-Download bzw. Upload hat recht geringe Anforderungen an Service-Availability und Paket-Verlust-Rate. Es ist zwar eine hohe Dienstverfügbarkeit erwünscht,
jedoch ist diese nicht kritisch für die Stabilität einer Anlage.
Noch unkritischer ist die Paket-Verlust-Rate, da verloren gegangene Pakete durch
TCP erneut gesendet werden.
34
Kapitel 3. Analyse
3.3. Einflussnahme auf die QoS-Parameter
Delay und Jitter sind ebenfalls nicht von kritischer Bedeutung für die Übertragung
von Dateien.
Allein der Durchsatz der Pakete ist von größerer Bedeutung, um Dateien so schnell
wie möglich zu übertragen. Dies gilt aber nur in dem Rahmen, in dem die Anforderungen der Kommunikationsmuster höherer Priorität nur geringfügig oder gar nicht
beeinflusst werden. Wobei auch hier ein hoher Durchsatz wünschenswert ist, um die
Belastung des Netzwerks zeitlich so kurz wie möglich zu halten.
3.2.4
Human-Machine-Interface
Die Überwachung und der Eingriff in den Automationsprozess erfolgen nach allen
bisher genannten Kommunikationsformen, jedoch teilweise nach eigenen Prioritäten.
Die ausschließlich zur Visualisierung benötigten Messdaten werden, wie Daten zum
Steuern und Regeln, isochron propagiert, jedoch in größeren Intervallen und mit
geringerer Priorität. Desweiteren ist deren Toleranz gegenüber Delay, Jitter und
Paket-Verlust weitaus größer.
Eingriffe in den Prozessablauf und Statusabfragen gleichen im Ablauf der Kommunikationsform der Alarmsignalisierung. Die Anforderungen an Delay und Paket-Verlust
hängen stark von der Art der Nachrichten und deren Priorität ab. Eine einfache Abfrage von Messdaten ist von weit geringerer Priorität, als ein vom HMI ausgelöstes
Alarmsignal. Die Änderung einer Stellgröße liegt in einem Bereich dazwischen.
Vom HMI ausgelöste Datei-Up- und Downloads haben genau die Anforderungen, die
für diesen Anwendungsfall definiert wurden.
3.3
Einflussnahme auf die QoS-Parameter
Um die einzelnen QoS-Parameter zu beeinflussen, und damit geforderte Grenzen
einhalten zu können, müssen zunächst deren Abhängigkeiten analysiert werden.
Für die Betrachtungen einzelner Parameter wird auf die, in [Jas02] verwandten,
analytischen Methoden zurückgegriffen, die aud [BT04] basieren. Diese beschreiben
das Worst-Case-Verhalten eines Netzwerkelements anhand einer Ankunftskurve und
einer Servicekurve. Alle hier verwendeten Betrachtungen gehen von einer konstanten
Paketgröße aus.
35
3.3. Einflussnahme auf die QoS-Parameter
Kapitel 3. Analyse
Die Ankunftskurve α(t) eines Elements, wie z.B. einer QDisc, ist eine stetig steigende
Funktion, die die eintreffenden Daten über die Zeit charakterisiert. Sie begrenzt den
Datenfluss R nach oben, wenn für alle Zeitpunkte u ≤ t gilt:
R(t) − R(u) ≤ α(t − u)
(3.1)
Eine einfache Möglichkeit die Ankunftskurve zu beschreiben, ist der Token-Bucket,
der durch die Parameter b für die Bucketgröße und r für die Abflussrate beschrieben
werden kann. Es wird bei der Verwendung der Ankunftskurve davon ausgegangen,
dass alle Daten eines Bursts gleichzeitig in der Queue eintreffen.
αr,b (t) = r · t + b
(3.2)
Der Parameter Bucketgröße gibt dabei die Größe von Bursts, bei angesammelten
Token, in [Bytes] oder [Paketen], an. Die maximale Ankunftsrate entspricht der
Abflussrate des Token-Buckets in [Bytes/s] oder [Pakete/s].
Die Servicekurve β(t) beschreibt, wann ein Paket in einem Element bedient wird.
Sie wird in den meisten Fällen in Form der ”rate latency function” dargestellt.
(
βR,T (t) = R[t − T ]+ =
R(t − T ) wenn t > T
0
wenn t ≤ T
(3.3)
R beschreibt die Rate in der Daten, die sich im System befinden abgearbeitet werden,
in [Bytes/s] oder [Pakete/s]. Der Parameter T stellt die maximale Latenz [s] des
Systems dar, bevor die ersten Daten abgearbeitet werden können.
Ankunfts- und Servicekurve werden anhand eines Beispiels in Abbildung 3.2 erklärt.
Das Beispielsystem stellt eine Queue mit FIFO-Charakteristik dar.
Die Ankunftskurve wird durch einen Tokenbucket begrenzt, dessen Parameter b
die maximale Paketgröße Lmax zugewiesen wird. Diese wird mit der Länge eines
maximal großen Frames, inklusive Präambel, Header, Frame-Check-Sequence und
Inter-Frame-Gap, angenommen und entspricht damit b = Lmax = 1538Byte. Präambel, Frame-Check-Sequence und Inter-Frame-Gap werden zwar erst in der Hardware
hinzugefügt [WPR+ 02], jedoch ist die Bedienungszeit der Pakete von deren Größe
abhängig. Um den maximalen, belegten Speicher in der Queue zu berechnen, sind
Präambel, Frame-Check-Sequence und Inter-Frame-Gap wieder abzuziehen.
Die Ankunftsrate r wird mit 25M Bit/s angenommen.
36
Kapitel 3. Analyse
3.3. Einflussnahme auf die QoS-Parameter
Abbildung 3.2: Service- und Ankunftskurve
Der Parameter R der Servicekurve entspricht der Linkkapaziät des Netzwerk-Devices
C = 100M Bit/s. Die Latenz T ist abhängig davon, wie schnell ein Paket über
die Queue durchgereicht werden kann. Angenommen das Durchlaufen der Queue
würde 1000 Instruktionen in Anspruch nehmen, dann würde die Queue auf einem
Prozessor mit 1GHz Taktfrequenz und einer Instruktion pro Takt eine Latenz von
1µs aufweisen.
Mit diesen Parametern lassen sich nun die folgenden Werte berechnen:
• die maximale Verweilzeit eines Pakets in der Queue.
• den maximal genutzten Speicher der in der Queue gehaltenen Pakete
Die Formel für die maximale Verweilzeit dmax in der Queue lautet:
dmax = T +
b
R
Der maximal belegte Speicher Bmax berechnet sich mit:
37
(3.4)
3.3. Einflussnahme auf die QoS-Parameter
Bmax = α(T ) = r · T + b1
Kapitel 3. Analyse
(3.5)
Das Ergebnis muss auf das nächste n-fache der Paketgröße aufgerechnet werden.
Durch Einsetzen ergeben sich folgende Werte:
dmax = 124, 04µs
Bmax = 3028Byte
3.3.1
Service Availability
Die Dienstverfügbarkeit ist stark abhängig von der Stabilität aller beteiligten Elemente. Es darf zu keinen Hardwareausfällen kommen. Die Software muss sorgfältig
programmiert sein, unter den Gesichtspunkten, dass Deadlock-Situationen um jeden
Preis zu verhindern sind.
Um die Dienstverfügbarkeit zu erhöhen, sind redundante Lösungen denkbar. Diese
sind jedoch nicht Schwerpunkt dieser Arbeit und sollen daher nicht weiter betrachtet
werden.
3.3.2
Packet Loss Rate
Pakete können aus zwei Gründen verloren gehen. Zum einen kann es bei der Übertragung eines Pakets zu Fehlern durch Störeinflüsse von außen kommen, wodurch das
Paket beim Empfang verworfen wird. Dem kann man durch Einsatz störungsarmer
Hardware, wie z.B. Kategorie 5 Kabel, entgegenwirken.
Die zweite Ursache ist das Überlaufen eines Puffers in einem Switch oder Host. In
einem Host kommt das nicht vor, solange der empfangende Prozess die Pakete schnell
genug abholt. In einem Switch werden Pakete mit einer höheren Wahrscheinlichkeit
verworfen. Treffen an zwei Ports eine Serie von Pakete mit dem gleichen Zielport ein,
und deren addierte Ankunftskurven liegen höher als die Servicekurve des Zielports,
beginnt sich die Ausgangsqueue des Ports mit Verweisen auf die gespeicherten Pakete
zu füllen. Geschieht das über einen längeren Zeitraum, so kann die Queue des Ports
1
b entspricht hier der maximalen Paketgröße inklusive Header, aber ohne Präambel, CRC und
IFG: 1514Byte
38
Kapitel 3. Analyse
3.3. Einflussnahme auf die QoS-Parameter
überlaufen. Daraufhin werden alle weiteren Pakete verworfen, bis wieder Platz zur
Aufnahme eines Zeigers zur Verfügung steht.
Um das zu verhindern, muss für die Menge aller Ports P gelten [Jas02]:
X
ri < R j
(3.6)
∀ i 6= j ∈ P
Bedingt durch die niedrige Ankunftsrate, können weiter auftretende Bursts abgebaut
werden können.
3.3.3
Delay
Die Garantie zur Einhaltung dieser Grenzen ist von verschiedenen Faktoren abhängig. Grob setzt sich der Delay aus drei Teilen zusammen: Delay im Sendeknoten,
auf dem Medium und im Empfängerknoten. Im Folgenden sollen alle Teile genauer
betrachtet werden.
3.3.3.1
Delay im Sendeknoten
Hier sind wiederum einzelne Elemente für unterschiedliche, variable und konstante
Anteile an der Gesamtlatenz beteiligt. Zum einen ist der Delay im Systemcall zu
betrachten, mit dem die zu versendenden Daten an das Betriebssystem übergeben
werden.
Linux-Systemcalls der Socket-Schnittstelle haben grundsätzlich eine vorhersehbare
Bearbeitungszeit, die von der Schnelligkeit der CPU abhängt. Da sie jedoch von
einem Aktivitätsträger im Kern unterbrochen werden können, ist der dadurch verursachte Delay nicht deterministisch. Das ist im Falle von Soft- und HardwareInterrupts recht unkritisch, da diese in der Regel nur aus ein paar Anweisungen
bestehen, nach deren Abarbeitung der Systsemcall weiter ausgeführt werden kann.
Problematisch kann es jedoch bei sogenannten Bottom-Halfs und Tasklets werden.
Dabei handelt es sich um asynchron auftretende Aktivitätsträger im Kern, die dazu
ausgelegt sind auch Tasks, die mehrere tausend Taktzyklen in Anspruch zu nehmen.
Diese können nur von Interrupts unterbrochen werden, sind jedoch dazu in der Lage Systemcalls zu unterbrechen. Das Problem könnte durch die Verwendung einer
Echtzeiterweiterung umgangen werden. Für weitere Informationen zu Tasklets und
Bottom-Halfs sei [BC02] empfohlen.
39
3.3. Einflussnahme auf die QoS-Parameter
Kapitel 3. Analyse
Das nächste Element, das den Delay beeinflusst, ist der Protokoll-Stack. Um diesen
Teil-Delay gering zu halten, besteht der Stack in der Automation nur aus Layer 1,
2 und 7. Daten, die nicht den Echtzeitanforderungen unterliegen und der vertikalen
Integration dienen, sollten die restlichen Layer weiterhin nutzen können.
Einen nicht unerheblichen Einfluss auf den Delay hat die verwendete Queueing Disziplin. Der Delay innerhalb der Queueing Disziplin sich lässt mit dem Ankunftsbzw. Servicekurven-Modell ermitteln, wenn folgende Rahmenbedingungen erfüllt
sind [Jas02]:
• Der Ankunftsprozess muss für jede Verbindung, d.h. sendende Quelle auf einer Station, charakterisiert werden können. Dies kann, wie oben
erläutert, durch den Einsatz eines Token Buckets erreicht werden. Dieser sollte
nach erwarteter Senderate und Paketgröße der Quelle dimensioniert werden,
um eine obere Grenze durchzusetzen. Überschreitet der Prozess diese Grenze, wird er mit einem erhöhten Delay durch den Token Bucket bestraft, nicht
jedoch die restlichen Quellen.
• Die maximale Paketgröße muss bestimmbar sein. Dies ist wichtig, da
der Worst-Case-Delay stark abhängig von der Paketgröße ist. Diese bestimmt
in Abhängigkeit mit der Linkkapazität, die Zeit, die es braucht um ein Paket
auf das Medium zu senden. Wird die Paketgröße klein gehalten, verkürzt sich
der Delay. In der Automation werden in der Regel kleine Pakete verschickt, die
Sensordaten enthalten. Durch die vertikale Integration von Netzwerkkommunikation aus dem Office-Bereich auf dem gleichen Netzwerksegment, besteht die
Gefahr, dass diese Pakete den Worst-Case-Delay alleine durch ihre Größe drastisch anheben. Dem kann durch ein Verkleinern der Maximum Transmission
Unit (MTU) am Netzwerktreiber entgegengewirkt werden.
• Die verwendeten Paket Scheduling Algorithmen müssen bekannt
sein. Durch das Wissen über die Algorithmen kann deren Verhalten durch das
Ankunfts-/Servicekurven-Modell berechnet werden. Dies ist durch die Queueing Disziplinen unter Linux gewährleistet.
Verwendet man die Prio Queueing Disziplin, so lassen sich nach den oben genannten Bedingungen Aussagen über den Worst-Case-Delay innerhalb der QDisc treffen.
Hierzu sind einige Definitionen nötig:
40
Kapitel 3. Analyse
3.3. Einflussnahme auf die QoS-Parameter
• Für Lmax wird ein Wert zwischen 84 und 1538Byte angenommen. In diesem
Rahmen bewegt sich die Größe eines validen Ethernet-Frames, wie er auf dem
physischen Medium gesendet wird.
• Die Prio QDisc besteht aus n Bändern, mit den aufsteigenden Prioritäten
i ∈ [0; n − 1], wobei 0 die niedrigste Priorität darstellt.
• Für jedes Band der Priorität i der Prio-QDisc existieren mi Quellen, für die
gelten mi ∈ N .
• Jede Quelle j wird durch einen eigenen Token-Bucket begrenzt, dessen BurstParameter bj auf die maximale Paketgröße Pmax festgelegt wird. Der Parameter
rj ist für jede Quelle unterschiedlich. Zum Ermitteln der Ankunftskurve αi des
Bandes i werden die Token-Bucket-Parameter jeder Quelle addiert.
bi =
X
bj = mi ∗ Pmax
(3.7)
rj
(3.8)
∀j∈mi
ri =
X
∀j∈mi
αi (t) = ri · t + bi
(3.9)
• Um Stausituationen zu vermeiden, dürfen die addierten Ankunftsraten der
Bänder mit der Priorität i > 0 nicht die Linkkapazität C übersteigen. Daher
gilt:
n−1 X
X
rj < C
(3.10)
i=1 ∀j∈mi
Betrachtet man nun das Band mit der höchsten Priorität, so gelten die Bedingungen
einer Queue mit FIFO-Charakteristik, wie sie oben schon betrachtet wurde. Da
ein Paket der höchsten Priorität immer gegenüber den Paketen niedriger Priorität
bevorzugt wird, kann es nur von einem gerade gesendeten Paket oder von Paketen
gleicher Priorität, die vor ihm eingetroffen sind, verzögert werden. Daher gilt für das
Band mit der höchsten Priorität die Formel 3.4.
Für alle Bänder niedrigerer Priorität gilt, dass die Ankunftskurven der höherprioren
Bänder zur eigenen hinzu addiert wird. Also gilt für alle Bänder:
41
3.3. Einflussnahme auf die QoS-Parameter
dmaxi = T +
Kapitel 3. Analyse
n−1
X
bj
j=i
R
(3.11)
Diese Formel lässt die konstanten Verzögerungen außer Acht, die durch die Ausführung des Codes im Betriebssystem verursacht werden. Diese muss durch Zeitmessungen im Kernel ermittelt werden.
Der Delay durch den Treiber nimmt nur einen sehr geringen Teil ein, da Treiber dazu
ausgelegt sind, die Daten schnellstmöglich an die Hardware zu übergeben. Daher ist
die Wahrscheinlichkeit einer Unterbrechung sehr gering.
Der Delay in der Hardware entsteht sowohl durch Hinzufügen von Präambel, SFD
und Frame-Check-Sequence, als auch durch die Zeit, die benötigt wird ein Paket
auf das Medium zu legen. Die Zeit um die Daten auf das Medium zu senden wird
durch seine Linkkapazität gegeben. Ein Fast-Ethernet-Interface (100MBit) sendet
12,5Byte/µs, was heißt, dass ein 1538Byte großes Paket in 123.04µs versendet wird.
3.3.3.2
Delay auf dem Medium
Der Delay auf dem Medium ist abhängig von sowohl der Signallaufzeit, und somit
der Länge der verwendeten Kabel, als auch der Anzahl und Verzögerung in den
Netzwerkvermittlungselementen.
Die Signallaufzeit in einem UTP-Kabel der Kategorie 5 beträgt V = 2 · 102 m/µs
[Hal96]. Dadurch ergibt sich folgende Formel für die Verzögerung Tp [µs]:
Tp =
S[m]
V [m/µs]
(3.12)
Zur Signallaufzeit addiert sich der Delay, der in den Netzwerkvermittlungselementen auftritt. Da sich der Umfang dieser Arbeit auf die Betrachtung von Ethernet
beschränkt, kommen hier nur zwei Typen dieser Elemente in Frage: Hubs und Switches.
Hubs sind keine Vermittlungselemente im eigentlichen Sinne, da sie das empfangene
Signal nur verstärken und auf allen Ports weiterleiten. Sie werden jedoch erwähnt,
da ihr Einsatz eine weitere Verzögerungszeit hinzu addiert. Der Standart IEEE 802.3
[IEE02] definiert zwei Klassen von Repeatern mit einer 100MBit Rate, die sich durch
unterschiedliche Verzögerungszeiten auszeichnen. Bei der Nutzung eines schnelleren
Klasse II Hub gilt: Delay ≤ 3.68µs.
42
Kapitel 3. Analyse
3.3. Einflussnahme auf die QoS-Parameter
Der Delay eines Switches setzt sich wiederum aus zwei Zeiten zusammen. Zum einen
die Zeit, die ein Switch benötigt, um ein Paket zu vermitteln, ohne dass QueueingEffekte eintreten. Diese Zeit ist vom jeweiligen Switch abhängig. Kommt es zum
Queueing, kann je nach verwendeten Paket Scheduling Algorithmus entweder die
Formel 3.4 oder 3.11 zur Anwendung kommen.
3.3.3.3
Delay im Empfangsknoten
Im Empfangsknoten kommen wieder die Verzögerungen in Hardware, Treiber und
Systemcall zum Tragen, mit den jeweiligen Abhängigkeiten. Paket Scheduling Algorithmen werden hier nicht verwendet.
3.3.4
Jitter
Der Jitter wird durch die variablen Aspekte im Delay bestimmt. Er entsteht bereits durch den sendenden Prozess, der niemals hundertprozentig isochron senden
kann. Dies kann durch den Einsatz eines entsprechenden Prozess-Schedulers und
fein-granularer Timer im Betriebssystem minimiert werden .
Einen großen Einfluss auf den Jitter hat der Protokoll-Stack. Daher wird er, wie
schon erwähnt, auf Layer 1, 2 und 7 reduziert.
Die in Linux implementierten Paket Scheduling Algorithmen können nur zum Eingrenzen von maximalem Delay eingesetzt werden. Pakete werden trotzdem weiterhin
zu den frühest möglichen Zeitpunkt gesendet. Daher bewegt sich der Jitter zwischen
dem Best- und dem Worst-Case-Delay.
Wird dennoch ein geringer Jitter benötigt, um z.B. für die Visualisierung eine konstante Bildwiederholrate zu erzielen, können die Daten am Empfänger gepuffert
werden, um dann mit geringem Jitter ausgelesen zu werden. Dies führt jedoch zu
einem Anstieg im Delay, was in dem Fall der Visualisierung durchaus akzeptabel
wäre.
3.3.5
Throughput
Der Durchsatz eines Datenstroms ist abhängig davon, wieviel Bandbreite von anderen Datenströmen verbraucht wird, und ist nach oben begrenzt durch die Linkkapazität des Netzwerk-Device. Um den Durchsatz eines Datenstroms zu sicheren
müssen die der restlichen Datenströme begrenzt werden.
43
3.4. API der Linux-Queueing-Disziplinen
3.4
Kapitel 3. Analyse
Application Programming Interface der LinuxQueueing-Disziplinen
In diesem Abschnitt soll beschrieben werden, wie aus Sicht einer Applikation, die
unter Linux zur Verfügung stehenden Queueing Disziplinen konfiguriert werden können. Es werden die für diese Arbeit benötigten QDiscs vorgestellt und deren Parameter erläutert.
Die Informationen über diese Schnittstellen sind zum größten Teil aus der Analyse der Linux-Kernel Quellen und der Quellen des Programms TC aus dem Paket
iproute2 gewonnen worden.
3.4.1
Kommunikation über Netlink-Sockets
Zur Konfiguration aus einer Applikation heraus stellt der Kernel Netlink-Sockets
bereit [WPR+ 02]. Diese sind das Kommunikationsmittel, mit dem man vom UserSpace aus mit dem Kernel in einen Dialog treten kann.
Die dafür erforderlichen Header-Dateien sind in Listing 3.1 dargestellt.
Quelltext 3.1: Erforderliche Header Dateien für Netlink-Kommunikation
# include
# include
# include
# include
# include
< sys / types .h >
< sys / socket .h >
< asm / types >
< linux / netlink .h >
< linux / rtnetlink .h >
Geöffnet werden Netlink-Sockets mit dem Systemcall socket(), dessen genaue Beschreibung der entsprechenden Manpage zu entnehmen ist. Als domain-Parameter
ist PF_NETLINK zu wählen, sowie für den type-Parameter SOCK_DGRAM oder SOCK_RAW
. In netlink.h sind verschiedene Protokolle definiert, die jeweils eine Schnittstelle
zu einem anderen Subsystem im Kernel repräsentieren. So bildet NETLINK_ROUTE
die Schnittstelle zu Routing und Netzwerk, NETLINK_FIREWALL zur Firewall und
NETLINK_ARPD zur ARP-Tabelle. Zum Manipulieren der Queueing-Disziplinen muss
als protocol-Parameter NETLINK_ROUTE eingetragen werden, dessen Definition in
rtnetlink.h enthalten ist.
Um mit dem Kernel zu kommunizieren, werden über die Systemcalls sendmsg()
und recvmsg() Netlink-Messages ausgetauscht. Zum Transport der Netlink-Messages
werden diese in die Struktur struct msghdr eingebettet, die im Folgenden erklärt
wird (Listing 3.2).
44
Kapitel 3. Analyse
3.4. API der Linux-Queueing-Disziplinen
Quelltext 3.2: Die
1
2
3
4
5
6
7
8
9
msghdr
Struktur
struct msghdr {
void
* msg_name ;
socklen_t
msg_namelen ;
struct iovec * msg_iov ;
size_t
msg_iovlen ;
void
* msg_control ;
socklen_t
msg_controlle n ;
int
msg_flags ;
};
Im Zeiger msg_name wird die Speicheradresse eines Adressierungsobjekts gespeichert,
dessen Größe in msg_namelen übergeben wird. Auf den Aufbau dieses Adressierungsobjekts wird in Abschnitt 3.4.2 eingegangen.
Der Daten-Member msg_iov ist ein Zeiger auf einen Vektor von iovec-Strukturen.
Eine Struktur nimmt die Basisadresse und Größe des Adressbereichs auf, in dem
sich die zu versendende Message befindet. In msg_iovlen wird die Anzahl der zu
versendenden Messages angegeben und nicht die Bytes, die der Zeiger einnimmt.
Listing 3.3 zeigt den Aufbau von struct iovec.
Quelltext 3.3: Die
1
2
3
4
iovec
Struktur
struct iovec {
void
* iov_base ;
size_t
iov_len ;
};
msg_control, msg_controllen und msg_flags können genutzt werden, um optionale,
Protokoll-spezifische Informationen zu übergeben. Für die Nutzung von NetlinkMessages werden sie nicht benötigt.
3.4.2
Addressierung der Netlink-Messages
Da die Kommunikation über Netlink-Sockets zwischen User-Prozessen und dem Kernel erfolgt, werden zur Addressierung die Prozess IDs genutzt. Zu diesem Zweck ist
in netlink.h die Struktur struct sockaddr_nl definiert, die in Listing 3.4 gezeigt
wird.
Quelltext 3.4: Die
1
2
3
4
5
6
sockaddr_nl
struct sockaddr_nl {
sa_family_t
nl_family ;
unsigned short nl_pad ;
__u32
nl_pid ;
__u32
nl_group ;
};
45
Struktur
3.4. API der Linux-Queueing-Disziplinen
Kapitel 3. Analyse
Als nl_family wird immer AF_NETLINK übergeben.
nl_pad füllt die Lücke zwischen nl_family und nl_pid bis zur nächsten 4-Byte-
Grenze auf.
In nl_pid wird die Prozess ID des Empfängerprozesses übergeben. Da von User-Seite
aus der Kernel der Empfänger ist, wird das Feld auf Null gesetzt 2 .
Es ist prinzipiell möglich in nl_group eine Multicast-Gruppenmaske zu übergeben
und so mehrere Prozesse zu adressieren. Wie dies genau funktioniert, war im Laufe
dieser Arbeit nicht in Erfahrung zu bringen.
3.4.3
Aufbau der Netlink-Messages
Der grundsätzliche Aufbau einer Netlink-Message wird in Abbildung 3.3 gezeigt und
anhand des Listings 3.5 erläutert.
Abbildung 3.3: Netlink-Message
In netlink.h ist die Struktur struct nlmsghdr (Listing 3.5) definiert, die die Daten
des Headers aufnimmt.
Quelltext 3.5: Die
1
2
3
4
5
6
7
nlmsghdr
Struktur
struct nlmsghdr {
__u32 nlmsg_len ;
__u16 nlmsg_type ;
__u16 nlmsg_flags ;
__u32 nlmsg_seq ;
__u32 nlmsg_pid ;
};
Das nlmsg_len Feld hält die Länge der Message inklusive Header und Attribute in
Bytes.
In nlmsg_type (Zeile 2) wird das Kommando eingetragen, das von dem Kernelsubsystem ausgeführt werden soll. Die zur Verfügung stehenden Kommandos sind vom
genutzten Netlink-Protokoll abhängig. Das NETLINK_ROUTE Protokoll enthält einen
2
Die PID des Kernel ist 0
46
Kapitel 3. Analyse
3.4. API der Linux-Queueing-Disziplinen
Satz von 27 Befehlen, von denen jedoch nur neun für die Konfiguration von QDiscs
relevant sind. Diese werden in Tabelle 3.1 zusammengefasst.
RTNetlink-Messagetyp
Bedeutung
RTM_NEWQDISC
Neue QDisc anlegen
RTM_DELQDISC
QDisc löschen
RTM_GETQDISC
QDisc-Parameter anfordern
RTM_NEWTCLASS
Neue Klasse anlegen
RTM_DELTCLASS
Klasse löschen
RTM_GETTCLASS
Klassenparameter anfordern
RTM_NEWTFILTER
Neuen Filter anlegen
RTM_DELTFILTER
Filter löschen
RTM_GETTFILTER
Filterparameter anfordern
Tabelle 3.1: RTNetlink-Kommandos
Die in nlmsg_flags (Zeile 3) einzutragenden Flags verfeinern die Kommandos in
Tabelle 3.1. Die zur Verfügung stehenden Flags sind in netlink.h definiert und
werden in Tabelle 3.3 zusammengefasst.
Message-Typ
Flag
Bedeutung
NEW-Messages
NLM_F_CREATE
Element wird erstellt,
falls es noch nicht existiert
Element wird nicht erstellt,
wenn es schon existiert
Überschreibe existierendes
Element
Hänge Element an das Ende der
Liste (Keine Angabe des Handles)
NLM_F_EXCL
NLM_F_REPLACE
NLM_F_APPEND
DEL-Messages
-
Tabelle 3.2: Flags für Netlink-Messages
In nlmsg_seq wird die Sequenznummer der Message in der Kommunikation zwischen
Kernel und User-Space-Applikation festgehalten.
Im Feld nlmsg_pid wird die Prozess ID des sendenden Prozesses eingetragen. Diese
47
3.4. API der Linux-Queueing-Disziplinen
Kapitel 3. Analyse
dient als Quelladresse, da im Addressierungsobjekt selbst keine solche vorgesehen
ist.
Message-Typ
Flag
Bedeutung
GET-Messages
NLM_F_ROOT
NLM_F_ATOMIC
Spezifiziere die Wurzel des
Elementbaums
Liefere alle passenden Elemente
zurück
Befehl ist nicht unterbrechbar
NLM_F_DUMP
(NLM_F_ROOT|NLM_F_MATCH)
NLM_F_REQUEST
Es handelt sich um eine
Request-Message
Multipart-Message
Wird durch NLMSG_DONE terminiert
Message-Quittierung
Kann Error-Codes enthalten
Echo-Message zu Überprüfung
der Kommunikation
NLM_F_MATCH
Alle Messages
NLM_F_MULTI
NLM_F_ACK
NLM_F_ECHO
Tabelle 3.3: Flags für Netlink-Messages (forts.)
3.4.3.1
Traffic-Control-Messages
Eine Traffic-Control-Message (Abbildung 3.4) mit angehängten Attributen wird als
Payload der Netlink-Message verschickt. Zur Bildung der Traffic-Control-Message
ist in rtnetlink.h die Struktur struct tcmsg (Listing 3.6) definiert.
Abbildung 3.4: Traffic-Control-Message
48
Kapitel 3. Analyse
3.4. API der Linux-Queueing-Disziplinen
Quelltext 3.6: Die
1
2
3
4
5
6
7
8
9
struct tcmsg {
unsigned char
unsigned char
unsigned short
int
__u32
__u32
__u32
};
tcmsg
Struktur
tcm_family ;
tcm_pad1 ;
tcm_pad2 ;
tcm_ifindex ;
tcm_handle ;
tcm_parent ;
tcm_info ;
Das Feld wird tcm_family (Zeile 2) laut der Definition in rtnetlink.h stets mit dem
Wert AF_UNSPEC belegt.
Die beiden Padding-Felder tcm_pad1 (Zeile 3) und tcm_pad2 (Zeile 4) werden auf den
Wert Null gesetzt. Sie dienen dazu, das tcm_ifindex-Feld auf die nächste 4-ByteGrenze zu schieben.
Im Feld tcm_ifindex (Zeile 4) wird der Index-Wert des betreffenden NetzwerkDevices übergeben. Es handelt sich dabei nicht um den Namen des Devices, sondern
dessen interne Identifizierungsnummer. Um den Index eines Netzwerk-Devices zu
ermitteln, wird der Systemcall ioctl() mit SIOCGIFINDEX als request-Parameter
genutzt. Zu näheren Informationen sei auf die Manpage netdevice(7) verwiesen.
Das Handle des jeweiligen Traffic-Control-Elements wird in tcm_handle (Zeile 5)
gespeichert. Wird als Handle Null angegeben, so wird dem Element ein Handle vom
Kernel zugewiesen.
In tcm_parent wird das Handle des Elternelements angegeben. Handelt es sich bei
dem zu konfigurierenden Element um die Root-QDisc, so ist als Elternelement entweder TC_H_ROOT oder TC_H_INGRESS anzugeben.
Die Verwendung des tcm_info-Feldes (Zeile 6) ist abhängig vom verwendeten MessageTyp, und ob es sich bei dem Ziel um eine QDisc, Klasse oder einen Filter handelt.
Wird mit RTM_GETQDISC oder RTM_GETTCLASS der Status einer Queueing Disziplin oder
Klasse abgefragt, nutzt der Kernel das Feld zur Übermittlung eines Teils der Statusinformationen. Welche das im einzelnen sind wurde in diese Arbeit nicht ermittelt.
Bei der Konfiguration von Filtern wird in den oberen 16 Bit des tcm_info-Feldes die
Priorität des Filters und in den unteren 16-Bit das Protokoll, das gefiltert werden
soll, an den Kernel übergeben. Darauf wird im Abschnitt 3.4.5 eingegangen.
Die Attribute die der jeweiligen Message angehängt werden, sind vom verwendeten
Element abhängig. Grundsätzlich ist in einem TCA_KIND-Attribut die Bezeichnung
des Elements als String zu übergeben. In linux/pkt_sched.h sind für alle QDiscs
49
3.4. API der Linux-Queueing-Disziplinen
Kapitel 3. Analyse
Strukturen definiert, die in den meisten Fällen im Attribut TCA_OPTIONS an den
Kernel übergeben werden. Alle Attribute, die zur Konfiguration eines Elements notwendig sind, werden in Abschnitt 3.4.4 bzw. 3.4.5 im Einzelnen erklärt.
Der Aufbau eines Attributes ist in Abbildung 3.5 dargestellt. In rtnetlink.h sind
Makros zur Erstellung und Bearbeitung von Attributen definiert.
Abbildung 3.5: Attribute einer Traffic-Control-Message
3.4.4
Verfügbare Queueing Disziplinen
Unter Linux-Kernel 2.6 existieren 13 verschiedene Queueing Disziplinen, von denen
acht klassenlos und fünf klassenbehaftet sind. Die meisten lassen sich für die Zwecke
dieser Arbeit nicht verwenden, da sie entweder den Anforderungen von Automatisierungskommunikation zuwiderlaufen oder für die Arbeit auf höheren Protokollschichten ausgelegt sind. So verwirft Random Early Detection zufällig gewählte Pakete,
um den Durchsatz fair über alle Verbindungen hinweg zu drosseln, und DSMark,
der vollwertigen Implementierung von DiffServ, ist auf das DS-Feld im IP-Header
angewiesen. Im Folgenden sollen die für diese Arbeit relevanten Queueing Disziplinen erläutert werden. Die in den Überschriften, in Klammern, angegebenen Namen
entsprechen den Namen der jeweiligen QDisc, mit dem sie in dem TCA_KIND-Attribut
an den Kernel übergeben werden müssen.
3.4.4.1
First-In-First-Out (bfifo, pfifo, pfifo fast)
Bei diesen Queueing Disziplinen handelt es sich um verschiedene Implementierungen
des FIFO-Algorithmus. Der einzige Unterschied zwischen bfifo und pfifo besteht
darin, dass die Größe der Queue bei bfifo Byte und bei pfifo in Paketen berechnet
wird. Die pfifo fast-QDisc stellt einen Spezialfall dar. Sie besteht eigentlich aus drei
FIFO-Queues, die nach den Strict-Priority-Algorithmus abgearbeitet werden. Die
Zuordnung der Pakete, zu den Queues richtet sich nach dem DS-Feld im IP-Header.
50
Kapitel 3. Analyse
3.4. API der Linux-Queueing-Disziplinen
pfifo fast ist die Default-QDisc für alle Netzwerk-Devices und Blattklassen einer
QDisc, wenn für diese keine QDisc explizit konfiguriert wurde. Der einzige Parameter
dieser QDiscs ist die Größe der Queue in Byte für bfifo und in Paketen für pfifo und
pfifo fast. Er kann nur indirekt mit dem Befehl ifconfig <device> txqueuelen <len>
konfiguriert werden. Bei einem Überfüllen der Queue, werden alle nachkommenden
Pakete verworfen, bis wieder ein Platz für ein weiteres Paket frei ist.
Die anderen beiden Varianten lassen sich hingegen über die Netlink-Messages konfigurieren. Die Struktur struct tc_fifo_qopt enthält den Parameter limit mit dem
die Größe der Queue, je nach Variante, in Bytes oder in Paketen übergeben wird.
Die Struktur wird im Attribut TCA_OPTIONS an die Netlink-Message angefügt.
3.4.4.2
Stochastical Fair Queueing (sfq)
Die Stochastical Fair Queue verhält sich wie ein Round Robin Algorithmus, indem
sie die zur Verfügung stehende Bandbreite unter allen Verbindungen (Flows) aufteilt und sie auf mehrere interne Queues verteilt. Eine Verbindung wird durch eine
TCP/UDP-Port Nummer klassifiziert, dies macht die QDisc zwar für die Automationsspeziefischen Zwecke ungeeignet, sie ist jedoch gut einsetzbar um den Best-EffortVerkehr auf den höheren Protokoll-Ebenen fair zu halten.
Die SFQ besitzt eine Reihe von Parametern, mit der sie beeinflusst werden kann.
Diese sind in der Struktur tc_sfq_qopt (Listing 3.7) zusammengefasst.
Quelltext 3.7: Die
1
2
3
4
5
6
7
tc_sfq_qopt
Struktur
struct tc_sfq_qopt {
unsigned quantum ;
int
perturb_period ;
__u32
limit ;
unsigned divisor ;
unsigned flows ;
};
Der Parameter quantum legt die Anzahl Bytes fest, die ein Flow senden darf, bevor
der nächste an der Reihe ist.
Da insgesamt 65535 verschiedene Port-Nummern existieren, ist es nicht optimal
für jeden Flow eine eigene Queue zu verwalten. Deshalb wird nur eine begrenzte
Anzahl Queues angelegt, auf die dann alle Flows verteilt werden. Treten mehr Flows
auf, als Queues vorhanden sind, werden sie doppelt belegt. Um eine statistische
Fairness zu ermöglichen, werden die Flows nach einer Zeit umsortiert. In welchen
51
3.4. API der Linux-Queueing-Disziplinen
Kapitel 3. Analyse
Sekundenintervallen das geschehen soll, wird im Paramter perturb_period festgelegt.
Wird der Parameter nicht gesetzt, findet keine Umsortierung statt.
Die letzten drei Parameter sind zur Zeit dieser Arbeit fest in den Code der QDisc
einkompiliert und können nicht beeinflusst werden. limit legt die Queue-Größe und
flows die Anzahl der Queues fest. Bei divisor handelt sich um einen Hash-Divisor.
3.4.4.3
Prio (prio)
Die Prio-QDisc ist die Implementierung des Strict Priority Algorithmus. Sie besteht
aus einer Reihe von Klassen, die je eine Prioritätsstufe darstellen. Dabei stellt, im
Gegensatz zur Wertigkeit des User-Priority-Feldes im VLAN-Tag, der Wert 0 die
höchste Priorität dar.
Um eine Prio-QDisc zu konfigurieren, wird die tc_prio_qopt-Struktur im TCA_OPTIONS
-Attribut an die Netlink-Message angehängt.
Quelltext 3.8: Die
1
2
3
4
tc_prio_qopt
Struktur
struct tc_prio_qopt {
int
bands ;
__u8 priomap [ TC_PRIO_MAX +1];
};
Im Parameter bands wird die Anzahl der Klassen angegeben, die die QDisc enthalten
soll. Diese werden beim Erzeugen der QDisc automatisch mit erschaffen, und erhalten ein Handle mit einer Minor-Nummer entsprechend der Priorität, inkrementiert
um eins. Bis zu 16 Klassen können auf diese Weise erzeugt werden, jedoch können
keine Klassen nachträglich erzeugt werden.
Sind keine Filter für die QDisc konfiguriert, so werden Pakete über ein PrioritätsMapping klassifiziert, bei dem die Socket-Priorität auf die entsprechende Klasse
abgebildet wird. Diese Map wird über den Parameter priomap übergeben. Dieser besteht aus einem Array von 16 Werten, bei der die Einzelnen Positionen der SocketPrioritäten entspricht. Als Werte werden an den Positionen die Prioritäten der Klassen eingetragen.
3.4.4.4
Hierarchical Token Bucket (htb)
Der Hierarchical Token Bucket(HTB) stellt eine klassenbehaftete Implementierung
des Token Bucket Flow Algorithmus dar. Nicht der QDisc selbst, sondern ihren
52
Kapitel 3. Analyse
3.4. API der Linux-Queueing-Disziplinen
Klassen werden Burst- und Rate-Parameter zugewiesen. Die Klassen können in beliebigen Baumstrukturen angeordnet werden, wobei die Parameter der Kindklassen
nicht die der Elternklassen übersteigen dürfen. Hat eine Elternklasse mehr Bandbreite zur Verfügung, als die Kindklassen verbrauchen, so kann die Bandbreite auf
die Kindklassen verteilt werden, solange diese unter einem maximalen Grenzwert
bleiben.
Die Verteilung der Bandbreite an die Kindklassen erfolgt als Sendezeit, gemessen
in der internen Einheit ”Ticks”. Die folgenden Informationen zur Umrechnung von
Microsekunden nach Ticks und zurück, stammt aus einer E-Mail-Korrespondenz mit
Stephen Hemminger, einem Mit-Autor der iproute2-Utilities. In der Datei /proc/net/psched sind zwei Variablen eingetragen, t2us und us2t, die als hexadezimale
Werte ausgelesen werden können. Der erste Wert in der Datei entspricht der Variablen t2us und der zweite der Variablen us2t. Welche Bedeutung die beiden anderen
Werte haben, konnte nicht ermittelt werden. Möchte man die Ticks pro Microsekunde ausrechnen, dividiert man t2us durch us2t.
Um die benötigten Ticks für eine bestimmte Paketgröße zu ermitteln, verwaltet jede
Klasse intern zwei Rate-Tabellen mit je 256 Einträgen, die die Anzahl der von einem Paket verbrauchten Token auf die benötigten Ticks abbilden. Die Tabelle rtab
gilt dabei für die konfigurierte Mindestrate und die Tabelle ctab für die Maximalrate, die nicht überschritten werden darf, unabhängig davon, wieviel Bandbreite der
Elternklasse noch zur Verfügung steht.
Da die Tabellen nur 256 Einträge enthalten, nimmt ein maximal großes Paket 256
Token ein. Um die Größe eines Tokens zu ermitteln teilt man die maximale Paketgröße [Byte] durch 256 und rundet zu nächsten 2er Potenz auf.
Ein Eintrag Ei in eine Rate-Tabelle mit der Tokengröße T und der Rate R wird wie
folgt berechnet:
Ei = (
i · T [Byte]
) · T icks[ticks/µsec]
R[Byte/µs]
(3.13)
Um die QDisc zu konfigurieren wird die nachstehend beschriebene Struktur tc_htb_glob
genutzt. Jedoch wird sie nicht, wie bei anderen QDiscs im TCA_OPTIONS-Attribut versendet, sondern in einem eigenen TCA_HTB_INIT-Attribut. Das TCA_OPTIONS-Attribut
wird jedoch als leeres Attribut davor eingefügt.
53
3.4. API der Linux-Queueing-Disziplinen
Quelltext 3.9: Die
1
2
3
4
5
6
7
8
struct tc_htb_glob {
__u32
__u32
__u32
__u32
__u32
Kapitel 3. Analyse
tc_htb_glob
Struktur
version ;
rate2quantum ;
defcls ;
debug ;
direkt_pkts ;
};
Der Parameter version dient zum Versionsabgleich zwischen Software und verwendeter HTB-Version, da neue Versionen des TC-Programms nicht mit alten HTBVersionen kompatibel sind. Für die im Rahmen dieser Arbeit genutzten QDisc muss
Versionsnummer 3 angegeben werden.
rate2quantum ist eine Berechnungsgröße für die Zuteilung von überschüssiger Band-
breite. Diese wird als Quantum nach einem Weighted Round Robin Algorithmus
von Eltern an die Kindklassen weitergegeben. Wird beim Erzeugen einer Klasse ein
Quantum nicht explizit angegeben, so wird es durch Division ihrer Rate durch den
rate2quantum-Wert ermittelt. Der Default-Wert für rate2quantum beträgt 10.
In defcls wird die Minor-Nummer der Klasse angegeben, die Pakete aufnehmen soll,
die nicht durch einen Filter klassifiziert werden konnten. Wird kein Wert angegeben, so entspricht er null, was bedeutet, dass unklassifizierte Pakete aus der QDisc
herausfallen und mit der vollen Linkkapazität bedient werden.
Der debug-Parameter nimmt Debug-Level Informationen auf. Leider konnte im Rahmen dieser Arbeit nicht ermittelt werden, wie diese anzugeben sind.
Der Parameter direkt_pkts gibt die Anzahl der Pakete an, die an der HTB-QDisc
direkt bedient wurden, wenn bei der Konfiguration keine Default-Klasse angegeben
wurde. Dieser Parameter wird bei Statusabfragen vom Kernel befüllt.
Um eine Klasse eines HTB zu konfigurieren, wird eine die tc_htb_opt benutzt. Um
einige der Parameter erklären zu können, muss jedoch zuerst näher auf eine andere Struktur eingegangen werden. Mit der tc_ratespec-Struktur werden Datenraten
spezifiziert, die zur Konfiguration der Klassen nötig sind. Es werden jedoch nicht
alle Parameter der Struktur benötigt.
54
Kapitel 3. Analyse
3.4. API der Linux-Queueing-Disziplinen
Quelltext 3.10: Die
1
2
3
4
5
6
7
8
tc_ratespec
Struktur
struct tc_ratespec {
unsigned char
cell_log ;
unsigned char
__reserved ;
unsigned short feature ;
short
addend ;
unsigned short mpu ;
__u32
rate ;
};
Der Parameter cell_log ist der binäre Logarithmus der Tokengröße. Mit ihm kann
man durch eine einfache Bitshift-Operation die Anzahl Token für ein Paket, und
somit dessen Sendezeit in den rtab- und ctab-Tabellen ermitteln.
rtab [ pkt_size > > cell_log ] = pkt_xmit_time ;
Die Paramter __reserved, feature und addend werden zur Konfiguration der HTBKlasse nicht genutzt.
mpu ist die Minimum Packet Unit, also die Mindestgröße eines Pakets. Für alle
Einträge in einer der Rate-Tabellen, deren Paketgröße kleiner wäre als mpu, wird
zur Berechnung der Paketsendezeit der Wert von mpu verwendet.
Der rate-Parameter ist die Datentransferrate, angegeben in Bytes pro Sekunde.
Die tc_htb_opt-Struktur wird wie bei der QDisc nicht im TCA_OPTIONS-Attribut, sondern in dessen Anschluss in einem eigenen Attribut namens TCA_HTB_PARMS gesendet.
Im Folgenden werden die einzelnen Parameter erklärt.
Quelltext 3.11: Die
1
2
3
4
5
6
7
8
9
struct tc_htb_opt {
struct tc_ratespec
struct tc_ratespec
__u32
__u32
__u32
__u32
__u32
};
tc_htb_opt
Struktur
rate ;
ceil ;
buffer ;
cbuffer ;
quantum ;
level ;
prio ;
Die Parameter rate und ceil geben die Mindest- bzw. Maximalrate an, die der
Klasse zur Verfügung stehen sollen. Dabei ist zu beachten, dass die beiden Parameter
für eine Klasse, deren Elternknoten die QDisc ist, gleich sind.
Über die beiden Parameter buffer und cbuffer wird die Menge an Sendezeit eingestellt, die eine Klasse ansammeln und als Burst versenden kann. buffer ist also der
55
3.4. API der Linux-Queueing-Disziplinen
Kapitel 3. Analyse
Burst-Parameter für rate und cbuffer für ceil. Die Werte für die Parameter werden als benötigte Sendezeit für die Größe bei der entsprechenden Rate übergeben.
Durch den Timer-Takt von 1ms ergibt sich Mindestwert für buffer. In Byte wird
dieser wie folgt berechnet:
b = rate/1000Hz
(3.14)
Das würde für eine Klasse deren Rate 1200000Byte/s beträgt einen Burst-Wert
von mindestens 1200Bytes haben muss um seine Rate erreichen zu können. Das ist
jedoch bei kleinen Paketen nicht unbedingt erwünscht. Daher kann laut [Hub03] der
Paramter cbuffer genutzt werden, um den Burst weiter nach unten zu beschränken.
Der quantum-Parameter bestimmt wie groß der Anteil an überschüssiger Bandbreite
ist, den die Klasse im Verhältnis zu den Geschwisterklassen abbekommt. Wird der
Parameter nicht angegeben, wird er durch den rate2quantum Divisor der QDisc
bestimmt.
Die Verwendung des Parameters level ist nirgendwo dokumentiert, und auch das
Programm TC stellt diese Option nicht bereit.
Die überschüssige Bandbreite der Elternklassen wird nach dem Weighted Round
Robin Algorithmus auf die Kindklassen verteilt. Die Reihenfolge in der sie verteilt
werden, wird durch den prio-Parameter bestimmt. Der Wert liegt im Intervall [0; 7],
wobei 0 die höchste Priorität darstellt.
Nach dem TCA_HTB_PARMS-Attribut müssen noch die Attribute TCA_HTB_RTAB und
TCA_HTB_CTAB angefügt werden. Diese enthalten die beiden Tabellen rtab und ctab,
deren Inhalt mit der Formel 3.13 berechnet wird.
3.4.5
Filter
Die Konfiguration von Filtern funktioniert genauso, wie die Konfiguration von Klassen und QDisc, jedoch mit ein paar Besonderheiten. Zunächst ist da der Aufbau
der Handles zu erwähnen. Dieser ist nicht, wie bei Klassen und QDiscs, einheitlich,
sondern von dem jeweils verwendeten Filtertyp abhängig. Daher soll weiter unten
darauf eingegangen werden, wo der verwendete Filter näher erklärt wird.
Elternknoten eines Filters kann jede klassenbehaftete Queueing Disziplin sein, oder
eine ihrer Klassen. Passiert ein Paket diesen Knoten, wird eine Klassifizierung durchgeführt.
56
Kapitel 3. Analyse
3.4. API der Linux-Queueing-Disziplinen
Eine weitere Besonderheit ist die Nutzung des tcm_info-Feldes in der tcmsg-Struktur
(Listing 3.6). Ihm wird die Information über Priorität des Filters und des zu filternden Protokolls zugewiesen. Der Prioritätswert liegt im Intervall [0; 7], mit 0 als höchster Priorität, und bestimmt die Reihenfolge die Filter mit dem gleichen Elternknoten aufgerufen werden. Filter mit gleicher Priorität werden in der Reihenfolge
aufgerufen, in der sie erzeugt wurden.
Das zu filternde Protokoll entspricht einem gültigen Protokolltyp, wie er im TypeFeld des Ethernet-Headers vorkommt. Definierte Werte sind in der Header-Datei
linux/if ether.h enthalten. Durch den Protokoll-Wert wird eine Art Vorfilterung vorgenommen. Sollen alle Protokolle berücksichtigen werden, muss der Wert ETH_P_ALL
(0x0003) verwendet werden.
Der Prioritätswert nimmt die oberen 16-Bit des tcm_info-Feldes ein und das Protokoll die unteren.
3.4.5.1
Der U32-Filter
Die meisten zur Verfügung stehenden Filter filtern nach speziellen Merkmalen, die
entweder eine höhere Protokollschicht voraussetzen (DSMark) oder vom RoutingModul am Socket-Buffer vorgenommene Markierungen (fw, route) benötigen. U32
filtert zwar prinzipiell nach Mustern in höheren Protokollschichten, ist jedoch so
flexibel, dass er mit einem Trick 3 so konfiguriert werden kann, dass er nach Feldern
im Ethernet-Header filtert.
Grundsätzlich besteht der Filter aus einer Reihe von Schlüssel-, Maske-, OffsetDatensätzen, mit denen Muster in einem Paket erkannt werden können. Schlüssel
und Maske decken je 32 Bit ab und können durch den Offset in 4Byte-Schritten jedes
Muster an jeder Stelle, innerhalb der Payload des Ethernet-Headers, erkennen. Der
Offset beginnt ab dem Ende des Ethernet-Headers. Handelt es sich dabei um einen
VLAN-Tagged-Frame, beginnt der Offset zwischen dem Tag Protocol Identifier und
der Tag Control Information. Soll jedoch ein Feld im Ethernet-Header selbst erkannt
werden, so kann ein negativer Offset genutzt werden.
Um zum Beispiel die Zieladresse eines Ethernet-Frames zu filtern, müssen zwei Datensätze angelegt werden, da die vollständige Adresse nicht von 32-Bit abgedeckt
werden kann. Der erste Datensatz hätte als Schlüssel die obersten zwei Byte der
Adresse, eine Maske mit dem Wert 0x00FF und ein Offset von -16. Der Schlüssel
3
Dieser Trick wurde von den Entwicklern vorgeschlagen
57
3.4. API der Linux-Queueing-Disziplinen
Kapitel 3. Analyse
des zweiten Datensatzes würde die restlichen vier Bytes der Adresse enthalten, die
Maske hätte den Wert 0xFFFF und der Offset wäre -12.
Das Handle des U32-Filters ist in drei Segmente unterteilt. Die oberen 12 Bit nimmt
die ID einer Hash-Tabelle ein, die erzeugt wird, sobald an einem Elternknoten ein
neuer Filter mit einer Priorität angelegt wird, die bisher kein Filter an diesem Knoten besitzt. Die Hash-Table-IDs werden nach diesem Prinzip automatisch vergeben,
beginnend bei dem Wert 0x800. Diese ID ist eindeutig für den Elternknoten, an dem
der Filter konfiguriert wurde.
Die unteren 12 Bit nehmen das eigentliche Handle auf, das für die Hash-Tabelle
eindeutig sein muss. Die mittleren acht Bit stehen einem Hash-Wert zur Verfügung.
Zur Zeit dieser Arbeit ist jedoch kein Anwendungsfall aufgetreten, wo dieser benötigt
wurde, weshalb dessen Bedeutung nicht weiter nachgegangen wurde.
Um den U32-Filter anzulegen, müssen wie bei Klassen und QDiscs Attribute an die
Netlink-Message angefügt werden. Das erste Attribut ist TCA_KIND mit der Filterkennung ”u32” als String, gefolgt von einem leeren TCA_OPTIONS-Attribut.
Danach wird im Attribut TCA_U32_CLASSID das vollständige Handle der Zielklasse
untergebracht, welche nicht zwingend zu der gleichen Elternklasse oder -qdisc angehören muss, wie der Elternknoten des Filters.
Als letztes folgt das Attribut TCA_U32_SEL, in dem der Selektor des Filters untergebracht wird. Der Selektor wird aus zwei Strukturen gebildet: der tc_u32_selStruktur (Listing 3.12) und einem Array von tc_u32_key-Struktur (Listing 3.13).
Beide Strukturen sollen im Folgenden erläutert werden.
Quelltext 3.12: Die
1
2
3
4
5
6
7
8
9
10
11
12
13
14
tc_u32_sel
Struktur
struct tc_u32_sel {
unsigned char
flags ;
unsigned char
offshift ;
unsigned char
nkeys ;
__u16
__u16
short
offmask ;
off ;
offoff ;
short
__u32
hoff ;
hmask ;
struct tc_u32_key keys [0];
};
Das einzige relevante Flag das in flags gespeichert wird, ist das TC_U32_TERMINAL,
58
Kapitel 3. Analyse
3.4. API der Linux-Queueing-Disziplinen
das gesetzt werden muss, wenn das TCA_U32_CLASSID-Attribut in der Message enthalten ist.
Den Verwendungszweck der Parameter offshift, offmask, off, offoff, hoff und
hmask wurde im Laufe dieser Arbeit nicht ermittelt, da sie zum Einsatz in dessen
Rahmen nicht benötigt werden.
Der Parameter nkeys gibt die Anzahl der folgenden tc_u32_key-Strukturen an.
Der keys Parameter ist ein Zeiger auf den nachfolgenden Speicherbereich, in dem das
Array der tc_u32_key-Strukturen angelegt wird. Dieses Array bildet die Datensätze,
die zum erkennen der Muster benötigt werden.
Quelltext 3.13: Die
1
2
3
4
5
6
tc_u32_key
Struktur
struct tc_u32_key {
__u32 mask ;
__u32 val ;
int
off ;
int
offmask ;
};
Im mask-Parameter wird die 32-Bit Maske gespeichert, mit der durch eine ANDOperation die nicht zu betrachtenden Bits ausgeblendet werden.
Der Parameter val nimmt den Schlüssel auf.
off stellt den Offset für den Schlüssel dar. Dieser kann nur in 4-Byte-Schritten
angegeben werden.
Mit dem Parameter offmask wird bestimmt, ab welcher Position der Offset des
Musters gemessen wird. Ist der Parameter 0, wird der Offset ab dem Ende des
Ethernet-Headers gemessen, ist er -1, so wird er ab dem Beginn des nächsthöheren
Headers gemessen.
Wird eine Queueing Disziplin oder Klasse gelöscht, so werden automatisch alle Filter, deren Elternknoten sie ist, ebenfalls gelöscht. Ist das so erwünscht müssen für
die Erzeugung des Filter nicht notwendigerweise Priorität und Handle angegeben
werden. Soll jedoch ein Filter gezielt gelöscht werden muss dieser eindeutig identifizierbar sein. Dazu ist die Angabe des Handles des Elternkotens, des Handles des
Filters inklusive Hash-Table-ID, dessen Priorität und die Art des Filters in einem
TCA_KIND-Attribut nötig.
59
3.5. Designentscheidungen
3.5
3.5.1
Kapitel 3. Analyse
Designentscheidungen
Statische Verkehrscharakteristik
Es wird, aufgrund der heute in der Regel statischen Verkehrscharakteristik einer Automationsumgebung, auf eine dynamische Allokation der QoS-Parameter verzichtet.
Jedoch soll die entwickelte Software in Hinblick auf eine Erweiterung auf dynamische
Umgebungen offen sein.
3.5.2
Linux ohne Echtzeiterweiterung
Echtzeiterweiterungen für das Linux-Betriebssystem nutzen die Kern-im-Kern-Architektur. Dabei setzt sich der Echtzeit-Kern der Erweiterung zwischen das InterruptSystem des Rechners und den Linux-Kern. Der Linux-Kern greift auf ein simuliertes
Interrupt-System des Echtzeit-Kerns zurück, hat aber noch vollen Zugriff auf alle
seine Treiber.
Echtzeitanwendungen laufen als Module im Kern-Adressraum und haben dadurch
keinen Zugriff auf die Systemcall-Schnittstellen des Betriebssystems. Zugriff auf die
Hardware, muss durch eigene Treiber realisiert werden.
Eine solche Echtzeitanwendung könnte das vom Linux-Kern bereitgestellte QoSFramework nicht nutzen. Daher wird auf den Einsatz einer Echtzeiterweiterung verzichtet.
Zur Zeit ist für die Echtzeiterweiterung RTAI eine experimentelle Entwicklung nahmens RTAI/fusion in Arbeit. Diese soll einen kurzzeitigen Wechsel von der RTAIin die Linux-Domäne ermöglichen, um deren Systemschnittstellen zu nutzen. Dies
bringt aber auch einen Verlust des Determinismus für diesen Zeitraum mit sich.
3.5.3
Einsatz von Switches
Um den Determinismus für Ethernet zu erreichen, soll eine Microsegmentierung des
Netzwerks durch Switches durchgeführt werden. Die eingesetzten Switches sollen
802.1p-fähig sein und über Ports mit mindestens vier Ausgangsqueues verfügen, die
nach dem Strict-Priority-Algorithmus bedient werden.
60
Kapitel 4
Konzept
4.1
Grobentwurf
Um verschiedene Kommunikationsformen mit verschiedenen QoS-Eigenschaften, wie
sie in Kapitel 3.2 besprochen wurden, unterscheiden zu können, bedarf es einer logischen Einteilung der Netzwerkressourcen. Der Kommunikationsschicht liegt ein
Modell zugrunde, welches das Medium logisch in bidirektionale Kanäle mit eigenen
QoS-Eigenschaften einteilt. Jeder Kanal entspricht einer Multicastgruppe mit zwei
oder mehr Teilnehmern. Damit lässt sich jede Kommunikationsform aus Kapitel 3.2
unterstützen. Isochrone Propagation von Messdaten erfordert ohnehin MulticastBetrieb. Gezielte Adressierung einer Station erfordert einen eigenen Kanal mit zwei
Teilnehmern. Dies ist unproblematisch, da davon ausgegangen wird, dass alle Kommunikationspfade vor der Inbetriebnahme der Anlage bekannt sind. Auch die Anmeldung und Abmeldung von Publish-Subscriber-Listen, wie sie in Abschnitt 3.1.5
erwähnt wurden, ist durch das Modell unterstützt, auch wenn deren Implementierung höheren Protokollschichten überlassen wird.
Abbildung 4.1 zeigt ein konzeptionelles Klassenmodell, an dem das Grobkonzept
weiter beschrieben wird.
Um über einen Kanal kommunizieren zu können, muss von einem Prozess ein Kanalendpunkt (Channel ) geöffnet werden. Dem Kanalendpunkt sind lokale QoS-Eigenschaften zugewiesen, die so gewählt sind, dass die QoS-Eigenschaften des Kanals
gewahrt werden. Es wird angenommen, dass lokalen Parameter vor der Inbetriebnahme der Anlage durch eine Scheduability-Analyse ermittelt und über eine Konfigurationsdatei eingelesen werden.
61
4.1. Grobentwurf
Kapitel 4. Konzept
Abbildung 4.1: Konzeptionelles Klassenmodell
Ein Kanal wird über eine ID eindeutig identifiziert; diese wird bei jeder Interaktion
angegeben. Eine Kanal ID wird auf eine Layer-2-Multicast-Adresse abgebildet.
Für bestimmte Kanäle, wie einen Alarm-Kanal, ist es notwendig, dass mehr als ein
Prozess eines Rechners auf den Kanal zugreifen kann. Für diesen Fall wird mit einem Sychronisationsobjekt(Sync) der wechselseitige Ausschluss beim Senden durchgesetzt.
Die Kommunikation erfolgt über Packet-Sockets (Kapitel 2.3.1), um den TCP/UDP/IP-Stack zu umgehen.
Die Adressierung ist vom verwendeten Device (Physical Device) und dessen Layer-2Protokoll abhängig. Diese wird vorgenommen, während der Kanalendpunkt an das
Device gebunden wird.
Um die Klassifizierung von Paketen durchzuführen, werden bei Initialisierung des
Devices zwei VLANs erzeugt: Eins für die Kanal-Konfigurationsschicht und ein anderes um die vertikale Integration durchzusetzen. In dem virtuellen Device der Kanäle werden die Socket-Prioritäten eins zu eins auf die User Priority des VLAN-Tags
abgebildet. Verkehr, der über das virtuelle Device für den Best-Effort-Verkehr gesendet wird, bekommt eine Standard-Priorität von 1 zugewiesen, was wie in 2.1.1
besprochen wurde, der niedrigsten Priorität entspricht.
Die Konfiguration der Queueing-Disziplinen, entsprechend der Kanal-Parameter,
wird durch einen QoS-Controller vorgenommen. Dieser nimmt die Parameter eines Kanalendpunktes auf und setzt sie in die entsprechenden Queueing-Disziplinen
um.
Als Schnittstelle zur Kommunikationsschicht dient eine Shared-Library, die zu der
aufrufenden Applikation gebunden wird.
62
Kapitel 4. Konzept
4.1. Grobentwurf
Die QoS-Parameter der Kanäle werden durch Linux-Queueing-Disziplinen durchgesetzt, die, wie in Kapitel 3.4.4 besprochen, über Netlink-Sockets konfiguriert werden. Zum Einsatz kommt eine Prio-Qdisc mit acht Bändern, deren Bandbreite
durch Hierarchical-Token-Buckets für jeden Kanal eingegrenzt wird. Der Best-EffortVerkehr bekommt an dem Band mit der niedrigsten Priorität einen eigenen Bucket
mit der verbleibenden Bandbreite zugewiesen.
Die Parameter für die Kanalendpunkte auf einem Rechner, werden in Form einer
Konfigurationsdatei bei der Initialisierung eingelesen.
Auf Grundlage des konzeptionellen Klassenmodells wird ein detailiertes Klassenmodell erstellt, das in Abbildung 4.2 dargestellt ist.
Die Klasse chContr dient als Bibliotheksschnittstelle und verwaltet die Kanalendpunkte, die in der chDescr-Klasse abgebildet sind. Die Klasse enthält das syncObjekt und noch ein Kommunikationsobjekt (com), das als Kommunikationsschnittstelle zu den Packet-Sockets dient.
Bei Initialisierung wird, wie in Kapitel 3.5.1 besprochen, eine Konfigurationsdatei
eingelesen, deren Inhalt durch die Klasse chConfRead zugreifbar ist.
Die Prozess-Klasse im konzeptionellen Klassendiagramm ist der chAvailContr-Klasse
gewichen, welche für jedes chDescr-Objekt ein chAvail-Objekt hält, das die maximale und die aktuelle Anzahl der Prozesszugriffe auf den Kanal verwaltet. Diese
chAvail-Objekte werden in einem Shared-Memory-Segment gehalten, um für alle
Prozesse einsehbar zu sein.
Die Klasse chDev entspricht der Klasse Physical Device aus dem konzeptionellen
Klassendiagramm und wird zu Adressierung und Konfiguration der VLANs eingesetzt. Die drei Instanzen der devInfo-Klasse halten nach der Initialisierung die
Informationen über das physikalische und die beiden virtuellen Devices.
Die Klasse chQoSContr setzt die QoS-Parameter der Kanalendpunkte in eine entsprechende Konfiguration der Queueing Disziplinen um.
Da es sich bei dem Klassenmodell um eine Design-Methode aus der Objekt Orientierung handelt, jedoch bei der Implementierung eine prozedurale Programmiersprache
zum Einsatz kommt, werden weitestgehend Utitlity-Klassen verwendet. Bei diesen
handelt es sich nach [Oes01] um eine Sammlung globaler Variablen und Funktionen,
die semantisch zu einer Klasse zusammengefasst werden.
63
4.2. Die Konfiguration (chConfRead)
Kapitel 4. Konzept
Abbildung 4.2: Übersicht Klassendiagramm
4.2
Die Konfiguration (chConfRead)
Bei der Konfigurationsdatei handelt es sich um eine Datei im XML-Format, deren
Aufbau im Folgenden anhand ihrer Document Type Definition erklärt werden soll.
64
Kapitel 4. Konzept
4.2. Die Konfiguration (chConfRead)
Abbildung 4.3: Übersicht Klassendiagramm
Quelltext 4.1: Document Type Definition der Konfigurationsdatei
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<? xml version = " 1.0 " encoding = " ISO -8859 -1 " ? >
< DOCTYPE channelconf [
<! ELEMENT channelconf ( host +) >
<! ELEMENT host
( name , netdevice , channel +) >
<! ELEMENT name
(# PCDATA ) >
<! ELEMENT netdevice
( devname , mtu ) >
<! ELEMENT devname
(# PCDATA ) >
<! ELEMENT mtu
(# PCDATA ) >
<! ELEMENT channel
( ID , processes , prio , delay , jitter , psize , bandwidth ) >
<! ELEMENT ID
(# PCDATA ) >
<! ELEMENT processes
(# PCDATA ) >
<! ELEMENT prio
(# PCDATA ) >
<! ELEMENT delay
(# PCDATA ) >
<! ELEMENT jitter
(# PCDATA ) >
<! ELEMENT psize
(# PCDATA ) >
<! ELEMENT bandwidth
(# PCDATA ) >
]>
Die Datei kann die Parameter für mehrere Rechner übernehmen (Zeile 3), so dass
für alle Rechner einer Automationsanlage die gleiche Konfigurationsdatei verwendet werden kann. Der Host (Zeile 4) wird durch den Rechnernamen identifiziert.
Beim Einlesen der Datei wird der name-Parameter mit dem Rechnernamen verglichen, um die passenden Konfigurationsparameter zu ermitteln. Die Daten für das
Netzwerk-Device (Zeile 6) bestehen aus dem Namen des Devices und der zu konfigurierenden MTU für das Device des Best-Effort-Verkehrs. Danach folgt eine Liste
mit den Kanalparametern (Zeile 9).
Die Klasse chConfRead dient als Interface zur Konfigurationsdatei. Mit deren Methode readConfFile() wird die Datei eingelesen und im Speicher gehalten und kann
mit den folgenden Methoden ausgelesen werden. Über die Methode getDevName()
werden der Name und die MTU für das Netzwerk-Device abgefragt. Mit jedem
Aufruf der Methode getChannelParame() werden die Parameter eines Kanals in die
per Referenz übergebenen Variablen eingetragen, bis alle Kanal-Daten übergeben
sind. Sind alle gewünschten Daten abgerufen, kann mit closeConfFile() die Datei
65
4.3. Die Bibliotheksschnittstelle (chContr)
Kapitel 4. Konzept
geschlossen und der belegte Speicher freigegeben werden.
4.3
Die Bibliotheksschnittstelle (chContr)
Die Klasse chContr dient als Bibliotheksschnittstelle und als zentrale ControllerKlasse, mit deren Methoden alle Aktivitäten, der mit ihr assozierten Klassen, gesteuert werden. Zusätzlich enthält sie eine Liste mit den geöffneten Kanalendpunkten,
sowie denen, die zum Öffnen bereitstehen.
Um den wechselseitigen Ausschluss sowohl beim Initialisieren von globalen Betriebsmitteln, wie Queueing Disziplinen und virtuellen Devices, als auch beim Zugriff auf
die chAvailContr-Klasse zu gewährleisten, hält die Klasse chContr ein Semaphor.
Die Interaktionsmöglichkeiten mit der Bibliotheksschnittstelle werden im Folgenden
mit Hilfe einiger Kollaborationsdiagramme gezeigt.
Initialisierung der Bibliothek
Vor der Nutzung der Bibliothek muss diese initialisiert werden, damit die Konfigurationsdatei ausgelesen wird und daraufhin alle benötigten Resourcen reserviert
werden können. Bei Initialisierung wird das Semaphor erschaffen, das den Vorgang
schützen soll. Wird durch die Existenz des Semaphors feststellt, dass ein anderer
Prozess die globalen Betriebsmittel bereits initialisiert hat, werden nur noch für den
Prozess globale Variablen initialisiert.
Das Diagramm in Abbildung 4.4 geht von der Annhame aus, dass noch kein Prozess
vorher auf die Bibliothek zugegriffen hat.
1 Die Initialisierung der Bibliothek wird durch die Funktion initChannels() angestoßen.
1.1 Über die Konfigurationsdatei werden alle verfügbaren Kanal-IDs, sowie deren
Parameter und Prozesszugriffsdaten, eingelesen und in dem chConfRead-Objekt
gehalten.
1.2 Der Name des Netzwerk-Devices wird durch die getDevName()-Methode angefordert.
1.3 Der Name des Devices wird mit der Methode initDev() an das device-Objekt
übergeben. Diese initialisiert alle erforderlichen Daten und legt die VLANs an.
66
Kapitel 4. Konzept
4.3. Die Bibliotheksschnittstelle (chContr)
Abbildung 4.4: Kollaborationsdiagramm zu initChannels()
1.4 Das chAvailContr-Objekt wird durch die Methode initChAvail() angewiesen
den Shared Memory anzulegen.
1.5 In initQoS() werden die QDisc-Grundkonfigurationen angelegt. Die Kanalspezifischen QoS-Einstellungen werden hier noch nicht vorgenommen, sondern
erst beim Öffnen des Kanals. Dies ist in einer statischen Umgebung zwar nicht
nötig, erleichtert aber die Erweiterung des Designs für dynamische Umgebungen.
1.6.*.1 Am chConfRead-Objekt werden zyklisch alle Kanaldaten sowie deren Prozesszugriffsdaten mit der Methode fillNextChannel() abgefragt.
1.6.*.2 Mit den ausgelesenen Daten wird ein chDescr-Objekt erstellt.
1.6.*.3 Die Prozesszugriffsdaten werden im chAvailContr-Objekt mit der Methode
addAvailEntry() eingetragen.
1.7 Die Konfigurationsdatei wird geschlossen.
Schließen der Bibliothek
Nach Benutzung der Bibliothek muss diese wieder geschlossen werden, um alle allokierten Resourcen wieder freizugeben. Der letzte zugreifende Prozess entfernt damit
67
4.3. Die Bibliotheksschnittstelle (chContr)
Kapitel 4. Konzept
auch alle VLANs, QoS-Einstellungen und das Shared-Memory-Segment. Auch in
dem Diagramm in Abbildung 4.5 wird davon ausgegangen, dass der ausführende
Prozess, der letzte ist, der auf die Bibliothek zugreift.
Abbildung 4.5: Kollaborationsdiagramm zu closeChannels()
1 Die Schließung der Bibliothek wird über die Methode closeChannels() durchgeführt.
1.1.* Bevor die Bibliothek geschlossen werden kann, muss geprüft werden, ob noch
geöffnete Kanäle für den Prozess existieren. Ist dies der Fall, muss der Vorgang
mit einer Fehlermeldung abgebrochen werden.
1.2.* Existieren keine geöffneten Kanäle mehr, werden alle chDescr-Objekte zerstört.
1.3 Mit der Methode closeAvailContr wird der Prozess vom Shared-Memory-Segment
getrennt.
1.4 Der letzte zugreifende Prozess entfernt mit der Methode closeQoSContr alle
QoS-Einstellungen.
1.5 Desweiteren entfernt der letzte Prozess mit closeDev am chDev-Objekt alle vorgenommen Einstellungen am Netzwerk-Device, inklusive VLANs.
68
Kapitel 4. Konzept
4.3. Die Bibliotheksschnittstelle (chContr)
Öffnen eines Kanals
Um Daten auf einem Kanal senden und empfangen zu können, muss ein Kanalendpunkt geöffnet werden. Ein geöffneter Kanal verfügt über ein Kommunikationsobjekt, das die nötigen send()- und recv()-Methoden bereitstellt.
Abbildung 4.6: Kollaborationsdiagramm zu chOpen()
1 Die Bibliotheksschnittstelle zum Öffnen von Kanälen ist die Funktion chOpen(),
bei der die ID des gewünschten Kanals übergeben werden muss.
1.1 Mit der Methode registerChannel() wird ermittelt, ob der Prozess auf den Kanal zugreifen darf und ob er dabei der erste ist. Außerdem wird ein Schlüssel
zu einem globalen Synchronisationsobjekt im per Referenz übergebenen Parameter key eingetragen, wenn mehr als ein Prozess auf den Kanal zugreifen
darf. Die registerChannel()-Methode ist durch das Semaphor geschützt, dass
bei der Initialisierung erschaffen wird.
1.2 Wurde ein Wert größer Null zurückgeliefert, wird ein Kommunikationsobjekt
für den Kanal erzeugt.
1.3 Weißt der Parameter key einen Wert ungleich Null auf, wird ein Sychronisationsobjekt mit dem enthaltenen Schlüssel generiert.
1.4 Sowohl Kommunikations- als auch Synchronisationsobjekt werden an das chDescr
-Objekt übergeben.
1.5 Der Kanal wird mit der Methode bindChannel an das Netzwerk-Device gebunden.
69
4.3. Die Bibliotheksschnittstelle (chContr)
Kapitel 4. Konzept
1.6 War der von der registerChannel()-Methode zurückgelieferte Wert gleich Eins,
ist der Prozess der erste, der auf den Kanal zugreift. In diesem Fall werden die QoS-Eigenschaften des Kanals mit der Methode addChannel() an das
chQoSContr-Objekt übergeben.
Schließen eines Kanals
Das Schließen eines Kanalendpunktes ist notwendig, um die Resourcen, die reserviert
wurden, wieder freizugeben.
Abbildung 4.7: Kollaborationsdiagramm zu chClose()
1 Um einen Kanalendpunkt zu schließen, muss die Methode chClose aufgerufen
werden.
1.1 Der Kanal wird am chAvailContr mit der Methode unregisterChannel() deregistriert.
1.2 Konnte der Kanalendpunkt deregistriert werden, wird er mit der Methode releaseChannel
() vom Netzwerk-Device entbunden.
1.3 Wurde von der Methode unregisterChannel() ein Wert gleich Eins zurückgeliefert, war der Prozess der letzte, der auf den Kanal zugegriffen hat. In diesem
Fall werden die QoS-Eigenschaften des Kanal mit der Methode remChannel()
70
Kapitel 4. Konzept
4.3. Die Bibliotheksschnittstelle (chContr)
am chQoSContr-Objekt wieder entfernt. Die registerChannel()-Methode ist
durch das Semaphor geschützt, dass bei der Initialisierung erschaffen wird.
1.4 Das Kommunikations- und das Synchronisationsobjekt des Kanalendpunktes
werden vom chDescr angefordert.
1.5 Wenn ein Synchronisationsobjekt vorhanden ist, wird es zerstört.
1.6 Das Kommunikationsobjekt wird zerstört.
Senden auf einem Kanal
Ist die Bibliothek initialisiert und ein Kanalendpunkt geöffnet, kann auf diesem
gesendet bzw. empfangen werden.
Abbildung 4.8: Kollaborationsdiagramm zu chOpen()
1 Zum Senden auf einem Kanal bietet die Biliotheksschnittstelle die Methode chSend
().
1.1 Vom chDescr-Objekt werden Synchronisations- und Kommunikationsobjekt angefordert.
1.2 Existiert ein Synchronisationsobjekt, so wird an ihm der exklusive Zugriff auf
den Kanal reserviert.
1.3 chContr ruft die send-Methode am Kommunikationsobjekt auf.
1.4 Der exklusive Zugriff wird wieder aufgehoben, sofern er zuvor reserviert wurde.
71
4.4. Der Kanalendpunkt (chDescr)
Kapitel 4. Konzept
Empfangen auf einem Kanal
Für den Empfang von Daten über einen Kanal ist keine Synchronisation notwendig,
da die Information alle Kanalendpunkte erreichen soll.
Abbildung 4.9: Kollaborationsdiagramm zu chRecv()
1 Mit der Methode chRecv() können Daten über einen geöffneten Kanalendpunkt
empfangen werden.
1.1 Das Kommunikationsobjekt wird von chDescr geholt.
1.3 Die recv()-Methode wird aufgerufen.
4.4
Der Kanalendpunkt (chDescr)
Die chDescr-Klasse stellt den Kanalendpunkt dar, durch den die Kommunikation
mit den restlichen Teilnehmern stattfindet. Jedes chDescr-Objekt hat eine eindeutige ID, durch die es identifiziert wird und eine Reihe von QoS-Parametern, die es
charakterisieren. Die ID ist eine netzwerkweite Identifikationsnummer, die für jeden
Kanal eindeutig ist, und im Parameter id gespeichert wird. Kanalendpunkte, die auf
einen Kanal zugreifen möchten, verwenden dessen ID. Durch die Art, wie die KanalID auf QDisc und Filter-Handles abgebildet wird, ergibt sich für die Kanal-ID ein
Wertebereich von 0x001 bis 0xFFF. Der Ursprung dieser Grenzen wird in Abschnitt
4.7 beschrieben.
Der Parameter prio entspricht einem Prioritätswert gemäß IEEE 802.1p.
Der delay-Parameter ist die maximale Verweilzeit in der QDisc in µsec. Der Delay kann nicht direkt beeinflusst werden, sondern wird indirekt über die Priorität
gesteuert. Der Parameter wird trotzdem in der Klasse gehalten, um zukünftigen Implementationen, die den Delay evtl. direkt beeinflussen können, zur Verfügung zu
stehen.
72
Kapitel 4. Konzept
4.4. Der Kanalendpunkt (chDescr)
Abbildung 4.10: chDesrc-Klasse
Mit jitter verhält es sich genauso wie mit dem delay-Parameter. Der Jitter kann
nicht direkt beeinflusst werden, sondern nur durch hohe Priorität oder durch Pufferung am Empfänger minimiert werden.
psize ist die maximale Payload-Größe in Byte. Der konfigurierte Wert muss einge-
halten werden, um die berechneten Parameter für den Delay einhalten zu können.
Daher werden Daten, die größer sind als in psize spezifiziert, von der chSend()Methode der Bibliothek zurückgewiesen.
Im Parameter bandwidth wird die benötigte Bandbreite des Kanals gespeichert. Diese
wird in Pakete/s angegeben, kann aber über die Paketgröße in Byte/s umgerechnet
werden.
Alle Kanalendpunkte, die während des Betriebs gebraucht werden, werden zur Zeit
der Bibliotheksinitialisierung erzeugt. Diese sind zu diesem Zeitpunkt noch ungeöffnet, was daran erkennbar ist, dass sie noch kein Kommunikationsobjekt besitzen.
Das Kommunikationobjekt(com) kapselt im wesentlichen einen Packet-Socket und
dessen Adresse, die mit dem Systemcall sendto() genutzt wird.
73
4.4. Der Kanalendpunkt (chDescr)
Kapitel 4. Konzept
Zusätzlich besitzt es die zwei abstrakten Methoden send()- und recv(), die durch
Ableitung der Klasse überschrieben werden können. Die Basis-Methoden sind wiederum einfache Kapselungen der sendto() und recv() Systemcalls.
Es sind jedoch auch andere Kommunikationsmethoden möglich, die bestimmte Kommunikationsformen besser unterstützen. So wäre es möglich, den Jitter auf Kosten
des Delays zu verringern, indem man die empfangenen Pakete puffert. In Abbildung
4.11 wird das Konzept zur Umsetzung dieser Kommunikationsform gezeigt.
Abbildung 4.11: Konzept für den gepufferten Empfang
Für das Konzept benötigt man zwei verschiedene Ableitungen der Klasse com, von
der die Klasse bufRecvCom die Senderseite des Kanals darstellt. Die Klasse für den
Empfang bufProcCom wartet in einem eigenen Prozess auf die Ankunft von Paketen.
Diese werden dann mit der send()-Methode an eine Message-Queue weitergegeben,
sobald sie eintreffen. Das bufRecvCom-Objekt kann diese mit der eigenen recv()Methode Jitter-frei auslesen.
Wird der Kanal von mehreren Prozessen genutzt, so muss der wechselseitige Ausschluss beim Senden gewährleistet sein. Zu diesem Zweck hält ein Kanalendpunkt,
auf dem mehr als ein Prozess zugreifen darf, ein Synchronisationsobjekt (sync) bereit, über das ein Kanal zum Senden reserviert werden kann (Abbildung 5.1).
74
Kapitel 4. Konzept
4.5. Prozesszugriffsverwaltung (chAvailContr/
chAvail)
Das in chDescr enthaltene Synchronisationsobjekt sync ist ein Prozess-übergreifendes,
vom Betriebssystem verwaltetes Semaphor, das global über einen Schlüssel identifiziert wird. Das Semaphor wird beim Anlegen eines Eintrags im Shared-MemorySegment von der Methode addChAvailEntry() erzeugt und dessen Schlüssel wird im
syncKey-Attribut des chAvail-Objekts abgelegt.
4.5
Prozesszugriffsverwaltung (chAvailContr/
chAvail)
Abbildung 4.12: chAvailContr- und chAvail-Klasse
Der Zugriff von mehr als einem Prozess auf einen Kanal ist nicht immer erwünscht.
Zum einen hängen die QoS-Parameter stark von der genutzten Bandbreite ab, so
dass nicht mehr Prozesse Daten senden dürfen, als vorher festgelegt wurden. Zum
anderen ist auch die Anzahl der zur Verfügung stehenden Semaphoren begrenzt.
Um zu verhindern, dass mehr Prozesse auf einen Kanal zugreifen, als vorgesehen
sind, muss ein Prozess-übergreifender Mechanismus existieren, der den Zugriff auf
die Kanäle einschränkt. Zu diesem Zweck existiert für jeden Kanal ein chAvailObjekt, das in einem Shared-Memory-Segment gehalten wird. Dies enthält sowohl
die maximale Anzahl von Prozessen, die auf den Kanal zugreifen dürfen (max), als
auch die aktuelle Anzahl von Prozessen, die schon auf den Kanal zugreifen (cur).
Außerdem halten diese Objekte den Schlüssel zu dem Kanal-zugehörigen Semaphor,
falls mehr als ein Prozess einen Endpunkt auf diesem Kanal öffnen darf. Ein neues
Objekt wird mit der Methode addChAvailEntry() in das Shared-Memory-Segment
eingetragen. Wurde der Eintrag schon von einem anderen Prozess vorgenommen,
wird kein neuer Eintrag angelegt.
Das Shared-Memory-Segment wird von dem ersten Prozess erzeugt, der die Methode
initAvailContr aufruft, und vom letzten zugreifenden Prozess mit der Methode
75
4.6. Netzwerk-Device (chDev)
Kapitel 4. Konzept
closeAvailContr wieder zerstört. Alle anderen Prozesse verbinden bzw. lösen sich
von dem bestehenden Segment.
Die Methoden registerChannel() und unregisterChannel() dienen als Test-AndSet-Methoden zur Reservierung des Kanalzugriffs. Der Rückgabewert signalisiert
den Zugriffsstatus des Kanals. Ein negativer Wert zeigt, dass der Kanalendpunkt
nicht geöffnet bzw geschlossen werden kann. Ein Wert gleich Null gibt den Kanal
zum Öffnen bzw. Schließen frei. Wird ein positiver Wert zurückgeliefert, heißt das,
der Prozess ist der erste bzw. der letzte, der auf den Kanal zugreift. Damit wird
signalisiert, dass die zum Kanal zugehörige QDisc angelegt bzw. gelöscht werden
kann. Abbildung 4.13 zeigt den Vorgang exemplarisch für registerChannel als Aktivitätsdiagramm.
Abbildung 4.13: registerChannel-Methode
4.6
Netzwerk-Device (chDev)
Das Adressierungsschema eines Packet-Sockets ist vom unterlagerten Netzwerk-Device
abhängig. Wird ein Kanal geöffnet, muss dessen Socket an das entsprechende Device
gebunden und die Kanal-ID auf eine Adresse abgebildet werden. Die chDev-Klasse
enthält für diesen Zweck zwei abstrakte Methoden, die durch Implementierung in abgeleiteten Klassen, für das jeweilige Adressierungsschema angepasst werden können.
Für diese Arbeit ist lediglich eine abgeleitete Klasse für das Binden des Sockets an
Ethernet-Devices vorgesehen. Eine Anpassung an andere Layer-2-Protokolle, soweit
76
Kapitel 4. Konzept
4.6. Netzwerk-Device (chDev)
Abbildung 4.14: Die chDev-Klasse
sie durch die Packet-Socket-Schnittstelle nutzbar sind, sollte durch dieses Design
leicht fallen.
Informationen über das reale und die zwei virtuellen Netzwerk-Devices werden vom
chDev-Objekt in drei devInfo-Objekten gehalten. Die Information besteht aus dem
Namen, dem Index und dem ARP-Addresstyp des Device.
Bei der Initialisierung des chDev-Objekts mit der Methode initDev(), wird der Name des zu verwendenden realen Netzwerk-Devices übergeben, mit dem dann dessen
Index und Adresstyp ermittelt werden. Je nach Adresstyp kann dann die Initialisierung fortgesetzt werden. Entspricht der Adresstyp Ethernet, werden als nächstes
die beiden VLANs erzeugt, falls diese noch nicht existieren sollten. Das VLAN für
die Kanäle bildet die Priorität der mit dem Kanal assoziierten Sockets auf die UserPriority eins zu eins ab. Das VLAN für den Best-Effort-Verkehr bildet alle SocketPrioritäten auf den User-Priority-Wert Eins ab, welcher nach 802.1p dem Wert mit
der niedrigsten Priorität entspricht. Das VLAN-Device bekommt die IP-Adresse des
physikalischen Device zugewiesen, und die MTU wird auf den in der initDev() übergebenen Wert gesetzt. Danach werden die Informationen über die beiden virtuellen
77
4.7. QoS-Controller (chQoSContr)
Kapitel 4. Konzept
Devices ermittelt und in deren devInfo-Objekten gespeichert. Die beiden abstrakten Methoden werden mit den Ethernet-spezifischen Methoden überschrieben. Die
Konfiguration der virtuellen Devices wird über eine Konfigurationsbibliothek durchgeführt, die die nötigen ioctl()-Zugriffr kapselt.
Die für Ethernet konzipierte bindChannel()-Methode öffnet einen Packet-Socket,
bildet die Kanal-ID auf eine Ethernet-Multicast-Adresse ab und bindet den PacketSocket des Kommunikationsobjekts an diese Adresse am virtuellen Device. Die ermittelte Adresse wird dem Kommunikationsobjekt zugewiesen. releaseChannel()
entfernt den Packet-Socket von dem Netzwerk-Device und schließt ihn.
4.7
QoS-Controller (chQoSContr)
Abbildung 4.15: Die chQoSContr-Klasse
Der QoS-Controller ist die Schnittstelle zu den Queueing-Disziplinen unter Linux.
Beim Hinzufügen oder Entfernen eines Kanals übernimmt der QoS-Controller die
Parameter des Kanals und fügt entsprechende Queueing-Disziplinen hinzu oder entfernt sie wieder. Dazu nutzt er eine dafür implementierte QDisc-KonfigurationsBibliothek, die den Zugriff auf die Netlink-Sockets kapselt.
Die Filterregeln, die zum Klassifizieren der Pakete genutzt werden, sind vom verwendeten Layer-2-Protokoll abhängig. Unter Ethernet ist die ID eines Kanals Teil einer
Filterregel. Diese ist ein Teil der Multicast-Adresse des Ethernet-Frames. Wird die
Bibliothek für ein Device mit einem anderen Layer-2-Protokoll genutzt, kann diese
78
Kapitel 4. Konzept
4.7. QoS-Controller (chQoSContr)
Regel nicht verwendet werden. Für diesen Fall wird in chQoSContr eine Tabelle mit
Filterregeln für mögliche Adresstypen gehalten.
Das chQoSContr-Objekt wird mit dem Index des zu verwendenden Device und dessen
Adresstyp über die Methode initQoS() initialisiert. Wird für den boolschen Parameter initQDisc TRUE übergeben, so wird ein Grundgerüst an Queueing-Disziplinen erzeugt, an dem jeweils die benötigten Queueing-Disziplinen für die Kanäle angebracht
werden. Die QDisc für den Best-Effort-Verkehr wird auch zur Zeit der Initialisierung
erzeugt und bekommt zunächst die gesamte Bandbreite zugesprochen.
Die Methode closeQoS entfernt alle QoS-Einstellungen vom konfigurierten NetzwerkDevice.
Mit den Methoden addChQoS() und remChQoS() werden die Queueing-Disziplinen,
entsprechend der übergebenen QoS-Parameter, erzeugt bzw. gelöscht. Gleichzeitig
werden die Filter, entsprechend der Regeln für den Adresstyp, gesetzt. Mit jedem
Hinzufügen und Entfernen von Kanälen, wird die QDisc des Best-Effort-Verkehrs
mit der verbleibenden Bandbreite rekonfiguriert.
Die Vorgehensweise, QDiscs und Filter für die Kanäle erst bei deren Öffnung bzw.
Schließung zu konfiguriert, unterstützt die Erweiterbarkeit der Bibliothek für dynamische Umgebungen.
Wie der Aufbau der QDiscs bei der Initialisierung und für jeden Kanal im Detail
aussieht, soll im Folgenden genauer betrachtet werden.
Basis-QDisc-Konfiguration
Für die Basiskonfiguration (Abbildung 4.16) wird bei der Initialisierung zunächst
eine Prio-QDisc mit acht Bändern als Root-QDisc konfiguriert. Wie in 2.3.3.2 erläutert, kann die Major-Nummer eines QDisc-Handles mit einem Wert zwischen
0x0001 und 0x7FFF erzeugt werden. Für die Prio-QDisc wird das Handle 0x7FFF:0
gewählt, damit die niedrigen Handles für die Blatt-QDiscs frei bleiben.
In 3.4.4 wurde besprochen, dass eine Prio-QDisc ihre Klassen selbst in der Anzahl der
konfigurierten Bänder erzeugt. Diese Klassen erhalten Handles deren Minor Nummer
von 0x0001 bis 0x0008 durch nummeriert. Die Priorität der Klassen ist umgekehrt
proportional zu deren Minor-Nummer.
Switches klassifizieren Pakete nach dem in IEEE 802.1p definierten Schema (vgl.
Kapitel 2.1.1), daher müssen Pakete in der QDisc auf die gleich Weise klassifiziert
werden. Um das zu gewährleisten wird für jede Klasse der Prio-QDisc ein u32-Filter
79
4.7. QoS-Controller (chQoSContr)
Kapitel 4. Konzept
Abbildung 4.16: Basis-QDisc-Konfiguration
erzeugt, der das User-Priority-Feld des VLAN-Tags ausliest und an die Zielklasse
mit der entsprechenden Priorität sendet (vgl. Abbildung4.16 und Tabelle A.1).
Um den Klassifizierungsaufwand für hochpriore Pakete zu minimieren, werden den
Filtern Prioritäten entsprechend der Priorität ihrer jeweiligen Zielklasse zugewiesen.
Grundsätzlich müsste man keinen eigenen Filter für Prio erzeugen, da dieser Pakete
selbst aufgrund ihrer Socket-Priorität klassifizieren kann. Auf die Socket-Prioritäten
der Pakete, die über das Best-Effort-Device versendet werden, kann jedoch kein
Einfluss genommen werden. Daher wird die Socket-Prioritäten durch die EgressPrio-Map des Best-Effort-Devices alle auf die Priorität 1 abgebildet und für die
QDisc die Filter erzeugt.
80
Kapitel 4. Konzept
4.7. QoS-Controller (chQoSContr)
Wie in in Kapitel 3.3.3 besprochen, muss der Verkehr für eine nach dem StrictPriority-Algorithmus arbeitende Queue charakterisierbar sein, um den maximalen
Delay innerhalb der Queue garantieren zu können. Dort wurde der Verkehr durch
den Token-Bucket-Algorithmus eingegrenzt. Dies soll in der Konfiguration durch eine
HTB-QDisc geschehen, deren Kindklassen die Bandbreite für jeden Kanal eingrenzen
sollen. Die QDisc wird als reiner Bandbreitenbegrenzer eingesetzt werden, ohne das
Automatische Verteilen von überschüssiger Bandbreite.
In der Basiskonfiguration werden die Klassen für die Kanäle noch nicht erzeugt, sondern nur deren Eltern-QDiscs an jeder Prio-Klasse. Die Handles der QDiscs werden
so gewählt, dass deren Major-Nummer jeweils der um eins inkrementierten UserPriority der Pakete entspricht, die ihnen durch die Filter zugewiesen werden. Auch
hier sei zum besseren Versändnis wieder auf Tabelle A.1 verwiesen.
Abbildung 4.17: Best-Effort-QDisc-Konfiguration
An der QDisc 2:0, deren Elternklasse die niedrigste Priorität hat, wird die Klasse
für den Best-Effort Verkehr angefügt (Abbildung 4.17). Diese bekommt das Handle
2:FFFF zugewiesen, da 0xFFFF dieses außerhalb des Wertebereichs der Kanal-ID
und es daher nicht zu Kollisionen der Klassen Handles kommen kann. Bevor die
81
4.7. QoS-Controller (chQoSContr)
Kapitel 4. Konzept
Kanäle geöffnet werden, bekommt die Klasse des Best-Effort-Device die gesamte
Bandbreite als rate-Parameter zugewiesen. Als Burst-Parameter wird die maximale
Best-Effort-Paketgröße zugewiesen. Diese entspricht der für das Best-Effort-Device
konfigurierten MTU plus Präambel, Header, CRC und IFG.
Der Eltern-QDisc wird ein Filter angefügt, der die Pakete nach dem Wert im VIDFeld des VLAN-Tags klassifiziert. Entspricht die VID im Paket, der VID des BestEffort-VLANs, so wird das Paket an die Klasse 2:FFFF übergeben.
Der Klasse 2:FFFF wird eine SFQ-QDisc als Blatt-QDisc zugewiesen, der ein Handle automatisch vom Betriebssystem zugewiesen bekommt. Diese sorgt für Fairness
zwischen den Datenströmen, die den Best-Effort-Verkehr ausmachen.
QDisc-Konfiguration für Kanäle
Abbildung 4.18: QDisc-Konfiguration für die Kanäle 2 (Prio 4), 3 (Prio 1), 4 (Prio7)
und 5 (Prio4)
82
Kapitel 4. Konzept
4.7. QoS-Controller (chQoSContr)
Jedes mal, wenn ein Kanal vom ersten Prozess geöffnet bzw. vom letzten Prozess
geschlossen wird, muss eine Konfiguration der QDiscs vorgenommen werden. Wird
ein Kanal das erste mal geöffnet, wird für ihn eine eigene Klasse an eine der HTBQDiscs angefügt. Die Eltern-QDisc wird mit Hilfe des Prio-Parameters des Kanals
gewählt. Die Major-Nummer des Handles entspricht des um eins inkrementierten
Wert des Prio-Parameters. Um die Klasse zur späteren Löschung identifizieren zu
können, erhält die Klasse ein Handle mit einer Minor-Nummer, die der Kanal-ID
entspricht.
In Abbildung 4.18 wird das Prinzip beispielhaft an vier Kanälen demonstriert. Die
Kanäle mit den IDs 2 und 5 besitzen einen Priority-Wert von 4, während Kanal
4 einen Priority-Wert von 7 hat. Kanal 3 hat die niedrigste Priorität, was nach
IEEE 801.1p die Priorität 1 ist. Die Eltern-QDisc der Klasse, die für den Kanal
erzeugt wird, ist die gleiche wie die, der Klasse für den Best-Effort-Verkehr (blass
eingezeichnet).
Der Wert für den rate-Parameter wird, wie in 4.4 angegeben, aus dem bandwidthund dem psize-Parameter des Kanals berechnet. Jedoch muss dazu noch der Overhead durch Präambel, Start-of-Frame-Delimiter, Ethernet-Header inklusive VLANTag, CRC und IFG auf die Paketgröße addiert werden. Als cburst-Parameter dient
der Parameter psize, der wiederum um den Overhead erhöht wird.
Für jede der Klassen wird ein Filter an der Eltern-QDisc angelegt, der die Pakete
anhand der letzten 12 Bit der Zieladresse im Ethernetheader klassifiziert. Entsprechen diese der ID des Kanals, für den die Klasse angelegt wurde, wird das Paket an
die Klasse weitergegeben.
Um die Filter zur späteren Löschung eindeutig identifizieren zu können, werden diese mit einem eindeutigen Handle angelegt und Priorität angelegt. Da die Kanäle,
die diese Filter passieren, alle die gleiche Priorität haben, wird alle Filter die gleiche
Priorität konfiguriert, wodurch, wie in Kapitel 3.4.5 erläutert, nur eine Hash-Tabelle
für die Filter angelegt wird. Als Handle für den Filter wird die Kanal-ID verwendet,
die jedoch nur 12-Bit breit ist. Dadurch ergibt sich die obere Grenze für den Wertebereich der Kanal-IDs Es wäre zwar möglich eine Zuordnungstabelle von Kanal-IDs
zu Filterhandles zu verwalten, jedoch müsste diese dann wieder Prozess-übergreifend
zugreifbar sein. Um diesen Aufwand zu umgehen wurde ein verminderter Wertebereich für die Kanal-IDs in Kauf genommen.
Als Blatt-QDisc kommt eine pfifo-QDisc zum Einsatz, deren Handle automatisch
zugewiesen wird, da diese beim Löschen der Klasse automatisch mit entfernt wird.
83
4.7. QoS-Controller (chQoSContr)
Kapitel 4. Konzept
84
Kapitel 5
Implementierung
In diesem Kapitel wird die prototypische Implementierung des im Kapitel 4 besprochenen Designs behandelt. Da das objekt-orientierte Konzept in der prozeduralen Programmiersprache C umgesetzt wurde, sind ein paar Dinge anzumerken. Alle
Utility-Klassen sind als globale, statische Variablen und Funktionen in einem jeweils
getrennten Modul umgesetzt worden.
Die aus der Objekt-Orientierten Softwareentwicklung bekannte Vererbung von Klassen, ist in der prozeduralen Programmiersprache C nicht im klassischen Sinne umsetzbar. Die im Klassendiagramm verwendeten, ableitbaren Klassen bieten im wesentlichen die Möglichkeit, abstrakte Methoden auf verschiedene Weise zu implementieren. Diese Methoden werden in C durch Zeiger auf Funktionen realisiert. Es
werden verschiedene Implementierungen einer solchen Funktion mit gleichen Parametern und Rückgabetypen erstellt. Zur Laufzeit wird ermittelt, welche Implementierung der Funktionen genutzt werden soll und deren Adresse im Zeiger gespeichert.
Im Folgenden wird kurz auf die Implementierungsumgebung eingegangen. Danach
werden die einzelnen Module der Bibliothek in den entsprechenden Abschnitten
genauer betrachtet. Module wie Konfigurationsbibliotheken, die semantisch einem
anderen Modul untergeordnet sind, werden in den Unterabschnitten der jeweiligen
Hauptmodule behandelt. Abschließend wird deren Implementierungsaufwand inklusive Kommentaren aufgezeigt.
85
5.1. Implementierungsumgebung
5.1
Kapitel 5. Implementierung
Implementierungsumgebung
Die Implementierung wird auf einem Rechner mit Intel Celeron 2,8GHz und 512
MB RAM durchgeführt, auf dem eine Debian Linux Distribution in der Version 3.1
installiert wurde. An der Standard Kernelkonfiguration werden folgende Optionen
verändert:
• Die Option CONFIG_PREEMPT wird entfernt, da das Modul 8021q sonst bei atomaren Vorgängen unterbrochen wird, was zu Kernel Panics führt.
• Das Linux Advanced Router Modul wird, durch Entfernen der Option CONFIG_IP
-_ADVANCED_ROUTER, aus dem Kernel herausgenommen.
• Um das Propagieren von IPv6-Routing-Informationen zu unterbinden, wird
die CONFIG_IPV6-Option entfernt.
Als Entwicklungsumgebung dient eine Kombination aus dem Editor vim-6.3.68 und
dem Compiler gcc-3.3.5.
Zum Auswerten der Konfigurationsdatei, werden das parser- und das tree-Modul
der Bibliothek libxml2 genutzt.
Bei der Konfiguration der Queueing-Disziplinen werden, zum Aufbauen und Versenden der Netlink-Messages, Teile des Quellcodes des Programms TC verwendet.
Dieses ist Teil der iproute2-Utility-Suite [ipr], welche unter der GNU-Public-License2 veröffentlicht ist.
Für die Messung der Ende-zu-Ende Propagationszeit, hat Dipl. Inf. Bernhard Gelling
eine Messbibliothek zur Verfügung gestellt.
5.2
chConfRead
Die Konfigurationsdatei wird mit Hilfe des XML-Parsers aus der Bibliothek libxml2
eingelesen und mit dem tree-Modul der Bibliothek, in einer Baumstruktur abgebildet. Danach wird der Aufbau der Datei verifiziert1 und die Position benötigter
Knotenpunkte des Baums in Zeigern abgelegt.
1
Es wird darauf hingewiesen, dass der Aufbau nicht über eine DTD-Datei, sondern durch den
Sourcecode selbst verifiziert wird
86
Kapitel 5. Implementierung
5.3. chContr
Implementierungsaufwand
Datei
Zeilen (ohne Kommentare)
chConfRead.h
10
chConfRead.c
256
xmlNav.h
11
xmlNav.c
83
Gesamt
360
Tabelle 5.1: Implementierungsaufwand chConfRead
5.3
chContr
In der Header-Datei der Bibliothek sind eine Reihe von Rückgabewerte definiert,
um aufgetretene Fehler in den Funktionen näher zu spezifizieren (Listing 5.1). Bei
einem Fehler in der Bibliothek werden diese als Negativwerte zurückgeliefert.
Quelltext 5.1: Fehlerrückgabewerte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
enum {
NO_ERR = 0 ,
ERR_NOT_SPEC ,
ERR_AVAIL_TABLE_FULL ,
ERR_AVAIL_TABLE_EMPTY ,
ERR_INVAL_CH_ID ,
ERR_INVAL_MODE ,
ERR_INVAL_SIZE ,
ERR_CH_OPEN ,
ERR_CH_OCCUPIED ,
ERR_CH_NOCCUPIED ,
ERR_CH_NOT_EXIST ,
ERR_NO_QOS_INIT ,
ERR_QOS_INIT_CALLED ,
ERR_NO_XML_FILE ,
ERR_INVAL_XML_FILE ,
ERR_INVAL_DEVICE ,
ERR_INVAL_ADDRTYPE ,
ERR_NO_LOCAL_MEM ,
ERR_SYSCALL ,
E R R _ AV A I L _ E N T R Y_ O C C
};
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
Kein Fehler
Nicht näher spezifizierter Fehler
Shared - Memory ist voll
Es existiert kein Eintrag im Shared - Memory
Die Kanal - ID kann ( noch ) nicht eingesetzt werden
Kom munikati onsmodu s existiert nicht
Übergebene Payload größer als zugelassen
Der Kanal ist bereits geöffnet
Der Kanal ist bereit besetzt
Der Kanal ist nicht besetzt
Der Kanal ist nicht für den Einsatz vorgesehen
Bibliothek wurde noch nicht initialisiert
Bibliothek wurde bereits initialisiert
Pfad zur Konfig uration sdatei ist falsch
Aufbau Konf igurati onsdate i ist falsch
Netzwerk - Device existiert nicht
Adresstyp wird nicht unterstützt
malloc () ist fehlgeschlagen
Ein Systemcall ist fehlgeschlagen
Es existiert schon ein Eintrag für diesen Kanal im ShM
Alle Funktionen der Bibliothek werden entsprechend der Kollaborationsdiagramme
aus Kapitel 4.3 umgesetzt.
In der Initialisierungsfunktion initChannels() wird zunächst ermittelt, ob die Bi-
87
5.3. chContr
Kapitel 5. Implementierung
bliothek, und damit alle globalen Betriebsmittel, schon von einem anderen Prozess
initialisiert wurde. Dies geschieht indem das Semaphor, das das Shared-MemorySegment schützen soll, mit einem festen Schlüssel und den Flags IPC_CREAT und
IPC_EXCL aufgerufen wird. Kommt es dabei zum Fehler und der Inhalt der globalen
Variablen errno entspricht EEXIST, wird davon ausgegangen, dass der Erstzugriff auf
die Bibliothek schon durch einen anderen Prozess erfolgt ist. In diesem Fall bekommt
die globale Variable first den Wert FALSE zugewiesen, die jeder init-Funktion der
anderen Contr-Klassen als Parameter übergeben werden.
Für die Funktion chOpen() wird ein mode-Parameter deklariert, der in zwei 16-Bit
Felder geteilt ist. Die oberen 16-Bit sind für Flags reserviert. Zur Zeit der Arbeit ist
nur das USE_THREADS-Flag definiert, welches signalisiert, dass es sich, bei dem auf die
Bibliothek zugreifenden Prozess, um eine multi-threaded Anwendung handelt und
somit der Sendezugriff auf den Kanalendpunkt wechselseitig ausgeschlossen werden
muss.
Die unteren 16-Bit bestimmen den Kommunikationsmodus des Kanals. Bisher sind
zwei Kommunikationsmodi definiert: CH_BASIC_MODE und CH_TEST_MODE. Die beiden
Modi werden in Abschnitt 5.6 und Kapitel 6.3 näher erklärt. Aufgrund des Kommunikationsmodus bekommt das chDescr-Objekt seine send()- und recv()-Methoden
zugewiesen (Listing 5.2).
Quelltext 5.2: Zuweisung der Kommunikationmethoden
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
switch ( mode & 0 xFFFF ) {
case CH_BASIC_MODE :
channel - > send = basicModeSend ;
channel - > recv = basicModeRecv ;
break ;
# ifdef _CH_TEST_
case CH_TEST_MODE :
channel - > send = testModeSend ;
channel - > recv = testModeRecv ;
break ;
# endif
default :
releaseChannel ( channel ) ;
un reg iste rCh ann el ( id ) ;
return - ERR_INVAL_MODE ;
}
Bei der Registrierung des Kanalendpunkts wird der Methode registerChannel() ein
syncKey-Parameter per Referenz mit übergeben. Existiert ein Schlüssel für den Kanal, wird er in den Parameter eingetragen. Mit dem Schlüssel wird eine Verbindung
zum Semaphor geöffnet. Kann nur ein Prozess auf einen Kanal zugreifen, wird 0
88
Kapitel 5. Implementierung
5.3. chContr
in den syncKey eingetragen, was signalisiert, dass kein Semaphor für diesen Kanal
existiert.
Nutzt der Prozess jedoch Threads, so muss auch hier der wechselseitige Ausschluss
beim Senden gewährleistet sein. Dazu muss beim Öffnen des Kanalendpunktes das
USE_THREADS-Flag gesetzt werden, welches die chOpen-Methode veranlasst, ein lokales
Semaphor mit dem Schlüssel IPC_PRIVATE zu erzeugen. Ist das Flag gesetzt und ein
Prozesszugriff von mehr als einem Prozess ist erlaubt, wird das Prozess-übergreifende
Semaphor für den Kanalendpunkt genutzt. Der Vorgang ist in Abbildung 5.1 dargestellt.
Abbildung 5.1: Semaphore für Prozess- und Threadsynchronisation
Nachdem der Socket des chDescr-Objekts an das Device gebunden ist, wird ihm die
für den Kanal definierte Priorität zugewiesen (Listing 5.3).
Quelltext 5.3: Setzen der Socket-Priotität
1
2
3
if ( setsockopt ( channel - > sock , SOL_SOCKET , SO_PRIORITY , ( const void *) & prio ,
sizeof ( prio ) ) < 0) {
return -1;
}
Die Liste der chDescr-Objekte wird in dem dafür implementierten Modul chContain
eingefügt. Auf dieses Modul wird im Folgenden eingegangen.
chContain
Das chContain-Modul implementiert einen Container für die chDescr-Objekte. Da
die Objekte für jeden Kommunikationsvorgang benötigt werden, ist ein schnellst-
89
5.3. chContr
Kapitel 5. Implementierung
möglicher Zugriff auf die Objekte nötig. Eine einfache Liste, die sequenziell durchsucht werden müsste, kann daher nicht eingesetzt werden. Am besten wäre die direkte Abbildung der Kanal-ID auf eine Speicheradresse, jedoch würde ein Array aus
Zeigern mit 212 Einträgen alleine 4kByte Speicher belegen, ohne auch nur ein Objekt
zu referenzieren. Eine Hash-Tabelle würde einen kollisionsfreien Hash-Algorithmus
voraussetzen und, je nach Dimensionierung der Tabelle, wiederum zu Suchoperationen führen.
Abbildung 5.2: Speichermodell für chDescr-Objekte
Die implementierte Lösung sieht ein dynamisch angelegtes, zweidimensionales Array
mit Zeigern auf chDescr-Objekte vor (Abbildung 5.2). Die Indizierung erfolgt über
die Kanal-ID, die über einen Offset in zwei Segmente geteilt wird. In der Implementierung wird ein Offset von 5 gewählt, was eine Verhältnis von 128 auf 32 Einträgen
bedeutet. Um den Speicherbedarf gering zu halten, werden nur die Arrays der zweiten Dimension erzeugt, die benötigt werden. Desweiteren wird für das erste Array
nur so viel Speicher allokiert, wie zur Haltung der benötigten Arrays der zweiten
90
Kapitel 5. Implementierung
5.3. chContr
Dimension erforderlich ist. So ist die optimale Speicherausnutzung abhängig von der
Distanz zwischen den einzelnen Kanal-IDs. Für 32 chDescr-Objekte die von 0 bis
31 sequenziell durchnummeriert sind, würde die Tabelle 132 Byte groß sein2 . Die
Größe würde jedoch auf 4224 Byte ansteigen, wenn die IDs der 32 Objekte jeweils
eine Distanz von 32 aufweisen würden3 . Das ist generell nicht problematisch, sollte
jedoch berücksichtigt werden, wenn der Speicheroverhead gering gehalten werden
soll.
In Listing 5.6 werden die Makros zur Umrechnung der Kanal-ID auf die Indizes und
zur Bestimmung der Größe des Arrays der zweiten Dimension gezeigt.
Quelltext 5.4: Makros zur Umrechnung der Indizes in
1
2
3
4
# define
# define
# define
# define
chContain
ID_OFFSET (( unsigned short ) 5)
LDSEG ( x ) (( x ) >> ID_OFFSET )
// Leading Segment
TRSEG ( x ) (( x ) & ~(( unsigned short ) 0 xFFFF << ID_OFFSET ) ) // Trailing Segment
TRSEGSIZ (( unsigned short ) (1 << ID_OFFSET ) )
Mit der Funktion insertChannelDescr()werden chDescr-Objekte der Tabelle hinzugefügt.
Zunächst wird geprüft, ob der errechnete, obere Index größer ist, als die Anzahl der
allokierten Array-Elemente. Ist das der Fall, wird das Array mit realloc() mit der
erforderlichen Größe neu allokiert und die neu hinzugewonnenen Zeiger im Array
mit NULL initialisiert.
Quelltext 5.5: Stufenweises Allokieren in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
chContain
if ( LDSEG ( channel - > id ) >= tableSize ) {
if ( chDescrTable != NULL ) {
memOffset = tableSize ;
}
tableSize = LDSEG ( channel - > id ) +1;
chDescrTable = realloc (( void *) chDescrTable , tableSize * sizeof ( struct chDescr **) )
;
if ( chDescrTable == NULL ) {
tableSize = memOffset ;
return - ERR_NO_LOCAL_ME M ;
}
for (; memOffset < tableSize ; memOffset ++) {
chDescrTable [ memOffset ] = NULL ;
}
}
2
3
32 · 4Byte + 4Byte für das erste Array der Größe 1
32 ∗ 32 ∗ 4Byte + 32 ∗ 4Byte
91
5.3. chContr
Kapitel 5. Implementierung
Danach wird geprüft, ob der Zeiger des oberen Index auf NULL zeigt. Ist dies der
Fall, wird der Speicher für ein neues Array allokiert und dessen Felder mit NULL
initialisiert.
Ist die Position mit den für die ID ermittelten Indizes noch nicht belegt, wird der
Speicher für ein neues chDescr-Objekt allokiert und die Daten des übergebenen
Objekts kopiert. Ist die Position schon belegt wird -ERR_CH_OCCUPIED zurückgeliefert,
ansonsten 0.
Mit der Funktion getChannelDescr() wird der Zeiger auf ein gespeichertes Objekt
angefordert. Durch die Art der Speicherung kann die Position mit nur drei Instruktionen abgefragt werden. Existiert das Objekt nicht, wird der NULL-Zeiger zurückgeliefert.
Die Funktion removeChannelDescr()entfernt einen einzelnen Eintrag aus der Tabelle, wobei dessen Speicher freigegeben wird. Jedoch wird nicht geprüft, ob der
Eintrag der letzte war, und somit eines der Arrays freigegeben werden könnte. Ist
kein Eintrag an der Stelle vorhanden, wird -ERR_INVAL_CH_ID und ansonsten 0 zurückgeliefert.
Die Funktion getNextChannelDescr()kann zum sequentiellen Abrufen der gespeicherten Elemente genutzt werden. Mit jedem Aufruf wird ein Iterator übergeben,
der die Stelle markiert, ab der nach dem nachfolgenden Element gesucht werden soll.
Wird ein Objekt gefunden, wird der Zeiger auf dessen Speicheradresse zurückgeliefert und der Parameter iterator auf die aktuelle Position gesetzt. Befindet sich kein
Objekt mehr hinter der angegeben Position, wird NULL zurückgeliefert.
Wird mit jedem neuen Aufruf der Iterator des letzten Aufrufs übergeben, wird die
Liste sequenziell durchlaufen. Um die Suche am Anfang der Tabelle zu beginnen,
muss dem Iterator ein Wert von -1 zugewiesen werden.
Implementierungsaufwand
Datei
Zeilen (ohne Kommentare)
channel.h
51
chContr.c
402
chContain.h
11
chContain.c
184
Gesamt
648
Tabelle 5.2: Implementierungsaufwand chContr
92
Kapitel 5. Implementierung
5.4
5.4. chDescr
chDescr
Quelltext 5.6: Die
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct chDescr {
unsigned short
int
unsigned long
unsigned long
unsigned long
unsigned short
int
int
int
unsigned int
struct sockaddr
socklen_t
int
int
};
chDescr-Struktur
id ;
prio ;
// Usr Priority
delay ;
// usec
jitter ;
// usec
bandwidth ;
// Pakets / s
psize ;
// PayloadSize [ Byte ]
mode ;
// Kommun ikation smodus
sem ;
// S y n c h ro n i s a ti o n s ob j e k t
sock ;
// Ko mm uni ka tio nso bj ekt
seq ;
// Bisher gesendete Pakete
* sendAddr ;
// Mcast - Addr
addrLen ;
// Länge von sendAddr
(* send ) ( struct chDescr * channel , void * buf , size_t size ) ;
(* recv ) ( struct chDescr * channel , void * buf , size_t size ) ;
Die chDescr-Struktur hält alle Informationen, die mit dem Kanalendpunkt assoziiert
werden.
mode wird von der Funktion chOpen() des chContr-Moduls gesetzt und entspricht
dem Parameter der gleichen Bezeichnung.
Das Kommunikationsobjekt ist in Form des Socket-File-Deskriptors(sock), der sockaddr
-Struktur und den Zeigern auf die Funktionen (*send)() und (*recv)() in die Struktur integriert. Die Einbindung des Members addrLen ist vorgesehen, da bei verschiedenen Layer-2-Protokollen unterschiedliche sockaddr-Strukturen eingesetzt werden,
deren Größe variiert. Aus diesem Grund kann keine statische sockaddr-Struktur eingefügt werden, sondern ein Zeiger.
Das Datenmember sem hält den Deskriptor des Semaphors, dass als Synchronisationsobjekt dient.
Beim Anlegen der chDescr-Objekte werden zunächst nur die ID und die QoS-Parameter
initialisiert. Solange der Kanalendpunkt geschlossen ist, bleiben sock und sem auf 0
bzw. -1.
Im chDescr-Modul sind die Basis-Kommunikationsfunktionen basicModeSend() und
basicModeRecv() implementiert, die den Methoden (*send)() und (*recv)() zugewiesen werden, wenn beim Öffnen des Kanals CH_BASIC_MODE übergeben wird (Listing
5.2).
93
5.5. chAvailContr
Kapitel 5. Implementierung
Implementierungsaufwand
Datei
Zeilen (ohne Kommentare)
chDescr.h
36
chDescr.c
40
Gesamt
76
Tabelle 5.3: Implementierungsaufwand chDescr
5.5
chAvailContr
Bei der Initialisierung des Moduls wird eine boolsche Variable im Parameter initShm
übergeben. Ist diese auf TRUE gesetzt, wird das Shared-Memory-Segment erzeugt und
mit 0 initialisiert. Ansonsten wird das existierende Shared-Memory-Segment in den
lokalen Adressraum eingeblendet.
Wird mittels der Funktion addChAvailEntry() ein neuer Eintrag dem Shared-MemorySegment hinzugefügt, wird überprüft, ob mehr als ein Prozess auf den Kanal, für den
dieser Eintrag gilt, zugreifen darf. Ist das der Fall, wird für den Kanal ein Semaphor
erzeugt und dessen Erzeugungsschlüssel im Eintrag abgelegt.
Beim Befüllen des Shared-Memory-Segments mit chAvail-Einträgen wird eine Fehlermeldung ausgegeben, falls das Ende des Segments erreicht wird. Um festzustellen
wo sich der nächste freie Eintrag befindet, macht sich das Programm zunutze, dass
kein Kanal mit der ID 0 existieren kann und das Shared-Memory-Segment mit Null
initialisiert wird. Listing 5.7 zeigt die dafür verwendete Suchschleife.
Quelltext 5.7: Suchschleife in
1
2
3
chAvailContr
for ( i = 0; ( chAvailTable [ i ]. id != 0) ||( sizeof ( struct chAvail ) > ( PAGE_SIZE - i *
sizeof ( struct chAvail ) ) ; i ++) {
...
}
Beim Schließen der Bibliothek wird am Shared-Memory-Segment überprüft, ob der
aufrufende Prozess der letzte darauf zugreifende ist. Dies geschieht durch einen Aufruf des Systemcalls shmctl() wie in Lisiting 5.8 dargestellt.
Quelltext 5.8: Abruf der Shm-Statistiken
1
shmctl ( shmID , IPC_STAT , & shmParam ) ;
94
Kapitel 5. Implementierung
5.6. chDev
Im shmParam.shm_nattach ist daraufhin die Anzahl der auf das Shared-MemorySegment zugreifenden Prozesse zu finden. Ist der Prozess der letzte zugreifende, so
werden die Semaphoren aller Kanäle und das Shared-Memory-Segment zerstört.
Implmentierungsaufwand
Datei
Zeilen (ohne Kommentare)
chAvailContr.h
30
chAvailContr.c
245
Gesamt
275
Tabelle 5.4: Implementierungsaufwand chAvailContr
5.6
chDev
Im Klassendiagramm wird gezeigt, dass die Utitltiy-Klasse chDev über zwei abstrakte
Methoden verfügt, die durch Ableitung der Klasse überschrieben werden können.
Im Modul chDev sind die zwei statischen, globalen Zeiger (*bindChannelP)() und
(*releaseChannelP)() deklariert, die diese abstrakten Methoden repräsentieren.
Bei Initialisierung wird der Adresstyp des Devices ermittelt, dessen Namen als Parameter der Funktion initDev übergeben wird. Aufgrund des Adresstyps wird ermittelt
welche Implementierungen der Funktionen bindChannel() und releaseChannel()
den Zeigern zugewiesen werden.
vlan
Handelt es sich bei dem Adresstyp um Ethernet, werden die virtuellen Devices erzeugt. Alle dafür nötigen ioctl()-Zugriffe werden von der dafür implementierten
Konfigurationsbibliothek vlan gekapselt.
Nach oben bietet die Bibliothek sowohl Funktionen zum Anlegen und Löschen von
virtuellen Devices, als auch zum Setzen der Ingress- und Egress-Priority-Maps. Eine
Besonderheit stellt die Funktion addBE_VLAN() dar, da sie ein virtuelles Device erzeugt, das die IP-Adresse des physikalischen Devices auf das virtuelle überträgt und
dessen MTU setzt. Die Funktion remBE_VLAN() macht diese Konfigurationen wieder
rückgängig.
95
5.6. chDev
Kapitel 5. Implementierung
devInfo
Das devInfo-Modul definiert die Struktur devInfo, die Name, Index und Addresstyp
eines Devices enthält. Zum Abrufen dieser Daten ist die Funktion initDevInfo()
definiert, die diese über ioctl()-Aufrufe bezieht.
chEth
Dieses Modul definiert die Funktionen chEthBind()und chEthRealease(), welche
die Ethernet-spezifischen Implementationen bindChannel() und releaseChannel()
-Methoden sind. Man kann im objekt-orientierten Sinne davon sprechen, dass chEth
eine abgeleitete Klasse von chDev ist.
Die Funktion chEthBind() öffnet einen Paket-Socket und weißt den zurückgegebenen Socket-Fileskriptor den sock-Member derchDescr-Struktur zu, die als Parameter
übergeben wurde. Anschließend wird eine sockaddr_ll-Struktur allokiert und dem
addr-Member zugewiesen. Diese Struktur ist speziell für Packet-Sockets spezifiziert
und erhält als Adressinformationen die Multicast-Adresse des Kanals und den Index
des virtuellen Devices. Mit diesen Daten wird der Socket an das Device gebunden
und anschließend in eine Multicast-Gruppe im Treiber eingetragen.
Die Funktion chEthRelease() entfernt den Socket wieder aus der Multicast-Gruppe
und schließt ihn. Anschließend gibt er den Speicher des addr-Members frei.
Datei
Zeilen (ohne Kommentare)
chDev.h
11
chDev.c
125
chEth.h
9
chEth.c
135
devInfo.h
11
devInfo.c
125
vlan.h
11
vlan.c
295
Gesamt
722
Tabelle 5.5: Implementierungsaufwand chDev
96
Kapitel 5. Implementierung
5.7
5.7. chQoSContr
chQoSContr
Bei Initialisierung des chQoSContr-Moduls wird zunächst die Kommunikationsverbindung zum Kern aufgebaut. Zu diesem Zweck wird die in der iproute2-Utility-Suite
beiliegende libnetlink-Bibliothek integriert. Mit der Funktionrtnl_open() wird eine globale rtnl_handle-Struktur initialisiert, die für die gesamte Kommunikation
genutzt wird.
Eine andere Funktion, die von iproute2 übernommen wird, ist tc_core_init(), die
die in Kapitel 3.4.4 beschriebenen Timer-Werte initialisiert.
Wie in Kapitel 4.7 erläutert wird, sind die Filtereinstellungen von dem verwendeten Layer-2-Protokoll abhängig. Daher werden in der initQoS() die Filterregeln für
die Filter der Prio-Klassen, der Best-Effort-Klasse und der einzelnen Kanal-Klassen
abhängig vom Adresstyp des verendeten Devices initialisiert. Der Wert des BestEffort-Filters ist fest (VID 3), die Werte der Prio- und Kanal-Filter jedoch sind
Variabel (User Prio bzw. Kanal ID). Daher bekommen sie zu Anfang keinen Wert in
für .val zugewiesen, sondern in einer eigenen Variablen einen Bit-Shift-Offset, der
anzeigt wo in dem 32 Bit breiten Suchmuster, sich der zu suchende Wert befinden
muss, um erkannt werden zu können.
An der Funktion initQoS() wird nun exemplarisch die Konfiguration von QDiscs,
Klassen und Filtern gezeigt. Für die Funktionen addChQoS() und remChQoS() sei nur
erwähnt, dass diese die Konfiguration wie in Kapitel 4.7 vorgesehen durchführen.
In Listing 5.9 zeigt, wie das für den Filter der Prio-QDisc umgesetzt wurde.
Quelltext 5.9: Filter-Selector für Prio-QDisc
1
2
3
4
prSel . sel . nkeys = 1;
// Prio - Filter ( User - Priority in VLAN - Tag )
prSel . keys [0]. mask = htonl (0 xE0000000 ) ;
prSel . keys [0]. val = 0;
prSelOff = 29;
// Anzahl der Bit um die geshiftet werden muss
Die Listings 5.10, 5.12 und 5.13 zeigen die QDisc-Basis-Konfiguration, wie sie in
Kapitel 4.7 beschrieben ist. In Listing 5.10 wird die Prio-QDisc mit acht Bändern
parametrisiert und dann konfiguriert.
97
5.7. chQoSContr
Kapitel 5. Implementierung
Quelltext 5.10: Hinzufügen der Prio-QDisc
1
2
3
4
5
prio_opt . bands = 8;
if ( addQDisc (& rth , TC_H_ROOT , 0 x7FFF0000 , prio , ( void *) & prio_opt , devIndex ) < 0
) {
rtnl_close (& rth ) ;
return -1;
}
Danach werden die HTB-QDiscs und der Filter für jede Klasse der Prio-QDisc hinzugefügt (Listing 5.12). Zeile 2 zeigt wie der User-Priority-Wert (userPrio), mit Hilfe
des Arrays aus Listing 5.11, auf die Minor-Nummern der Prio-Klassen abgebildet
wird. In Zeile 9 wird das Suchmuster für jeden Filter berechnet, indem der UserPriority-Wert, um die in Listing 5.9 definierten Anzahl Bits, nach links verschoben
wird.
Quelltext 5.11: User-Priority auf Prio-QDisc Mapping
1
2
3
4
5
6
7
8
9
10
11
static unsigned
//
6,
//
8,
//
7,
//
5,
//
4,
//
3,
//
2,
//
1
//
};
char prioMap [8] = {
UP Handle
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
Quelltext 5.12: Basis-QDiscs und Filter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for ( userPrio = 0; userPrio < 8; userPrio ++) {
parent = 0 x7FFF0000 + prioMap [ userPrio ];
handle = ( userPrio +1) << 16;
if ( addQDisc (& rth , parent , handle , htb , ( void *) & htb_opt , devIndex ) < 0) {
rtnl_close (& rth ) ;
return -1;
}
prSel . keys [0]. val = htonl ( userPrio << prSelOff ) ;
flowid = parent ;
if ( addFilter (& rth , 0 x7FFF0000 , 0 , flowid , ETH_P_8021Q , prioMap [ userPrio ] , u32
, & prSel , devIndex ) < 0) {
rtnl_close (& rth ) ;
return -1;
}
}
Nachdem die Grundkonfiguration von QDiscs und Filtern erfolgt ist, wird noch die
Klasse und der Filter für den Best-Effort-Verkehr hinzugefügt (Listing 5.13). In den
98
Kapitel 5. Implementierung
5.7. chQoSContr
Zeilen 1 bis 4 wird gezeigt, wie die Parameter der HTB-Klasse nach den Vorgaben in Kapitel 4.7 zugewiesen werden. Die Parameter sind im Einzelnen in Kapitel
3.4.4 beschrieben. Der Quelltext der Funktion get_cell_log() entstammt der Funktion tc_calc_rtable(). Diese ist in der Datei tc core.c implementiert und ist Teil
der iproute2-Utility-Suite. Sie wird kopiert und in die zwei einzelnen Funktionen
get_cell_log() und calc_rtable() unterteilt, damit deren Funktionalitäten separat verfügbar sind.
get_cell_log() generiert den binären Logarithmus der maximalen Tokengröße, in
Abhängigkeit von der maximalen Paketgröße, wie in Kapitel 3.4.4.4 beschrieben.
Die Funktion calc_rtable() errechnet die Rate-Table für eine HTB-Klasse. Sie wird
bei der Generierung von Netlink-Messages für diese Klasse eingesetzt, was in Listing
5.18 gezeigt wird.
Abschließend wird noch die SFQ-QDisc und der Filter für den Best-Effort-Verkehr
hinzugefügt.
Quelltext 5.13: Hinzufügen der Best-Effort-Klasse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
htb_copt . rate . cell_log = get_cell_log ( mtu + FRM_OVRHD ) ;
htb_copt . rate . mpu = mpu ;
htb_copt . rate . rate = maxbw ;
htb_copt . cbuffer = mtu + FRM_OVRHD ;
if ( addClass (& rth , 0 x00020000 , 0 x0002FFFF , htb , ( void *) & htb_copt , devIndex ) <
0) {
rtnl_close (& rth ) ;
return -1;
}
sfq_opt . perturb_period = 10;
if ( addQDisc (& rth , 0 x0002FFFF , 0 x00000000 , sfq , ( void *) & sfq_opt , devIndex ) < 0)
{
rtnl_close (& rth ) ;
return -1;
}
if ( addFilter (& rth , 0 x00020000 , 0 x00000000 , 0 x0002FFFF , ETH_P_8021Q , 8 , u32 , (
void *) & beSel , devIndex ) < 0) {
rtnl_close (& rth ) ;
return -1;
}
99
5.7. chQoSContr
Kapitel 5. Implementierung
qDisc und filter
Für die Konfiguration der Queueing Disziplinen, sowie deren Klassen und Filter, wird
eine eigene Bibliothek implementiert, die Funktionen zum Hinzufügen und Löschen
bietet.
Diese Funktionen sind sich im Aufbau sehr ähnlich und werden im Folgenden an
der Funktion addQDisc() erläutert (Listings 5.14 und 5.15). Zunächst wird eine
Request-Struktur (req) deklariert, die ein Netlink-Message inklusive Netlink-Header,
tc-Message und Speicher für Attrtbute reserviert. Die Member der Struktur bekommen Werte, entsprechend der in Kapitel qdiscconf erläuterten Konfigurationsbeschreibung, zugewiesen.
Quelltext 5.14: Setzen der QDisc-Basis-Parameter
1
2
3
4
5
6
7
8
9
memset (& req , 0 , sizeof ( req ) ) ;
req . nlh . nlmsg_len
= NLMSG_LENGTH ( sizeof ( struct tcmsg ) ) ;
req . nlh . nlmsg_type = RTM_NEWQDISC ;
req . nlh . nlmsg_flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE ;
req . tcm . tcm_family
req . tcm . tcm_ifindex
req . tcm . tcm_handle
req . tcm . tcm_parent
=
=
=
=
AF_UNSPEC ;
devIndex ;
handle ;
parent ;
Welche QDisc erzeugt werden soll, wird mit dem Parameter qdisc bestimmt. Aufgrund dessen Wert wird eine QDisc spezifische Netlink-Message generiert.
Quelltext 5.15: Generieren der Netlink-Message
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
switch ( qdisc ) {
case prio :
genPrioNLMsg (& req . nlh , ( struct tc_prio_qopt *) param ) ;
break ;
case htb :
genHTBNLMsg (& req . nlh , ( struct tc_htb_glob *) param ) ;
break ;
...
case sfq :
genSFQNLMsg (& req . nlh , ( struct tc_sfq_qopt *) param ) ;
break ;
default :
return -1;
}
}
Abschließend wird die Message über die Funktion rtnl_talk() aus der Bibliothek
100
Kapitel 5. Implementierung
5.7. chQoSContr
libnetlink an den Kernel gesandt.
Quelltext 5.16: Versenden der Netlink-Message
1
2
3
4
5
6
if ( rtnl_talk ( rth , & req . nlh , 0 , 0 , NULL , NULL , NULL ) < 0) {
return -1;
}
return 0;
}
Die Funktionen zum Generieren von Netlink-Messages, übernehmen die für sie definierten Strukturen und fügen je nach verwendeter QDisc Attribute hinzu. Dazu
wird die Funktion addattr_ll() genutzt, die ebenfalls Bestandteil der libnetlinkBibliothek ist. In Listing 5.17 wird gezeigt, wie die Attribute für die SFQ-QDisc in
der Funktion genSFQNLMsg() hinzugefügt werden.
Quelltext 5.17: Hinzufügen von Attributen
1
2
3
4
5
int genSFQNLMsg ( struct nlmsghdr *n , struct tc_sfq_qopt * opt ) {
addattr_l (n , 1024 , TCA_KIND , " sfq " , 4) ;
addattr_l (n , 1024 , TCA_OPTIONS , opt , sizeof ( struct tc_sfq_qopt ) ) ;
return 0;
}
Die Generierung von Attributen der HTB-Klasse gestaltet sich etwas komplizierter.
Für sie müssen noch die beiden Rate-Tabellen erzeugt werden und die angegebenen
burst und cburst-Parameter in Sendezeiten umgewandelt werden, wie es im Kapitel
3.4.4 beschrieben wurde. Dies geschieht mit der Funktion calc_rtable(), die, wie
schon vorher im Abschnitt erwähnt, aus der Funktion tc_calc_rtable ausgeschnitten wurde. Ist der Parameter buffer kleiner als der berechnete Mindestwert, wird
der Mindestwert zugewiesen.
Die Byte-Werte für buffer und cbuffer werden mit der Funktion tc_calc_xmittime
() aus der iproute2-Utility-Suite in die Sendezeit umgerechnet.
Anschließend werden alle Attribute an die Netlink-Message angehängt.
Quelltext 5.18: Generieren einer Netlink-Message für eine HTB-Klasse
1
2
3
4
5
6
7
8
9
int genHTBClassNLMsg ( struct nlmsghdr *n , struct tc_htb_opt * opt )
{
__u32 rtab [256] , ctab [256];
unsigned buffer =0 , cbuffer =0;
struct rtattr * tail ;
if (! opt - > ceil . rate ) opt - > ceil = opt - > rate ;
buffer = opt - > rate . rate / get_hz () ; // min ;
101
5.7. chQoSContr
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Kapitel 5. Implementierung
if ( opt - > buffer > buffer )
buffer = opt - > buffer ;
cbuffer = opt - > cbuffer +50;
calc_rtable (& opt - > rate , rtab ) ;
opt - > buffer = tc_calc_xmittime ( opt - > rate . rate , buffer ) ;
calc_rtable (& opt - > ceil , ctab ) ;
opt - > cbuffer = tc_calc_xmittime ( opt - > ceil . rate , cbuffer ) ;
addattr_l (n , 1024 , TCA_KIND , " htb " , 3) ;
tail = ( struct rtattr *) ((( void *) n ) + NLMSG_ALIGN (n - > nlmsg_len ) ) ;
addattr_l (n , 1024 , TCA_OPTIONS , NULL , 0) ;
addattr_l (n , 2024 , TCA_HTB_PARMS , opt , sizeof ( struct tc_htb_opt ) ) ;
addattr_l (n , 3024 , TCA_HTB_RTAB , rtab , 1024) ;
addattr_l (n , 4024 , TCA_HTB_CTAB , ctab , 1024) ;
tail - > rta_len = ((( void *) n ) + NLMSG_ALIGN (n - > nlmsg_len ) ) - ( void *) tail ;
return 0;
}
Datei
Zeilen (ohne Kommentare)
chQosContr.h
10
chQoSContr.c
341
qDisc.h
21
qDisc.c
208
filter.h
13
filter.c
108
qFIFO.h
7
qFIFO.c
19
qSFQ.h
6
qSFQ.c
13
qPrio.h
6
qPrio.c
16
qHTB.h
7
qHTB.c
78
fU32.h
11
fU32.c
36
Gesamt
900
Tabelle 5.6: Implementierungsaufwand chQoSContr
102
Kapitel 5. Implementierung
5.8
5.8. Testapplikation
Testapplikation
Zum Testen der Basisfunktionalität der Bibliothek steht die menügeführte Applikation channelapp zur Verfügung. Mit ihr lassen sich die Bibliothek und Kanäle öffnen
und schließen, sowie einzelne Pakete versenden und empfangen. Durch mehrere Instanzen ist der wechselseitige Ausschluss für den Kanalzugriff validierbar.
Um die Konfiguration der Queueing-Disziplinen zu prüfen, kann das Tool TC eingesetzt werden. Im Folgenden sollen die wichtigsten Befehle zur Überprüfung der
Konfiguration genannt werden:
1
2
3
# tc [ - s ] qdisc sh [ dev < devname >]
# tc [ - s ] class sh dev < devname >
# tc filter sh dev < devname > [ parent < handle >]
Der erste Befehl zeigt die Liste der angelegten QDiscs an. Mit der Option ’-s’ werden
noch statistische Informationen, wie die Anzahl Pakete und Bytes, die die QDisc
passiert haben, angezeigt.
Der zweite Befehl zeigt die erzeugten Klassen an. Hier muss darauf geachtet werden,
dass der Device-Name spezifiziert wird, da sonst keine Ausgabe erfolgt.
Mit dem letzten Befehl werden die angelegten Filter angezeigt. Wie bei den Klassen,
muss auch hier der Device-Name angegeben werden. Der Befehl zeigt immer nur
die Filter an, die an einem Knoten sitzen. Wird der Elternknoten nicht explizit
angegeben, so werden die Filter an TC_H_ROOT ausgegeben.
Implementierungsaufwand
Datei
channelapp.c
Zeilen (ohne Kommentare)
127
Tabelle 5.7: Implementierungsaufwand Testapplikation
103
5.10. Kompilierung und Installation
5.9
Kapitel 5. Implementierung
Gesamtaufwand
Modul
Zeilen (ohne Kommentare)
chConfRead
360
chContr
648
chDescr
76
chAvailContr
275
chDev
722
chQoSContr
900
4
209
chMsr
channelapp
127
5
msrSend
87
msrRecv6
75
Gesamt
3270
Tabelle 5.8: Implementierungsaufwand chQoSContr
5.10
Kompilierung und Installation
Auf der CD ist ein tar-Archiv der Bibliothek enthalten, dem ein Makefile beiliegt.
Im Makefile sind unter der Option LIBCFLAGS drei #define-Schalter, die den Umfang des zu kompilierenden Quellcodes steuern. _EMSG_ sorgt dafür, dass für jeden
Fehler eine Ausgabe auf stderr erscheint, während _DEBUG_ eine Ausgabe von DebugInformationen auslöst, die zum Testen der Bibliothek genutzt werden. Der Schalter
_CH_TEST_ entscheidet, ob die Instrumentierung des Quellcodes für die Bewertung
mit in die Bibliothek eingebunden wird.
Durch Ausführung von make wird die Bibliothek kompiliert. make clean entfernt
alle ausführbaren Dateien und den Objektcode.
Um die Bibliothek in ein Programm einzubinden, wird die Headerdatei channel.h
und der Pfad zu den Bibliotheksdateien libchannel.so, libchannel.so.0 und libchannel.so.0.0 benötigt. Dieser muss mit dem Befehl export LD LIBRARY PATH=<path>
bekannt gemacht werden. Außerdem müssen bei der Kompilierung die Optionen -L
<path> und -lchannel angehängt werden.
4
s. Kapitel 6.3
s. Kapitel 6.5
6
s. Kapitel 6.5
5
104
Kapitel 5. Implementierung
5.11. Aufgetretene Probleme
Bei der Verwendung der Bibliothek ist unbedingt darauf zu achten, dass vor dem
Beenden der Applikation die Funktion closeChannels() aufgerufen wird. Geschieht
dies nicht, können Betriebsmittel, wie Semaphoren, nicht freigegeben und die Einstellungen an den Queueing-Disziplinen und dem Netzwerk-Device nicht rückgängig
gemacht werden. Aus diesem Grund sollten entsprechende Signale abgefangen und
die Bibliothek geschlossen werden.
5.11
Aufgetretene Probleme
Während der Implementierung sind einen Reihe von Problemen aufgetreten, die auf
Eigenheiten im Betriebssystem zurückzuführen sind. Diese sollen hier mit entsprechender Lösung, falls vorhanden, vorgestellt werden.
Laut der manpage packet(7) kann ein Packet-Socket, mit der Hilfe der Optionen
PACKET_ADD_MEMBERSHIP und PACKET_DROP_MEMBERSHIP, explizit an eine MulticastAdresse gebunden bzw. von einer Multicast-Adresse entbunden werden. Beim Testen
der Applikation werden jedoch an einem Kanalendpunkt Nachrichten eines anderen
Kanals empfangen, obwohl dessen Multicast-Adresse von keinem Kanal auf der Empfängerseite konfiguriert wurde. Die Ursache liegt in der verwendeten Netzwerkkarte
und deren Linux-Treiber. Die Unterstützung von Multicast-Filterung ist von Treiber
zu Treiber unterschiedlich. Diesem Problem wird aus Zeitgründen und der Tatsache,
dass dessen Lösung der zentralen Kernproblemstellung der Arbeit nicht zuträglich
ist, nicht weiter nachgegangen.
Ein weiteres Problem ist, dass bei Sendungen von Paketen in kurzen Intervallen
Kernel-Panics ausgelöst werden können. Dies liegt daran, dass niederpriore Prozesse
unterbrechbar sind, selbst wenn sie sich gerade, durch Ausführung eines Systemcalls,
im Kernel-Adressraum aufhalten.
Das 802.1Q-Modul unter Linux ist für die Unterbrechungen nicht ausgelegt. Eine Lösung wäre es, für Prozesse, die Kanäle nutzen, einen Real-Time Scheduler einzusetzen
und dem Prozess eine höhere Priorität zu verleihen. Dadurch würde der Prozess im
Kern-Modus nicht mehr unterbrochen werden. Da jedoch Best-Effort-Applikationen
auch über VLANs versendet werden, kann diese Option nur eingesetzt werden, wenn
alle Applikationen, die Netwerkressourcen benötigen, einen höhere Priorität zugeordnet bekommen.
Eine andere Lösung ist die Kernel-Option CONFIG_PREEMPT, wie in Abschnitt 5.1 angegeben, auszuschalten. Somit können niederpriore Prozesse nicht mehr im Kernel-
105
5.11. Aufgetretene Probleme
Kapitel 5. Implementierung
Modus unterbrochen werden, was bedeutet, dass leicht erhöhte Latenzen für die
Aktivierung von hochprioren Prozessen auftreten können.
In [Hub03] ist angegeben, dass Filter Pakete an Klassen über mehrere Level hinweg
weiterreichen können. Dies ist auch in den meisten Anleitungen im Internet angegeben. Auf den in Abschnitt 5.1 angegeben Rechnern läßt sich das nicht bestätigen.
Werden Filter an einer QDisc angebracht, deren Flow-ID eine Major-Nummer aufwiest, die nicht der Major-Nummer der Eltern-QDisc des Filters entspricht, treten
die Pakete, die auf die Filter-Regel zutreffen, nicht in den Statistiken der entsprechenden Blatt-QDisc auf. Erst wenn für jede klassenbehaftete QDisc eine eigene
Filter-Instanz erzeugt wird, kommen die Pakete bei der Blatt-QDisc an.
106
Kapitel 6
Bewertung
In diesem Abschnitt wird eine Bewertung der gewählten Konfiguration der Queueing
Disziplinen anhand von Messungen vorgenommen.
6.1
Messumgebung
Die Messungen werden mit den in 5.1 beschriebenen Rechnern, in einem von einem
Cisco Catalyst 2950 Switch vermittelten Netz durchgeführt. Drei dieser Rechner sind
in Sterntopologie um den Switch angeordnet, wobei einer davon den Datenverkehr
auf dem Switch mit dem Programm Tethereal aufzeichnet.
Der Switch verfügt über vier Ausgangsqueues pro Port, die über ein Strict-PriorityQueueing bedient werden. Die Konfiguration des Switches beinhaltet die Einrichtung
der beteiligten Ports als Trunk-Ports für VLAN 1-3, wobei VLAN 1 alle EthernetFrames bediente, die kein VLAN-Tag enthalten. Weiterhin wurden für die MulticastAdressen, der an der Messung beteiligten Kanäle, statische Einträge in der MACAdress-Tabelle des Switches vorgenommen.
Dis Konfigurationsdatei des Switches liegt im Verzeichniss Messungen/Switchkonfiguration der CD.
6.2
Messgrößen
Gemessen wurden sowohl die Ende-zu-Ende-Propagationszeit zwischen zwei Rechnern, als auch die Verweilzeit eines Pakets innerhalb der Queueing Disziplinen. Um
107
6.3. Instrumentierung
Kapitel 6. Bewertung
eine Korrelation der Daten zu ermöglichen wird auch die Zeit gemessen, die ein Paket benötigt, um vom Eintritt in den Systemcall zur enqueue()-Funktion der QDisc
zu gelangen.
6.3
Instrumentierung
Die Messung wird durch eigens implementierte send()- und recv()-Methode am
chDescr-Objekt des zu messenden Kanals angestoßen. Diese sind instrumentiert um
zwei verschiedene Messungen vorzunehmen, die anschließend korreliert werden. Die
Methoden testModeSend() und testModeRecv() sind im Modul chMsr definiert.
6.3.1
Ende-zu-Ende Propagation
Um die Ende-zu-Ende Propagation und den Jitter bei Paketankunft zu messen,
wurde eine Bibliothek von Dipl. Inf. Bernharg Gelling geschrieben, deren Funktion 8Bit Information aufnimmt und diese am Parallel-Port des Testrechners ausgibt. Diese
Informationen wurden von einem Logic-Analyzer aufgezeichnet und anschließend in
Excel weiterverarbeitet.
Von den acht zur Verfügung stehenden Bit, wurden drei genutzt um die Kanal-ID
zu codieren und die restlichen fünf, für die Sequenznummer der Pakete verwendet.
Die send()-Methode wurde direkt vor dem Aufruf des sendto()-Systemcalls mit der
Funktion zum Setzen des Parallelports instrumentiert, während die recv()-Methode
direkt nach dem Aufruf des recv()-Systemcalls instrumentiert wurde.
6.3.2
Delay durch
sendto-Systemcall
und QDisc
Für die interne Delay-Messung wurde das Time-Stamp-Register der CPU genutzt.
Für diesen Zweck wird das Messmodul chMsr implementiert, mit dem verschiedene
Punkte im Betriebssystem instrumentiert werden.
Um den Delay innerhalb des Systemcalls und der QDisc zu messen, wird der PaketPfad an drei Punkten instrumentiert: In der send-Methode, am QDisc-Eingang und
am QDisc-Ausgang. An jedem dieser Punkte wird der Wert aus dem Time Stamp
Register der CPU ausgelesen und im Paket eingefügt. Dazu wird in das Paket eine Struktur eingefügt, die aus einem Header und drei 64-Bit Zeitstempel besteht
(Listing 6.1).
108
Kapitel 6. Bewertung
6.3. Instrumentierung
Quelltext 6.1: Die
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
msrFrm-Struktur
union msrPnt {
__u32 part [2];
__u64 value ;
};
struct msrHdr {
__u16 mark ;
__u16 chID ;
__u32 seq ;
__u32 cpu ;
__u8 wPos ;
};
struct msrFrm {
struct msrHdr hdr ;
union msrPnt tsc [ MAX_MSR_PNTS ];
char
buf [ MAX_MSR_PAYL ];
};
Der Header beginnt mit dem Erkennungsmuster 0x7FFE, über das festgestellt werden
kann, ob es sich um ein Testpaket handelt. Danach folgen Informationen über die
Kanal-ID, die Sequenznummer des Pakets und die Taktfrequenz der CPU. Letzteres
ist nötig, da die Zeitinformationen auf einem anderen Rechner ausgewertet werden,
der evtl. eine andere Taktfrequenz besitzt.
Headerinformationen werden in der send()-Methode gesetzt, wo auch der erste Zeitstempel, kurz vor dem Versenden des Pakets, gesetzt wird (Listing 6.2).
Quelltext 6.2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
testModeSend()-Funktion
int testModeSend ( struct chDescr * channel , void * buf , size_t size ) {
struct msrFrm frame ;
int sentData ;
memset (& frame , ( unsigned ) 0 , sizeof ( frame ) ) ;
frame . hdr . mark
frame . hdr . seq
frame . hdr . chID
frame . hdr . cpu
=
=
=
=
htons (0 x7FFE ) ;
htonl ( channel - > seq ) ;
htons ( channel - > id ) ;
htonl ( cpukHz ) ;
memcpy (( void *) & frame . buf , buf , size < MAX_MSR_PAYL ? size : MAX_MSR_PAYL ) ;
addMsrPoint (& frame ) ;
llaappch_write ( channel - > id , ( unsigned short ) channel - > seq ) ;
sentData = sendto ( channel - > sock , ( void *) & frame , size , 0 , channel - > sendAddr ,
channel - > addrLen ) ;
channel - > seq ++;
return sentData ;
}
109
6.3. Instrumentierung
Kapitel 6. Bewertung
Im Kern wird vor dem Aufruf der enqueue()-Funktion der QDisc ermittlet, ob ein
Frame mit einem VLAN-Tag das Muster für ein Testpaket enthält. Ist das der Fall,
wird ein Zeitstempel genommen und an der nächsten freien Stelle im Paket eingefügt
(Listing 6.3).
Quelltext 6.3: Instrumentierung an der
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
enqueue()-Funktion
spin_lock_bh (& dev - > queue_lock ) ;
/* Instrumetation for ChannelDelay Measurement */
if ( skb - > protocol == htons (0 x8100 ) ) {
struct msrFrm * frm ;
__u32 upper , lower ;
frm = ( struct msrFrm *) ( skb - > data + ( sizeof ( struct ethhdr ) + 4) ) ;
if ( frm - > hdr . mark == htons (0 x7FFE ) && frm - > hdr . wPos < MAX_MSR_PNTS ) {
rdtsc ( lower , upper ) ;
frm - > tsc [ frm - > hdr . wPos ]. part [ UPPER ] = htonl ( upper ) ;
frm - > tsc [ frm - > hdr . wPos ]. part [ LOWER ] = htonl ( lower ) ;
frm - > hdr . wPos ++;
}
}
/* End of Instrumentation */
rc = q - > enqueue ( skb , q ) ;
qdisc_run ( dev ) ;
spin_unlock_bh (& dev - > queue_lock ) ;
Der letzte Zeitstempel wird nach dem Aufruf der Funktion dequeue() an der QDisc
genommen und in das zurückgelieferte Paket eingefügt, sofern es sich um ein Testpaket handelt.
Die Pakete werden von dem Netzwerk-Analyzer tethereal aufgezeichnet und anschließend mit zwei Perl-Skripten in eine von Excel lesbare Form gebracht. Damit werden
Diagramme zur Visualisierung des Delays erstellt.
110
Kapitel 6. Bewertung
6.4. Lastmodell
Instrumentierungsaufwand
Datei
Zeilen (ohne Kommentare)
chMsr.h
37
chMsr.c
148
dev.c
1
12
sch generic.c2
12
Gesamt
209
Tabelle 6.1: Implementierungsaufwand Instrumentierung
6.4
Lastmodell
Das Lastmodell ist dahingehend konzipiert, dass die Dauerlast unterhalb der Linkkapazität des Netzwerkinterface (R = 12, 5Bytes/µs) bleibt. Damit können Stausituationen, die durch Bursts entstehen, wieder abgebaut werden und es entsteht kein
dauerhaftes Aufstauen von Paketen.
Exemplarisch wird hierzu die isochrone Propagation von Steuerdaten aufgegriffen,
wie sie im Use-Case Steuern und Regeln beschrieben wurde. Im Folgenden werden drei Lastkonfigurationen betrachtet (Tabelle 6.2), die sich in Paketgröße3 , und
Propagationsintervall unterscheiden. Jede Konfiguration besteht aus drei Kanälen,
wobei zwei Kanäle eine Priorität von vier und ein Kanal eine Priorität von sieben
aufweist. Der Kanal mit der hohen Priorität besitzt außerdem ein größeres Propagationsintervall.
Lastkonf.
Paketgröße
Intervall Prio 4
Intervall Prio 7
1
200Byte
50µs
100µs
2
500Byte
100µs
500µs
3
1496Byte
300µs
900µs
Tabelle 6.2: Lastkonfigurationen
Zur Ermittlung der verbrauchten Bandbreite der einzelnen Kanäle, wurde die FrameGröße der Lastkonfigurationen inklusive Präambel, Header, CRC und IFG zu Grun1
Kernel-Quelltext /usr/src/linux/net/core/dev.c
Kernel-Quelltext /usr/src/linux/net/sched/sch generic.c
3
Paketgröße bedeutet hier reine Payload
2
111
6.4. Lastmodell
Kapitel 6. Bewertung
de gelegt (Tabelle 6.3).
Lastkonf.
Framegröße Bandbreite
Prio 4
Bandbreite
Prio 7
Bandbreite
gesamt
1
242Byte
4, 48Byte/µs
2, 24Byte/µs
12, 1Byte/µs
2
542Byte
5, 24Byte/µs
1, 084Byte/µs
11, 924Byte/µs
3
1538Byte
5, 125Byte/µs
1, 71Byte/µs
11, 96Byte/µs
Tabelle 6.3: Genutzte Bandbreite der Lastkonfigurationen
Aufgrund der gewählten Lastkonfigurationen wurden die maximal auftretenden Delays mit der Formel 3.11 aus Kapitel 3.3.3.1 voraus berechnet. Der konstante DelayParameter T der Servicekurve wurde durch eine Messung des Delays in der QDisc
ermittelt. Dazu wurden 10000 Pakete in einem Intervall auf einem Kanal gesendet, der keinen Stau verursachen würde. Somit konnte der Durchschnitts-Delay in
der QDisc ermittelt werden. Dieser Beträgt 0.855µs und wird als Grundlage für die
Berechnung der Werte in Tabelle 6.4 verwendet.
Lastkonf.
Delay Prio 4
Delay Prio 7
1
58, 935µs
20, 215µs
2
130, 935µs
44, 215µs
3
369, 975
123, 895µs
Tabelle 6.4: Maximaler Delay der Kanäle in der Queueing
Disziplin
Um Vergleichsmöglichkeiten zu haben wurde das Lastmodell außer mit der für die
Implementierung vorgesehenen, noch mit zwei weiteren Queueing-Disziplin-Konfigurationen gemessen: eine Prio-QDisc ohne Bandbreitenbegrenzer und eine reine
FIFO-QDisc.
Ein weiteres Messzenario untersucht das Verhalten eines Kanals unter massiver Störlast durch Best-Effort-Verkehr. Hierzu wird je ein einzelner Kanal mit der Priorität
7 bzw. 1 und einem Sendeintervall von 1000µs gemessen. Jeder Kanal wird einmal
mit einem je einmal mit einer Störlast und einmal ohne gemessen. Die Störlast wird
durch das Kommando ping -f -s 500 ausgelöst.
112
Kapitel 6. Bewertung
6.5
6.5. Lastquelle
Lastquelle
Bei der Implementierung der Lastquelle, ist absolute Gleichzeitigkeit beim Senden
auf den einzelnen Kanäle nicht möglich. Um eine möglichst gute Annäherung zu
erreichen, werden die Sendeoperationen auf den Kanälen direkt aufeinander folgend
durchgeführt. Dabei wird auf dem Kanal mit der höchsten Priorität zuletzt gesendet,
um ein Zurückhalten von Paketen niedriger Priorität in der Queueing Disziplin zu
provozieren.
Die Lastquellenapplikation msrSend und das instrumentierte Gegenstück msrRecv
wird speziell für die Messungen des in Abschnitt 6.4 beschriebenen Lastmodells implementiert. Als Argumente nimmt msrSend die Payloadgröße, das Sendeintervall,
die Anzahl der Iterationen und einen Divisor entgegen. Mit dem Divisor wird angegeben, nach wieviel Iterationsschritten jeweils ein hochpriores Paket versendet werden
soll.
Der Implementierungsaufwand wird in Kapitel 5.9 angegeben.
6.6
Messergebnisse
Die einzelnen Diagramme zu den Messungen sind in Anhang B aufgeführt. Der
Grund, dafür, dass einige Diagramme kürzer sind als andere, obwohl die gleich Anzahl Pakete versendet wurden, ist teilweise bei Tethereal zu suchen, dass zeitweise
zu langsam ist um alle Pakete zu empfangen und zu verarbeiten. Ein anderer Grund
wird im Folgenden besprochen.
Es ist deutlich zu sehen, dass die Werte stark von den Erwartungen abweichen.
Außerdem ist zu erkennen, dass die Ursache für die Abweichungen in den QueueingDisziplinen zu suchen ist. Dort werden die Pakete aufgestaut, was wiederum zu
Paketverlust durch Überlaufen der Blatt-QDisc, verursacht. Im Vergleich zu anderen
QDisc-Konfigurationen fällt auf, dass die großen Delay-Werte ausschließlich in der
Konfiguration, die HTB nutzt, auftreten. Die durchschnittlichen und maximalen
Delay-Werte werden in den folgenden Tabellen zusammengefasst.
Lastkonf.
Delay Prio 4
Delay Prio 7
1
24940, 12µs
1549, 43µs
2
15149, 60µs
0, 098µs
3
2622, 887µs
0, 218µs
113
6.6. Messergebnisse
Kapitel 6. Bewertung
Tabelle 6.5: Mittlerer Delay für Prio/HTB-Konfiguration
Lastkonf.
Delay Prio 4
Delay Prio 7
1
85431, 54µs
30515, 08µs
2
44779, 55µs
7, 67µs
3
9054, 64µs
12, 15µs
Tabelle 6.6:
Konfiguration
Maximaler
Delay
für
Prio/HTB-
Lastkonf.
Delay Prio 4
Delay Prio 7
1
0, 105µs
0, 014µs
2
0, 097µs
0, 012µs
3
0, 094µs
0, 020µs
Tabelle 6.7: Mittlerer Delay für Prio-Konfiguration
Lastkonf.
Delay Prio 4
Delay Prio 7
1
3, 43µs
0, 33µs
2
6, 917µs
0, 94µs
3
6, 79µs
1, 018µs
Tabelle 6.8: Maximaler Delay für Prio-Konfiguration
Lastkonf.
Delay Prio 4
Delay Prio 7
1
0, 075µs
0, 076µs
2
0, 063µs
0, 065µs
3
0, 065µs
0, 065µs
Tabelle 6.9: Mittlerer Delay für FIFO-Konfiguration
Lastkonf.
Delay Prio 4
Delay Prio 7
1
0, 36µs
6, 117µs
114
Kapitel 6. Bewertung
6.7. Fazit
2
0, 357µs
0, 0676µs
3
6, 793µs
1, 018µs
Tabelle 6.10: Maximaler Delay für FIFO-Konfiguration
Da die Ursache für den hohen Delay offensichtlich in der HTB-QDisc liegt, werden weitere Messungen mit veränderten Parametern durchgeführt. Der cbufferParameter scheint zur Variation geeignet, da er genutzt wird, um den Burst auf eine
Paketgröße zu beschränken, und damit den Mindestwert für den Parameter buffer
unterschreitet.
Die Diagramme B.19 bis B.21 zeigen das Ergebnis der Messungen in der QDisc für
einen cbuffer-Parameter, der um 1000 Byte erhöht ist oder 1000 bzw. 500 Byte
unter dem Minimum liegt. Aus den Ergebnissen ist abzulesen, dass der cbufferParameter durchaus unter dem Minimum liegen kann, ohne dass ein erhöhter Delay
feststellbar wäre. Jedoch scheint es davon abhängig zu sein, wie weit sich der cbuffer
vom Minimum entfernt.
Da der Minimalwert für buffer von der Rate und dem Timer abhängig ist (s. Kapitel 3.4.4.4), kann dem Problem nicht mit einem einfachen Modifikator abgeholfen
werden. Dies wird in Diagramm B.20 gezeigt, wo ein Modifikator von -1000 keinen
Einfluss auf die beiden Kanäle mit der höheren Bandbreite hat, aber auf den Kanal
mit wenig Bandbreite, dessen cburst-Parameter unter die Paketgröße fällt.
Eine weitere Auffälligkeit bei den Messungen ist, dass die Delay-Werte für alle anderen QDisc-Konfigurationen unter einer Microsekunde liegen. Eigentlich sollte zumindest der dritte Kanal durch den Stau, den der Burst verursacht um ein paar
Microsekunden verzögert werden. Erklärbar ist dies, wenn die Hardware ihrerseits
eine Queue enthält, die größer ist, als ein Paket. In diesem Fall kann es bei so kurzen Bursts, wie die im Lastmodell nicht zu messbaren Stausituationen in der QDisc
kommen.
6.7
Fazit
Es wurden stark von der Erwartung abweichende Werte gemessen, die jedoch daraufhin deuten, dass der Einsatz der HTB-QDisc als präzisen Bandbreitenbegrenzer,
in der jetzigen Implementation nicht für den Automatisierungskontext geeignet ist.
115
6.7. Fazit
Kapitel 6. Bewertung
Dies ist jedoch bisher nur eine Vermutung, die mit weiteren Messungen verifiziert
werden muss. Aus Zeitgründen können diese Messungen nicht im Rahmen dieser
Arbeit durchgeführt werden.
116
Kapitel 7
Zusammenfassung und Ausblick
In dieser Arbeit wurde gezeigt, dass eine Integration von Ethernet in die Automatisierungsumgebung ohne proprietäre Hardware durchaus möglich ist. Switches
machen das Medium deterministisch, so dass keine Kollisionen mehr auftreten können.
Um einen priorisierten Datenverkehr zu realisieren ist ein Modell erstellt worden,
das QoS-behaftete Kanäle vorsieht. Die QoS-Eigenschaften sollten durch die vom
Linux-Kernel bereitgestellten Queueing-Disziplinen durchgesetzt werden.
Die Beschreibung der Queueing-Disziplinen, als Implementierungen von Paket-Scheduling-Algorithmen, deutete darauf hin, dass diese für den Einsatz in der verteilten
Automation geeignet sind. Die Queueing-Disziplinen wurden entsprechend dem, in
der Analyse verwandten Ankunfts- und Servicekurvenmodell, konfiguriert. Durchgeführte Messungen wichen jedoch stark von den erwarteten Ergebnissen ab. Die
Ergebnisse deuten daraufhin, dass die Queueing-Disziplinen, speziell gezeigt an der
HTB, in ihrer Implementierungsform im Linux-Kernel noch nicht ausgereift sind,
um in so präzisen Umgebungen eingesetzt zu werden, wie sie in der verteilten Automation vorkommen.
Als eine Weiterentwicklung dieser Arbeit würde sich die Implementierung präziser
Paket-Scheduling-Algorithmen anbieten. Diese Implementierung könnte dann in Zusammenhang mit einer Echtzeiterweiterung, wie RTAI, erfolgen, was eine Portierung
des Kanalkonzepts in eine harte Echtzeitumgebung ermöglichen würde.
Eine weitere Weiterentwicklung, könnte ein Programm sein, dass die lokalen QoSParameter eines Kanals aufgrund von Wissen über Topologie, Hardware und geplanten Netzwerkverkehr berechnet. Dies könnte so weit gehen, dass auf jedem Rechner
117
Kapitel 7. Zusammenfassung und Ausblick
ein Deamon läuft, der die QoS-Kapazitäten der gesamten Topologie kennt und die
lokalen QoS-Parameter dynamisch errechnet und mit anderen Deamons aushandelt.
118
Kapitel 8
Literaturverzeichnis
[BC02]
Daniel P. Bovet and Marco Cesati. Understanding the Linux Kernel.
O’Reilly, 2. edition, Dezember 2002.
[BT04]
Jean-Yves Le Boudec and Patrick Thiran. Network Calculus, A Theory
of Deterministic Queueing Systems for the Internet. Springer Verlag, 1.
edition, 2004.
[eH]
PROFIBUS Nutzerorganisation e.V. (Hrsg.). Profinet systembeschreibung. Technical report.
[Fel00]
Max Felser. Ethernet als Feldbus?, Kommunikationsmodelle für Industrielle Netzwerke. Hochschule für Technik und Informatik, Bern, Mai
2000. http://prof.hti.bfh.ch/index.php?id=fsm1.
[Fur03]
Frank J. Furrer. Industrieautomation mit Ethernet-TCP/IP und WebTechnologie. Hüthig Verlag Heidelberg, 3. edition, 2003.
[Hal96]
Fred Halsall. Data Communications, Computer Networks and Open Systems. Addison-Wesley Publishing Company Inc., 4. edition, 1996.
[Hub03]
Bert Hubert. Linux Advanced Routing and Traffic Control, September
2003. http://www.lartc.org.
[IEE]
Institute for Electrical and Electronics Engineers Inc. IEEE 1588, Standard for precision Clock Synchronization Protocol for Network Measurement and Control Systems. http://www.ieee.org.
119
Kapitel 8. Literaturverzeichnis
[IEE01]
Institute for Electrical and Electronics Engineers Inc. 802, IEEE Standard for Local and Metropolitan Area Networks, Overview and Architecture, März 2001. http://www.ieee.org.
[IEE02]
Institute for Electrical and Electronics Engineers Inc. 802.2, IEEE Standard for Information technology- Telecommunications and information
exchange between systems- Local and metropolitan area networks-specific
requirements, Carrier sense multiple access with collision detection (CSMA/CD) access method and physical layer specifications, März 2002.
http://www.ieee.org.
[IEE03]
Institute for Electrical and Electronics Engineers Inc. 802.1Q, IEEE
Standard for Local and Metropolitan Area Networks, Virtual Bridged Local Area Networks, Mai 2003. http://www.ieee.org.
[IEE04]
Institute for Electrical and Electronics Engineers Inc. 802.1D, IEEE
Standard for Local and Metropolitan Area Networks, Media Access Control(MAC) Bridges, Juni 2004. http://www.ieee.org.
[ipr]
iproute2 utitlity suite.
[Jas02]
Jürgen Jaspereite. Leistungsbewertung eines Netzwerkes mit Class-ofService Unterstützung für Prozessnahe Echtzeitkommunikation. PhD
thesis, Otto-von-Guericke Universität Magdeburg, Oktober 2002.
[JL04]
Herrmann Haertig Jork Loeser. Low-Latency Hard Real-Time Communication over Switched Ethernet. Technische Universität, Dresden, Juni
2004. http://os.inf.tu-dresden.de/papers ps/loeser ecrts2004.pdf.
[Kop97]
Hermann Kopetz. Real-Time Systems, Design Principles for Distributed
Embedded Applications. 1997.
[KS04]
Jan Kiszka and Robert Schwebel. Alternative: Rtnet. A&D Newsletter,
publish-industry Verlag GmbH, 2004.
[Oes01]
Bernd Oestereich. Objektorientierte Softwareentwicklung: Analyse und
Design mit der Unified Modeling Language. 2001.
[Tan02]
Andrew S. Tanenbaum. Computernetzwerke. Pearson Studium, 3. edition, 2002.
120
Kapitel 8. Literaturverzeichnis
[WPR+ 02] Klaus Wehrle, Frank Pählke, Hartmut Ritter, Daniel Müller, and Marc
Bechler. Linux-Netzwerkarchitektur, Design und Implementierung von
Netzwerkprotokollen im Linux-Kern. Addison-Wesley Verlag, 1. edition,
2002.
121
Kapitel 8. Literaturverzeichnis
122
Anhang A
Prioritätentabelle
Priorität
User Prio
Prio Class ID
Filter Prio
HTB Handle
hoch
7
6
5
4
3
0
2
1
x:1
x:2
x:3
x:4
x:5
x:6
x:7
x:8
0
1
2
3
4
5
6
7
8:0
7:0
6:0
5:0
4:0
1:0
3:0
2:0
niedrig
Tabelle A.1: Übersicht über alle prioritätsbezogenen Werte
123
Anhang A. Prioritätentabelle
124
Anhang B
Diagramme
B.1
HTB/Prio QDisc
Abbildung B.1: Delay in QDisc für 200Byte, 2 Kanäle Prio 4 50µs und 1 Kanal Prio
7 100µs
125
B.1. HTB/Prio QDisc
Anhang B. Diagramme
Abbildung B.2: Delay in QDisc für 500Byte, 2 Kanäle Prio 4 100µs und 1 Kanal
Prio 7 500µs
Abbildung B.3: Delay in QDisc für 1496Byte, 2 Kanäle Prio 4 300µs und 1 Kanal
Prio 7 900µs
126
Anhang B. Diagramme
B.2
B.2. HTB/Prio End-to-End
HTB/Prio End-to-End
Abbildung B.4: End-to-End Propagation Time für 200Byte, 2 Kanäle Prio 4 50µs
und 1 Kanal Prio 7 100µs
127
B.2. HTB/Prio End-to-End
Anhang B. Diagramme
Abbildung B.5: End-to-End Propagation Time für 500Byte, 2 Kanäle Prio 4 100µs
und 1 Kanal Prio 7 500µs
Abbildung B.6: End-to-End Propagation Time für 1496Byte, 2 Kanäle Prio 4 300µs
und 1 Kanal Prio 7 900µs
128
Anhang B. Diagramme
B.3
B.3. Prio QDisc
Prio QDisc
Abbildung B.7: Delay in QDisc für 200Byte, 2 Kanäle Prio 4 50µs und 1 Kanal Prio
7 100µs
Abbildung B.8: Delay in QDisc für 500Byte, 2 Kanäle Prio 4 100µs und 1 Kanal
Prio 7 500µs
129
B.4. Prio End-to-End
Anhang B. Diagramme
Abbildung B.9: Delay in QDisc für 1496Byte, 2 Kanäle Prio 4 300µs und 1 Kanal
Prio 7 900µs
B.4
Prio End-to-End
Abbildung B.10: End-to-End Propagation Time für 200Byte, 2 Kanäle Prio 4 50µs
und 1 Kanal Prio 7 100µs
130
Anhang B. Diagramme
B.4. Prio End-to-End
Abbildung B.11: End-to-End Propagation Time für 500Byte, 2 Kanäle Prio 4 100µs
und 1 Kanal Prio 7 500µs
Abbildung B.12: End-to-End Propagation Time für 1496Byte, 2 Kanäle Prio 4 300µs
und 1 Kanal Prio 7 900µs
131
B.5. FIFO QDisc
B.5
Anhang B. Diagramme
FIFO QDisc
Abbildung B.13: Delay in QDisc für 200Byte, 2 Kanäle Prio 4 50µs und 1 Kanal
Prio 7 100µs
Abbildung B.14: Delay in QDisc für 500Byte, 2 Kanäle Prio 4 100µs und 1 Kanal
Prio 7 500µs
132
Anhang B. Diagramme
B.6. FIFO End-to-End
Abbildung B.15: Delay in QDisc für 1496Byte, 2 Kanäle Prio 4 300µs und 1 Kanal
Prio 7 900µs
B.6
FIFO End-to-End
Abbildung B.16: End-to-End Propagation Time für 200Byte, 2 Kanäle Prio 4 50µs
und 1 Kanal Prio 7 100µs
133
B.6. FIFO End-to-End
Anhang B. Diagramme
Abbildung B.17: End-to-End Propagation Time für 500Byte, 2 Kanäle Prio 4 100µs
und 1 Kanal Prio 7 500µs
Abbildung B.18: End-to-End Propagation Time für 1496Byte, 2 Kanäle Prio 4 300µs
und 1 Kanal Prio 7 900µs
134
Anhang B. Diagramme
B.7
B.7. HTB/Prio QDisc variierender Burst-Parameter
HTB/Prio QDisc variierender Burst-Parameter
Abbildung B.19: Delay in QDisc für 500Byte, 2 Kanäle Prio 4 100µs und 1 Kanal
Prio 7 500µs mit cburst + 1000
Abbildung B.20: Delay in QDisc für 500Byte, 2 Kanäle Prio 4 100µs und 1 Kanal
Prio 7 500µs mit Minimum Burst - 1000
135
B.8. Ein Prio 1 Kanal ohne Störlast
Anhang B. Diagramme
Abbildung B.21: Delay in QDisc für 500Byte, 2 Kanäle Prio 4 100µs und 1 Kanal
Prio 7 500µs mit Minimum Burst - 500
B.8
Ein Prio 1 Kanal ohne Störlast
Abbildung B.22: Kanal Prio 1 500Byte ohne Störlast gemessen in QDisc
136
Anhang B. Diagramme
B.9. Ein Prio 1 Kanal mit Störlast
Abbildung B.23: Kanal Prio 1 500Byte ohne Störlast gemessen End-to-End
B.9
Ein Prio 1 Kanal mit Störlast
Abbildung B.24: Kanal Prio 1 500Byte mit Ping-Flood gemessen in QDisc
137
B.10. Ein Prio 7 Kanal ohne Störlast
Anhang B. Diagramme
Abbildung B.25: Kanal Prio 1 500Byte mit Ping-Flood gemessen End-to-End
B.10
Ein Prio 7 Kanal ohne Störlast
Abbildung B.26: Kanal Prio 7 500Byte ohne Störlast gemessen in QDisc
138
Anhang B. Diagramme
B.11. Ein Prio 7 Kanal mit Störlast
Abbildung B.27: Kanal Prio 7 500Byte ohne Störlast gemessen End-to-End
B.11
Ein Prio 7 Kanal mit Störlast
Abbildung B.28: Kanal Prio 7 500Byte mit Ping Flood gemessen in QDisc
139
B.11. Ein Prio 7 Kanal mit Störlast
Anhang B. Diagramme
Abbildung B.29: Kanal Prio 7 500Byte mit Ping Flood gemessen End-to-End
140
Anhang C
Inhalt der CD
Sourcecode
Dieses Verzeichnis enthält den kompletten Quellcode zum erzeugen der Bibliothek.
Die xml-Dateien sind Konfigurationsdateien. msrConf.xml ist die Konfigurationsdatei, die von dem Lastgenerator msrSend eingelesen wird. Für die drei Lastkonfigurationen existiert je eine eigene Datei, die über msrConf.xml kopiert werden kann,
um die Messkonfigurationen nach zu vollziehen.
Das Verzeichnis llaapp enthält die Messbibliothek von Dipl. Inf. Bernhard Gelling.
Im Verzeichniss Kernel-Instrumentierung befinden sich die beiden Kernel-Dateien,
die zur Messung instrumentiert wurden.
Messungen
Dieses Verzeichnis enthält alle Messdaten in Roh- und in aufbereiteter Form als
Excel-Dateien.
Quellen
Dieses Verzeichniss enthält alle elektronischen Quellen.
141