ltcp/bericht/nftables/nftables-perf.tex

50 lines
5.3 KiB
TeX

\subsubsection{Performance-Vergleich}
\paragraph{Testaufbau}
Um die Performance der beiden Firewall-Lösungen vergleichen zu könne, habe ich jeweils zwei unserer Zotac-Boards mit der Onboard-Netzwerkkarte an einen zusätzlichen Firewall-Rechner, der mir bereitgestellt wurde, verbunden. Die Spezifikationen der Zotac-Boards sind dem Abschnitt »Hardware« zu entnehmen. \\
Der zusätzliche Rechner war mit einem Intel Core 2 Duo E6750 mit 2,66 GHz, 2 GiB RAM ausgestattet und zwei Intel Gigabit-Netzwerkkarten ausgestattet (Intel 82566DM-2 und 82572EI). Die beiden Intel-Netzwerkkarten wurden direkt mit den beiden Zotac-Boards verbunden.
Der Firewall-Rechner wurde über die Onboard-Netzwerkkarte und die beiden Zotac-Boards über USB-Netzwerkkarten mit einem Switch und darüber mit der Headnode verbunden um einen Zugriff von außen bereitzustellen. \\
Der Firewall-Rechner soll nun über \texttt{iptables} und \texttt{nftables} den Datenverkehr zwischen den beiden Nodes kontrollieren. Die beiden Netzwerk-Interfaces der Firewall waren im Bridge-Modus verbunden. \\
\includegraphics{bilder/nft-layout.pdf}
\paragraph{Verwendete Software} Um schnell genug eine große Anzahl an Paketen pro Sekunde (PPS) erzeugen zu können um die Firewall-Lösungen zu benchmarken, habe ich \texttt{pktgen} verwendet. Hierbei handelt es sich um einen Paketgenerator, der als Kernel-Modul geladen wird und dadurch direkt im Kernel (ohne teure Kontext-Switches ins Userland) ausgeführt wird.
Zur Überwachung der Messdaten (Datenrate und PPS) habe ich auf allen vier Netzwerkschnittstellen das Tool \texttt{ifpps} aus dem \texttt{netsniff-ng}-Bundle laufen lassen.
\pagebreak
\paragraph{Testeinstellung} Zunächst habe ich die Datenrate und die PPS in Abhängigkeit der Ethernet Frame-Größe gemessen um festzustellen, mit welcher Paketgröße die Messungen am besten durchzuführen sind. \\ \\
\includegraphics{benchmarks/nft-size-load-rate-send.pdf}
\vspace{0.5cm}
\includegraphics{benchmarks/nft-size-load-rate-recv.pdf}
Beim Sender betrug die Prozessor-Last dauerhaft 100 \%, für den Empfänger ist die CPU-Last zusätzlich grün eingetragen.
\pagebreak
Wie aus den Diagrammen ersichtlich wird, wird bei Frame-Größen, die an die MTU des Ethernets (1500 Bytes) heranreichen, das Gigabit-Netzwerk mit ca. 980 MBit/s und ca. 82000 PPS fast komplett ausgereizt. Je kleiner die Frame-Größe wird, desto größer wird zunächst die Anzahl der PPS, da das Netzwerk immer noch gut ausgelastet wird; die Datenrate sinkt zunächst zur langsam. \\
Beim Sender beginnt jedoch bei Frame-Größe kleiner 300 Byte die Datenrate linear zu sinken. Die PPS stagnieren dann bei ca. 450000 Paketen. Dies ist mit der Leistungsfähigkeit der Atom-Prozessoren zu erklären, da diese ab dieser Grenze komplett ausgelastet sind und die Pakete nicht schneller erzeugen können. \\
Beim Empfänger geschieht dieser Einbrauch schon bei ca. 450 Byte Frame-Größe. Hier stagniert die PPS bei ca. 250000. Auch dies lässt sich mit der Auslastung des Prozessors erklären. Der Unterschied zum Sender besteht darin, dass bei diesem die Pakete lediglich statisch zusammengesetzt und losgeschickt werden müssen. Beim Empfänger hingegen muss das Betriebssystem die Pakete zunächst auswerten, was den Bearbeitungszeit verlängert. Dadurch kommen beim Empfänger wesentlich weniger Pakete an, als der Sender losschickt. (Die übrigen Pakete werden gedroppt.) \\
Um eine größtmögliche Auslastung des Gigabit-Netzwerkes zu ermöglichen und gleichzeitig die maximale Anzahl an PPS zu erhalten, habe ich also für die folgenden Benchmarks die Ethernet Frame-Größe auf 450 festgesetzt.
\paragraph{Anfängliche Probleme} Anfangs habe ich auf dem Empfänger keine »Anwendung« laufen lassen, die die Pakete des Senders entgegennimmt. Deshalb musste der Kernel zusätzliche ein ICMP-Paket mit »Connection Refused«-Flag an den Sender zurückschicken und daraufhin weitere Fehlerbehandlungen durchführen. Auf diese Weise habe ich am Empfänger zunächst nur ca. 110000 PPS empfangen können. Als Lösungsansatz habe ich dann \texttt{netcat} auf dem Port am Empfänger laufen lassen und die Daten nach \texttt{/dev/null} umgeleitet. Damit kamen keine Fehler mehr zustande und es konnten ca. 150000 PPS empfangen werden. Dies liegt jedoch immer noch weit unter den am Sender losgeschickten 450000 PPS und ist damit zu erklären, dass es für jedes Paket zu einem Kontex-Switch vom Kernel zu \texttt{netcat} kam und deshalb wieder die Bearbeitungszeit pro Paket stieg. \\
Letztendlich habe ich dazu entschieden, auf der Empfängerseite mit \texttt{iptables} die Pakete, die auf dem entsprechenden Port angekommen, direkt zu droppen. Damit konnten nun die zuvor erwähnten ca. 250000 PPS empfangen werden.
\pagebreak
\paragraph{Einfache Drop-Regeln} Für den nachfolgenden Benchmark habe ich entsprechend viele Regeln generieren lassen, die besagen, dass von (zufällig gewählten) IP-Adressen alle Pakete gedropt werden sollen. \\
\includegraphics{benchmarks/nft-ipt-drop.pdf}
Die Datenrate und die Anzahl an PPS liegen initial bei den bereits zuvor gemessenen ca. 980 MBit/s und 250000 Paketen pro Sekunde. Jedoch bricht die Leistungsfähigkeit bei beiden Firewall-Lösungen schnell erheblich ein. So kann \texttt{iptables} bei 5000 Regeln nur noch ca. 100 MBit/s bei 28000 Paketen verarbeiten, \texttt{nftables} schafft hier nur ca. 50 MBit/s bei 14000 Paketen.