Heim  >  Artikel  >  System-Tutorial  >  Verwendung von Netlink für die Kommunikation zwischen Userspace und Kernelspace

Verwendung von Netlink für die Kommunikation zwischen Userspace und Kernelspace

王林
王林nach vorne
2024-01-16 08:48:05891Durchsuche

用户空间和内核空间通讯-Netlink 上

Im Jahr 2001 führte das ForCES IETF-Komitee offiziell Standardisierungsarbeiten für Netlink durch. Jamal Hadi Salim schlug vor, Netlink als Protokoll für die Kommunikation zwischen der Routing-Engine-Komponente eines Netzwerkgeräts und seiner Steuerungs- und Verwaltungskomponente zu definieren. Sein Vorschlag wurde jedoch letztendlich nicht angenommen und durch das Muster ersetzt, das wir heute sehen: Netlink wurde als neue Protokolldomäne, Domäne, konzipiert.

Tobas, der Vater von Linux, sagte einmal: „Linux ist Evolution, nicht intelligentes Design.“ Was ist die Bedeutung? Mit anderen Worten, Netlink folgt auch bestimmten Designkonzepten von Linux, das heißt, es gibt kein vollständiges Spezifikationsdokument oder Designdokument. Was genau? Sie wissen schon: „Lesen Sie den verdammten Quellcode“.

Natürlich geht es in diesem Artikel nicht darum, den Implementierungsmechanismus von Netlink unter Linux zu analysieren, sondern um die Themen „Was ist Netlink“ und „Wie nutzt man Netlink sinnvoll?“ Sie müssen nur die Kernel-Quelle lesen Code, wenn Sie auf Probleme stoßen. Finden Sie heraus, warum.

Was ist Netlink? Um Netlink zu verstehen, müssen Sie mehrere wichtige Punkte verstehen:

1. Verbindungsloses Messaging-Subsystem für Datagramme

2. Implementiert auf Basis der gängigen BSD-Socket-Architektur

Was den ersten Punkt betrifft, fällt es uns leicht, an das UDP-Protokoll zu denken. Es ist nicht unvernünftig, Netlink auf der Grundlage des UDP-Protokolls zu verstehen. Solange Sie Parallelen ziehen und durch Analogie lernen können, gut im Zusammenfassen und Verknüpfen sind und schließlich den Wissenstransfer realisieren können, ist dies die Essenz des Lernens. Netlink kann eine bidirektionale und asynchrone Datenkommunikation zwischen Kernel->Benutzer und Benutzer->Kernel realisieren. Es unterstützt auch die Datenkommunikation zwischen zwei Benutzerprozessen und sogar zwischen zwei Kernel-Subsystemen. In diesem Artikel werden wir die beiden letztgenannten nicht berücksichtigen und uns darauf konzentrieren, wie die Datenkommunikation zwischen Benutzern <-> implementiert wird.

Als Sie den zweiten Punkt gesehen haben, ist Ihnen folgendes Bild in den Sinn gekommen? Wenn ja, bedeutet das natürlich, dass Sie die Wurzel der Weisheit haben; wenn nicht, spielt das keine Rolle, die Wurzel der Weisheit kann langsam wachsen, haha.

Wir werden hauptsächlich socket(), bind(), sendmsg() verwenden, wenn wir später die Netlink-Socket-Programmierung üben

Systemaufrufe wie

und recvmsg() und natürlich der von Socket bereitgestellte Polling-Mechanismus.

Netlink-Kommunikationstyp Netlink unterstützt zwei Arten von Kommunikationsmethoden: Unicast und Multicast.

Unicast: Wird häufig für die 1:1-Datenkommunikation zwischen einem Benutzerprozess und einem Kernel-Subsystem verwendet. Der Benutzerbereich sendet Befehle an den Kernel und empfängt dann die Ergebnisse der Befehle vom Kernel.

Multicast: Wird häufig für die 1:N-Datenkommunikation zwischen einem Kernelprozess und mehreren Benutzerprozessen verwendet. Der Kernel fungiert als Initiator der Sitzung und die User-Space-Anwendung ist der Empfänger. Um diese Funktion zu erreichen, erstellt das Kernel-Space-Programm eine Multicast-Gruppe. Anschließend treten alle Benutzerspace-Prozesse, die an den vom Kernel-Prozess gesendeten Nachrichten interessiert sind, der Gruppe bei, um vom Kernel gesendete Nachrichten zu empfangen. Wie folgt:

用户空间和内核空间通讯-Netlink 上

Die Kommunikation zwischen Prozess A und Subsystem 1 ist Unicast, und die Kommunikation zwischen den Prozessen B und C und Subsystem 2 ist Multicast. Das Bild oben sagt uns auch eine Botschaft. Daten, die vom Benutzerbereich an den Kernel übertragen werden, müssen nicht in die Warteschlange gestellt werden, d. h. der Vorgang wird synchron abgeschlossen, während Daten, die vom Kernelbereich an den Benutzerbereich übertragen werden, in die Warteschlange gestellt werden müssen, was asynchron ist. Dieses Verständnis kann uns viele Umwege bei der Entwicklung von Anwendungsmodulen auf Basis von Netlink ersparen. Wenn Sie eine Nachricht an den Kernel senden und bestimmte Informationen im Kernel abrufen müssen, z. B. eine Routing-Tabelle oder andere Informationen. Wenn die Routing-Tabelle zu groß ist, können Sie darüber nachdenken, wann der Kernel Daten über Netlink an Sie zurücksendet So erhalten Sie Datenprobleme. Nachdem Sie die Ausgabewarteschlange gesehen haben, können Sie kein Auge zudrücken.

Netlink-Nachrichtenformat Netlink-Nachricht besteht aus zwei Teilen: Nachrichtenkopf und Nutzlast, und die gesamte Netlink-Nachricht ist 4-Byte-ausgerichtet und wird im Allgemeinen in der Host-Byte-Reihenfolge übertragen. Der Nachrichtenkopf ist auf 16 Byte festgelegt und die Länge des Nachrichtentexts ist variabel:

用户空间和内核空间通讯-Netlink 上

Netlink-Nachrichtenkopf Der Nachrichtenheader ist in der Datei definiert und wird durch die Struktur nlmsghdr dargestellt:

Klicken Sie (hier), um es zu verkleinern oder zu öffnen

    struct nlmsghdr
  1. {
  2. __u32 nlmsg_len; /* Länge der Nachricht inklusive Header */
  3. __u16 nlmsg_type; /* Nachrichteninhalt */
  4. __u16 nlmsg_flags; /* Zusätzliche Flags */
  5. __u32 nlmsg_seq; /* Sequenznummer */
  6. __u32 nlmsg_pid; /* Sendeprozess-PID */
  7. };
Erklärung und Erklärung der Attribute jedes Mitglieds im Nachrichtenkopf:

nlmsg_len: Die Länge der gesamten Nachricht in Bytes. Enthält den Netlink-Nachrichtenheader selbst.

nlmsg_type: Der Nachrichtentyp, d. h. ob es sich um eine Daten- oder Steuernachricht handelt. Derzeit (Kernel-Version 2.6.21) unterstützt Netlink nur vier Arten von Kontrollnachrichten:

NLMSG_NOOP – leere Nachricht, nichts tun

NLMSG_ERROR – Zeigt an, dass die Nachricht einen Fehler enthält

NLMSG_DONE – Wenn der Kernel mehrere Nachrichten über die Netlink-Warteschlange zurückgibt, ist die letzte Nachricht in der Warteschlange vom Typ NLMSG_DONE und für das nlmsg_flags-Attribut aller verbleibenden Nachrichten ist das NLM_F_MULTI-Bit auf gültig gesetzt.

NLMSG_OVERRUN – Noch nicht verwendet.

nlmsg_flags: Zusätzliche beschreibende Informationen, die an die Nachricht angehängt sind, wie z. B. das oben erwähnte NLM_F_MULTI. Der Auszug lautet wie folgt:

Solange Sie wissen, dass nlmsg_flags mehrere Werte hat, können Sie die Antwort auf die Rolle und Bedeutung jedes Werts definitiv über Google und den Quellcode finden, daher werde ich hier nicht auf Details eingehen. Alle Werte im vorherigen Kernel 2.6.21:

用户空间和内核空间通讯-Netlink 上

nlmsg_seq: Nachrichtensequenznummer. Da Netlink auf Datagramme ausgerichtet ist, besteht die Gefahr eines Datenverlusts. Netlink bietet jedoch einen Mechanismus, der sicherstellt, dass Nachrichten nicht verloren gehen, sodass Programmentwickler ihn entsprechend ihren tatsächlichen Anforderungen implementieren können. Nachrichtensequenznummern werden im Allgemeinen in Verbindung mit Nachrichten vom Typ NLM_F_ACK verwendet. Wenn die Anwendung des Benutzers sicherstellen muss, dass jede von ihr gesendete Nachricht erfolgreich vom Kernel empfangen wird, muss das Benutzerprogramm die Sequenznummer beim Senden der Nachricht selbst festlegen Der Kernel empfängt die Nachricht, extrahiert dann die Seriennummer und legt dann dieselbe Seriennummer in der an das Benutzerprogramm gesendeten Antwortnachricht fest. Etwas ähnlich dem Antwort- und Bestätigungsmechanismus von TCP.

Hinweis: Wenn der Kernel aktiv eine Broadcast-Nachricht an den Benutzerbereich sendet, ist dieses Feld in der Nachricht immer 0.

nlmsg_pid: Wenn über Netlink ein Datenaustauschkanal zwischen einem User-Space-Prozess und einem bestimmten Subsystem im Kernel-Space eingerichtet wird, weist Netlink jedem dieser Kanäle eine eindeutige digitale Identifikation zu. Seine Hauptfunktion besteht darin, Anforderungsnachrichten und Antwortnachrichten aus dem Benutzerbereich zu korrelieren. Um es ganz klar auszudrücken: Wenn es mehrere Benutzerprozesse im Benutzerbereich und mehrere Prozesse im Kernelbereich gibt, muss Netlink einen Mechanismus bereitstellen, um sicherzustellen, dass die Dateninteraktion zwischen jedem Paar von „Benutzer-Kernel“-Raumkommunikationsprozessen konsistent ist.

用户空间和内核空间通讯-Netlink 上

Das heißt, wenn die Prozesse A und B über Netlink Informationen von Subsystem 1 erhalten, muss Subsystem 1 sicherstellen, dass die an Prozess A zurückgesendeten Antwortdaten nicht an Prozess B gesendet werden. Es eignet sich hauptsächlich für Szenarien, in denen Benutzerraumprozesse Daten aus dem Kernelraum abrufen. Wenn ein User-Space-Prozess eine Nachricht an den Kernel sendet, weist er dieser Variablen normalerweise über den Systemaufruf getpid() die Prozess-ID des aktuellen Prozesses zu eine Antwort vom Kernel erhalten. Dieses Feld wird für Nachrichten, die aktiv vom Kernel an den Benutzerbereich gesendet werden, auf 0 gesetzt.

Netlink-Nachrichtentext

Der Nachrichtentext von Netlink verwendet das TLV-Format (Type-Length-Value):

用户空间和内核空间通讯-Netlink 上

Jedes Attribut von Netlink wird durch struct nlattr{} in der Datei dargestellt

用户空间和内核空间通讯-Netlink 上

Von Netlink bereitgestellte Fehlermeldung

Inhalt Wenn während der Kommunikation zwischen User-Space-Anwendungen und Kernel-Space-Prozessen über Netlink ein Fehler auftritt, muss Netlink den User-Space über solche Fehler informieren. Netlink kapselt die Fehlermeldung separat, :

Klicken Sie (hier), um es zu verkleinern oder zu öffnen

    struct nlmsgerr
  1. {
  2. int error; //Standardfehlercode, definiert in der Header-Datei errno.h. Es kann mit perror()
  3. erklärt werden
  4. struct nlmsghdr msg; //Gibt an, welche Nachricht den Fehlerwert in der Struktur ausgelöst hat
  5. };
Dinge, die Sie beim Programmieren von Netlink beachten sollten Basierend auf der Netlink-Benutzer-Kernel-Kommunikation gibt es zwei Situationen, die zu Paketverlusten führen können:

1. Speicher erschöpft;

2. Pufferüberlauf im User-Space-Empfangsprozess. Die Hauptgründe für einen Pufferüberlauf können sein: Der User-Space-Prozess läuft zu langsam oder die Empfangswarteschlange ist zu kurz.

Wenn Netlink die Nachricht nicht korrekt an den empfangenden Prozess im Benutzerbereich übermitteln kann, gibt der empfangende Prozess im Benutzerbereich beim Aufruf des Systemaufrufs recvmsg() einen Fehler wegen unzureichendem Arbeitsspeicher zurück. Mit anderen Worten, die Pufferüberlaufsituation wird nicht im sendmsg()-Systemaufruf von user->kernel gesendet. Bitte denken Sie selbst darüber nach.

Wenn die Socket-Kommunikation blockiert wird, besteht natürlich keine versteckte Gefahr einer Speichererschöpfung. Warum ist das so? Gehen Sie schnell zu Google und schauen Sie nach, was ein blockierender Socket ist. Wenn Sie ohne nachzudenken lernen, werden Sie vergeblich sein; wenn Sie ohne zu lernen denken, werden Sie in Gefahr sein.

Netlink-Adressstruktur

Im TCP-Blogbeitrag haben wir die im Internetprogrammierungsprozess verwendete Adressstruktur und Standardadressstruktur erwähnt. Ihre Beziehung zur Netlink-Adressstruktur ist wie folgt:

Die detaillierte Definition und Beschreibung von struct sockaddr_nl{} lautet wie folgt:

用户空间和内核空间通讯-Netlink 上

Klicken Sie (hier), um es zu verkleinern oder zu öffnen

  1. struct sockaddr_nl
  2. {
  3. sa_family_t nl_family; /*Dieses Feld ist immer AF_NETLINK */
  4. unsigned short nl_pad; /* Derzeit nicht verwendet, gefüllt mit 0*/
  5. __u32 nl_pid; /* Prozess-PID */
  6. __u32 nl_groups; /* Multicast-Gruppenmaske */
  7. };

nl_pid: Dieses Attribut ist die Prozess-ID zum Senden oder Empfangen von Nachrichten. Netlink kann nicht nur die Benutzer-Kernel-Raumkommunikation realisieren, sondern auch die Echtzeitkommunikation zwischen zwei Prozessen im Benutzerraum oder zwischen zwei Prozessen in ermöglichen Kernelraumkommunikation. Wenn dieses Attribut 0 ist, gilt es im Allgemeinen für die folgenden zwei Situationen:

Erstens ist das Ziel, das wir senden möchten, der Kernel. Wenn wir also vom Benutzerbereich zum Kernelbereich senden, wird nl_pid in der von uns erstellten Netlink-Adressstruktur normalerweise auf 0 gesetzt. Eine Sache, die ich Ihnen hier erklären muss, ist, dass in der Netlink-Spezifikation der vollständige Name der PID Port-ID (32 Bit) lautet und ihre Hauptfunktion darin besteht, einen Netlink-basierten Socket-Kanal eindeutig zu identifizieren. Normalerweise wird nl_pid auf die Prozess-ID des aktuellen Prozesses gesetzt. Für den Fall, dass mehrere Threads eines Prozesses jedoch gleichzeitig den Netlink-Socket verwenden, wird die Einstellung von nl_pid im Allgemeinen wie folgt implementiert:

Klicken Sie (hier), um es zu verkleinern oder zu öffnen

  1. pthread_self() << 16 |
Zweitens: Wenn eine Multicast-Nachricht vom Kernel an den Benutzerbereich gesendet wird und sich der Benutzerbereichsprozess in der Multicast-Gruppe befindet, wird nl_pid in seiner Adressstruktur ebenfalls auf 0 gesetzt und muss gleichzeitig mit kombiniert werden Die anderen unten aufgeführten Informationen sind eine Eigenschaft.

nl_groups: Wenn ein User-Space-Prozess einer Multicast-Gruppe beitreten möchte, muss er den Systemaufruf bind() ausführen. Dieses Feld gibt die

Maske der Multicast-Gruppennummer an, der der Anrufer beitreten möchte (beachten Sie, dass es sich nicht um die Gruppennummer handelt, wir werden dieses Feld später im Detail erklären). Wenn dieses Feld 0 ist, bedeutet dies, dass der Anrufer keiner Multicast-Gruppe beitreten möchte. Für jedes Protokoll, das zur Netlink-Protokolldomäne gehört, können bis zu 32 Multicast-Gruppen unterstützt werden (da die Länge von nl_groups 32 Bit beträgt), und jede Multicast-Gruppe wird durch ein Bit dargestellt.

Was die verbleibenden Wissenspunkte von Netlink betrifft, werden wir sie später besprechen, wenn sie in praktischen Sitzungen nützlich sind.

Noch nicht fertig, Fortsetzung folgt...

Das obige ist der detaillierte Inhalt vonVerwendung von Netlink für die Kommunikation zwischen Userspace und Kernelspace. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:linuxprobe.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen