zoukankan      html  css  js  c++  java
  • Linux Netlink 基本使用方法

      1.什么是Netlink
      什么是Netlink?Netlink是linux提供的用于内核和用户态进程之间的通信方式。但是注意虽然Netlink主要用于用户空间和内核空间的通信,但是也能用于用户空间的两个进程通信。只是进程间通信有其他很多方式,一般不用Netlink。除非需要用到Netlink的广播特性时。
      那么Netlink有什么优势呢?一般来说用户空间和内核空间的通信方式有三种:/proc、ioctl、Netlink。而前两种都是单向的,但是Netlink可以实现双工通信。
      Netlink协议基于BSDsocket和AF_NETLINK地址簇(addressfamily),使用32位的端口号寻址(以前称作PID),每个Netlink协议(或称作总线,man手册中则称之为netlinkfamily),通常与一个或一组内核服务/组件相关联,如NETLINK_ROUTE用于获取和设置路由与链路信息、NETLINK_KOBJECT_UEVENT用于内核向用户空间的udev进程发送通知等。netlink具有以下特点:
      ①支持全双工、异步通信(当然同步也支持)https://www.weixiu3721.com
      ②用户空间可使用标准的BSDsocket接口(但netlink并没有屏蔽掉协议包的构造与解析过程,推荐使用libnl等第三方库)
      ③在内核空间使用专用的内核API接口
      ④支持多播(因此支持“总线”式通信,可实现消息订阅)
      ⑤在内核端可用于进程上下文与中断上下文
      如何学习Netlink?我觉得最好的方式就是将Netlink和UDPsocket对比学习。因为他们真的很对地方相似。AF_NETLINK和AF_INET对应,是一个协议族,而NETLINK_ROUTE、NETLINK_GENERIC这些是协议,对应于UDP。
      那么我们主要关注Netlink和UDPsocket之间的不同点,其中最重要的一点就是:使用UDPsocket发送数据包时,用户无需构造UDP数据包的包头,内核协议栈会根据原、目的地址(sockaddr_in)填充头部信息。但是Netlink需要我们自己构造一个包头(这个包头有什么用,我们后面再说)。
      一般我们使用Netlink都要指定一个协议,我们可以使用内核为我们预留的NETLINK_GENERIC(定义在linux/netlink.h中),也可以使用我们自定义的协议,其实就是定义一个内核还没有占用的数字。下面我们用NETLINK_TEST做为我们定义的协议写一个例子(注意:自定义协议不一定非要添加到linux/netlink.h中,只要用户态和内核态代码都能找到该定义就行)。我们知道使用UDP发送报文有两种方式:sendto和sendmsg,同样Netlink也支持这两种方式。下面先看使用sendmsg的方式。
      2.用户态数据结构
      首先看一下几个重要的数据结构的关系:
      2.1structmsghdr
      msghdr这个结构在socket变成中就会用到,并不算Netlink专有的,这里不在过多说明。只说明一下如何更好理解这个结构的功能。我们知道socket消息的发送和接收函数一般有这几对:recv/send、readv/writev、recvfrom/sendto。当然还有recvmsg/sendmsg,前面三对函数各有各的特点功能,而recvmsg/sendmsg就是要囊括前面三对的所有功能,当然还有自己特殊的用途。msghdr的前两个成员就是为了满足recvfrom/sendto的功能,中间两个成员msg_iov和msg_iovlen则是为了满足readv/writev的功能,而最后的msg_flags则是为了满足recv/send中flag的功能,剩下的msg_control和msg_controllen则是满足recvmsg/sendmsg特有的功能。
      2.2Structsockaddr_ln
      Structsockaddr_ln为Netlink的地址,和我们通常socket编程中的sockaddr_in作用一样,他们的结构对比如下。
      structsockaddr_nl{}的详细定义和描述如下:
      struct sockaddr_nl
      {
      sa_family_t nl_family;/*该字段总是为AF_NETLINK*/
      unsigned short nl_pad;/*目前未用到,填充为0*/
      __u32 nl_pid;/*process pid*/
      __u32 nl_groups;/*multicast groups mask*/
      };
      (1)nl_pid:在Netlink规范里,PID全称是Port-ID(32bits),其主要作用是用于唯一的标识一个基于netlink的socket通道。通常情况下nl_pid都设置为当前进程的进程号。前面我们也说过,Netlink不仅可以实现用户-内核空间的通信还可使现实用户空间两个进程之间,或内核空间两个进程之间的通信。该属性为0时一般指内核。
      (2)nl_groups:如果用户空间的进程希望加入某个多播组,则必须执行bind()系统调用。该字段指明了调用者希望加入的多播组号的掩码(注意不是组号,后面我们会详细讲解这个字段)。如果该字段为0则表示调用者不希望加入任何多播组。对于每个隶属于Netlink协议域的协议,最多可支持32个多播组(因为nl_groups的长度为32比特),每个多播组用一个比特来表示。
      2.3structnlmsghdr
      Netlink的报文由消息头和消息体构成,structnlmsghdr即为消息头。消息头定义在文件里,由结构体nlmsghdr表示:
      struct nlmsghdrhttps://www.weixiu3721.com
      {
      __u32 nlmsg_len;/*Length of message including header*/
      __u16 nlmsg_type;/*Message content*/
      __u16 nlmsg_flags;/*AddiTIonal flags*/
      __u32 nlmsg_seq;/*Sequence number*/
      __u32 nlmsg_pid;/*Sending process PID*/
      };
      消息头中各成员属性的解释及说明:
      (1)nlmsg_len:整个消息的长度,按字节计算。包括了Netlink消息头本身。
      (2)nlmsg_type:消息的类型,即是数据还是控制消息。目前(内核版本2.6.21)Netlink仅支持四种类型的控制消息,如下:
      a)NLMSG_NOOP-空消息,什么也不做;
      b)NLMSG_ERROR-指明该消息中包含一个错误;
      c)NLMSG_DONE-如果内核通过Netlink队列返回了多个消息,那么队列的最后一条消息的类型为NLMSG_DONE,其余所有消息的nlmsg_flags属性都被设置NLM_F_MULTI位有效。
      d)NLMSG_OVERRUN-暂时没用到。
      (3)nlmsg_flags:附加在消息上的额外说明信息,如上面提到的NLM_F_MULTI。
      那消息体怎么设置呢?可以使用NLMSG_DATA,具体见后面例子。

  • 相关阅读:
    Spring Cloud (八):服务调用追踪 sleuth & zipkin
    Spring Cloud (七):API 网关
    Spring Cloud (六):声明式 REST 请求 Feign
    maven 下载 jar 包到本地
    K8S 设置 Pod 使用 host 网络、配置 DNS
    Spring Cloud (五):容错处理 Hystrix
    Spring Cloud (四):客户端实现负载均衡
    [数仓]数据仓库设计方案
    [知识图谱]Neo4j知识图谱构建(neo4j-python-pandas-py2neo-v3)
    [Pandas]利用Pandas处理excel数据
  • 原文地址:https://www.cnblogs.com/zqw111/p/12936784.html
Copyright © 2011-2022 走看看