Maison  >  Article  >  Tutoriel système  >  Utiliser Netlink pour la communication entre l'espace utilisateur et l'espace noyau

Utiliser Netlink pour la communication entre l'espace utilisateur et l'espace noyau

王林
王林avant
2024-01-16 08:48:05937parcourir

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

En 2001, le comité ForCES IETF a officiellement réalisé des travaux de normalisation sur Netlink. Jamal Hadi Salim a proposé de définir Netlink comme un protocole de communication entre le composant moteur de routage d'un périphérique réseau et son composant de contrôle et de gestion. Cependant, sa suggestion n'a finalement pas été adoptée et a été remplacée par le modèle que nous voyons aujourd'hui : Netlink a été conçu comme un nouveau domaine de protocole, domaine.

Tobas, le père de Linux, a dit un jour "Linux est une évolution, pas une conception intelligente". Quel est le sens? En d'autres termes, Netlink suit également certains concepts de conception de Linux, c'est-à-dire qu'il n'existe pas de document de spécification ou de document de conception complet. Juste quoi? Vous savez --- "Lisez le putain de code source".

Bien sûr, cet article n'a pas pour but d'analyser le mécanisme d'implémentation de Netlink sur Linux, mais de partager avec vous les sujets de « Qu'est-ce que Netlink » et « Comment faire bon usage de Netlink ». Il vous suffit de lire les sources du noyau. code lorsque vous rencontrez des problèmes. Découvrez pourquoi.

Qu'est-ce que Netlink

Pour comprendre Netlink, il faut saisir plusieurs points clés :

1. Sous-système de messagerie sans connexion pour les datagrammes

2. Implémenté sur la base de l'architecture commune BSD Socket

Concernant le premier point, il nous est facile de penser au protocole UDP. C'est formidable d'y penser. Il n'est pas déraisonnable de comprendre Netlink sur la base du protocole UDP. Tant que vous pouvez faire des parallèles et apprendre par analogie, être doué pour résumer et associer, et enfin réaliser le transfert de connaissances, c'est l'essence de l'apprentissage. Netlink peut réaliser une communication de données bidirectionnelle et asynchrone entre noyau->utilisateur et utilisateur->noyau. Il prend également en charge la communication de données entre deux processus utilisateur et même entre deux sous-systèmes du noyau. Dans cet article, nous ne considérerons pas les deux derniers et nous concentrerons sur la manière d'implémenter la communication de données entre les utilisateurs <->

Lorsque vous avez vu le deuxième point, l'image suivante vous est-elle venue à l'esprit ? Si oui, cela signifie que vous avez la racine de la sagesse ; bien sûr, sinon, cela n’a pas d’importance, la racine de la sagesse peut grandir lentement, haha.

Nous utiliserons principalement socket(), bind(), sendmsg() lors de la pratique ultérieure de la programmation de socket Netlink

Les appels système tels que

et recvmsg(), et bien sûr le mécanisme d'interrogation fourni par socket.

Type de communication Netlink

Netlink prend en charge deux types de méthodes de communication : unicast et multicast.

Unicast : souvent utilisé pour la communication de données 1:1 entre un processus utilisateur et un sous-système du noyau. L'espace utilisateur envoie des commandes au noyau, puis reçoit les résultats des commandes du noyau.

Multicast : souvent utilisé pour la communication de données 1:N entre un processus noyau et plusieurs processus utilisateur. Le noyau agit en tant qu'initiateur de la session et l'application de l'espace utilisateur en est le récepteur. Afin de réaliser cette fonction, le programme spatial du noyau créera un groupe de multidiffusion, puis tous les processus de l'espace utilisateur intéressés par les messages envoyés par le processus du noyau rejoindront le groupe pour recevoir les messages envoyés par le noyau. Comme suit :

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

La communication entre le processus A et le sous-système 1 est unicast, et la communication entre les processus B et C et le sous-système 2 est multicast. L'image ci-dessus nous transmet également un message. Les données transférées de l'espace utilisateur vers le noyau n'ont pas besoin d'être mises en file d'attente, c'est-à-dire que l'opération est terminée de manière synchrone, tandis que les données transférées de l'espace noyau vers l'espace utilisateur doivent être mises en file d'attente, ce qui est asynchrone ; Comprendre cela peut nous éviter bien des détours lors du développement de modules applicatifs basés sur Netlink. Si vous envoyez un message au noyau et avez besoin d'obtenir certaines informations dans le noyau, telles qu'une table de routage ou d'autres informations, si la table de routage est trop volumineuse, alors lorsque le noyau vous renvoie des données via Netlink, vous pouvez penser à comment le recevoir. Problèmes de données, après tout, vous avez vu la file d'attente de sortie, vous ne pouvez pas fermer les yeux.

Format de message Netlink

Le message Netlink se compose de deux parties : l'en-tête du message et la charge utile, et l'intégralité du message Netlink est aligné sur 4 octets et généralement transmis dans l'ordre des octets de l'hôte. L'en-tête du message est fixé à 16 octets, et la longueur du corps du message est variable :

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

En-tête du message Netlink

L'en-tête du message est défini dans le fichier et représenté par la structure nlmsghdr :

Cliquez (ici) pour réduire ou ouvrir

  1. struct nlmsghdr
  2. {
  3. __u32 nlmsg_len; /* Longueur du message y compris l'en-tête */
  4. __u16 nlmsg_type; /* Contenu du message */
  5. __u16 nlmsg_flags; /* Drapeaux supplémentaires */
  6. __u32 nlmsg_seq; /* Numéro de séquence */
  7. __u32 nlmsg_pid; /* Processus d'envoi PID */
  8. };

Explication et explication des attributs de chaque membre dans l'entête du message :

nlmsg_len : La longueur du message entier, en octets. Inclut l'en-tête du message Netlink lui-même.

nlmsg_type : le type de message, c'est-à-dire s'il s'agit d'un message de données ou de contrôle. Actuellement (version 2.6.21 du noyau) Netlink ne prend en charge que quatre types de messages de contrôle, comme suit :

NLMSG_NOOP - message vide, ne faites rien

NLMSG_ERROR - Indique que le message contient une erreur

NLMSG_DONE - Si le noyau renvoie plusieurs messages via la file d'attente Netlink, le dernier message de la file d'attente est de type NLMSG_DONE et l'attribut nlmsg_flags de tous les messages restants a le bit NLM_F_MULTI défini pour être valide.

NLMSG_OVERRUN-Pas encore utilisé.

nlmsg_flags : informations descriptives supplémentaires jointes au message, telles que NLM_F_MULTI mentionné ci-dessus. L'extrait est le suivant :

Tant que vous savez que nlmsg_flags a plusieurs valeurs, quant au rôle et à la signification de chaque valeur, vous pouvez certainement trouver la réponse via Google et le code source, je n'entrerai donc pas dans les détails ici. Toutes les valeurs du noyau 2.6.21 précédent :

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

nlmsg_seq : numéro de séquence du message. Étant donné que Netlink est orienté vers les datagrammes, il existe un risque de perte de données, mais Netlink fournit un mécanisme garantissant que les messages ne sont pas perdus, permettant aux développeurs de programmes de l'implémenter en fonction de leurs besoins réels. Les numéros de séquence de message sont généralement utilisés conjointement avec les messages de type NLM_F_ACK. Si l'application de l'utilisateur doit s'assurer que chaque message qu'elle envoie est reçu avec succès par le noyau, elle a besoin que le programme utilisateur définisse lui-même le numéro de séquence lors de l'envoi du message, et le noyau reçoit le message. Extrayez ensuite le numéro de série, puis définissez le même numéro de série dans le message de réponse envoyé au programme utilisateur. Un peu similaire au mécanisme de réponse et de confirmation de TCP.

Remarque : lorsque le noyau envoie activement un message de diffusion à l'espace utilisateur, ce champ dans le message est toujours 0.

nlmsg_pid : lorsqu'un canal d'échange de données est établi via Netlink entre un processus de l'espace utilisateur et un certain sous-système dans l'espace du noyau, Netlink attribuera une identification numérique unique à chacun de ces canaux. Sa fonction principale est de corréler les messages de requête et les messages de réponse de l'espace utilisateur. Pour le dire franchement, s'il y a plusieurs processus utilisateur dans l'espace utilisateur et plusieurs processus dans l'espace noyau, Netlink doit fournir un mécanisme pour garantir que l'interaction des données entre chaque paire de processus de communication espace « utilisateur-noyau » est cohérente.

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

C'est-à-dire que lorsque les processus A et B obtiennent des informations du sous-système 1 via Netlink, le sous-système 1 doit garantir que les données de réponse renvoyées au processus A ne seront pas envoyées au processus B. Il convient principalement aux scénarios dans lesquels les processus de l'espace utilisateur obtiennent des données de l'espace noyau. Normalement, lorsqu'un processus de l'espace utilisateur envoie un message au noyau, il attribue généralement l'ID de processus du processus actuel à cette variable via l'appel système getpid(). Autrement dit, le processus de l'espace utilisateur le fait lorsqu'il l'espère. obtenir une réponse du noyau. Ce champ est défini sur 0 pour les messages activement envoyés du noyau vers l'espace utilisateur.

Corps du message Netlink

Le corps du message de Netlink adopte le format TLV (Type-Length-Value) :

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

Chaque attribut de Netlink est représenté par struct nlattr{} dans le fichier

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

Message d'indication d'erreur fourni par Netlink

Contenu Lorsqu'une erreur se produit lors de la communication entre les applications de l'espace utilisateur et les processus de l'espace noyau via Netlink, Netlink doit informer l'espace utilisateur de ces erreurs. Netlink encapsule le message d'erreur séparément,  :

Cliquez (ici) pour réduire ou ouvrir

    struct nlmsgerr
  1. {
  2. int error; //Code d'erreur standard, défini dans le fichier d'en-tête errno.h. Cela peut être expliqué en utilisant perror()
  3. struct nlmsghdr msg; //Indique quel message a déclenché la valeur d'erreur dans la structure
  4. };
Choses à noter lors de la programmation de Netlink Sur la base de la communication utilisateur-noyau Netlink, deux situations peuvent entraîner une perte de paquets :

1. Mémoire épuisée;

2. Débordement de tampon dans le processus de réception de l'espace utilisateur. Les principales raisons d'un dépassement de tampon peuvent être les suivantes : le processus de l'espace utilisateur s'exécute trop lentement ou la file d'attente de réception est trop courte ;

Si Netlink ne peut pas transmettre correctement le message au processus de réception dans l'espace utilisateur, alors le processus de réception dans l'espace utilisateur renverra une erreur de mémoire insuffisante (ENOBUFS) lors de l'appel du système recvmsg(). Cela doit être noté. En d'autres termes, la situation de débordement de tampon ne sera pas envoyée dans l'appel système sendmsg() depuis user->kernel. La raison a déjà été mentionnée. Veuillez y réfléchir vous-même.

Bien sûr, si le blocage de la communication par socket est utilisé, il n'y a aucun danger caché d'épuisement de la mémoire. Pourquoi ? Accédez rapidement à Google et recherchez ce qu’est un socket bloquant. Si vous apprenez sans réfléchir, vous serez en vain ; si vous réfléchissez sans apprendre, vous serez en danger.

Structure d'adresse de Netlink

Dans l'article de blog TCP, nous avons mentionné la structure d'adresse et la structure d'adresse standard utilisées dans le processus de programmation Internet. Leur relation avec la structure d'adresse Netlink est la suivante :

La définition et la description détaillées de struct sockaddr_nl{} sont les suivantes :

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

Cliquez (ici) pour réduire ou ouvrir

  1. struct sockaddr_nl
  2. {
  3. sa_family_t nl_family; /*Ce champ est toujours AF_NETLINK */
  4. unsigned short nl_pad; /* Actuellement non utilisé, rempli de 0*/
  5. __u32 nl_pid; /* processus pid */
  6. __u32 nl_groups; /* masque de groupes multicast */
  7. };

nl_pid : Cet attribut est l'ID du processus d'envoi ou de réception de messages. Comme nous l'avons dit précédemment, Netlink peut non seulement réaliser une communication dans l'espace utilisateur-noyau, mais également permettre une communication en temps réel entre deux processus dans l'espace utilisateur, ou entre deux processus dans l'espace utilisateur. espace du noyau. Lorsque cet attribut vaut 0, il s'applique généralement aux deux situations suivantes :

Premièrement, la destination que nous voulons envoyer est le noyau, c'est-à-dire que lors de l'envoi de l'espace utilisateur à l'espace noyau, nl_pid dans la structure d'adresse Netlink que nous construisons est généralement défini sur 0. Une chose que je dois vous expliquer ici est que dans la spécification Netlink, le nom complet du PID est Port-ID (32 bits) et sa fonction principale est d'identifier de manière unique un canal de socket basé sur Netlink. Normalement, nl_pid est défini sur l'ID de processus du processus en cours. Cependant, dans le cas où plusieurs threads d'un processus utilisent le socket netlink en même temps, le paramètre nl_pid est généralement implémenté comme suit :

Cliquez (ici) pour réduire ou ouvrir

  1. pthread_self() <<16 |
Deuxièmement, lorsqu'un message de multidiffusion est envoyé du noyau vers l'espace utilisateur, si le processus de l'espace utilisateur est dans le groupe de multidiffusion, alors nl_pid dans sa structure d'adresse est également défini sur 0, et en même temps, il doit être combiné avec les autres informations présentées ci-dessous une propriété.

nl_groups : si un processus de l'espace utilisateur souhaite rejoindre un groupe de multidiffusion, il doit exécuter l'appel système bind(). Ce champ précise le

masque du numéro de groupe multicast que l'appelant souhaite rejoindre (notez qu'il ne s'agit pas du numéro de groupe, nous expliquerons ce champ en détail plus tard). Si ce champ est à 0, cela signifie que l'appelant ne souhaite rejoindre aucun groupe de multidiffusion. Pour chaque protocole appartenant au domaine protocolaire Netlink, jusqu'à 32 groupes de multidiffusion peuvent être pris en charge (car la longueur de nl_groups est de 32 bits), et chaque groupe de multidiffusion est représenté par un bit.

Concernant les points de connaissances restants de Netlink, nous les aborderons plus tard lorsqu'ils seront utiles lors de séances pratiques.

Pas terminé, à suivre...

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer