zoukankan      html  css  js  c++  java
  • RTNETLINK内核与用户空间网络子系统交互机制

    主要涉及net/netlink/af_netlink.c与net/core/rtnetlink.c两个主文件。内核的网络子系统定义了rtnetlink,用做和用户空间的交互,rtnetlink为AF_NETLINK协议的一个类别NETLINK_ROUTE,其它类别包括NETLINK_XFRM、NETLINK_GENERIC等。renetlink主要注册了LINK、ROUTE、ADDRESS、NEIGHOUR等相关的操作。

    本文以PF_UNSPEC协议族的RTM_GETLINK为例进行介绍,首先注册rtnetlink内核套接口,主要是注册一个接收函数挂载到AF_NETLINK的处理流程中:

    1.  
      static int __net_init rtnetlink_net_init(struct net *net)
    2.  
      {
    3.  
      struct netlink_kernel_cfg cfg = {
    4.  
      .input = rtnetlink_rcv,
    5.  
      };
    6.  
      sk = netlink_kernel_create(net, NETLINK_ROUTE, &cfg);
    7.  
      }

    其次,注册三个回调函数在全局的数组rtnl_msg_handlers上,其结构如下:

    1.  
      struct rtnl_link {
    2.  
      rtnl_doit_func doit;
    3.  
      rtnl_dumpit_func dumpit;
    4.  
      rtnl_calcit_func calcit;
    5.  
      } *rtnl_msg_handlers[RTNL_FAMILY_MAX + 1];

    PF_UNSPEC协议组的RTM_GETLINK类型注册了以下三个操作:

    1.  
      void rtnl_register(int protocol, int msgtype,
    2.  
                 rtnl_doit_func doit, rtnl_dumpit_func dumpit, rtnl_calcit_func calcit)
    3.  
        
    4.  
      rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo, rtnl_calcit);

    其中,doit函数rtnl_getlink主要获取指定设备的接口信息,dumpit函数rtnl_dump_ifinfo获取全部接口的信息,calcit函数rtnl_calcit配合dumpit函数使用,计算出一个设备的接口信息所占用的空间(if_nlmsg_size()),用来控制分配返回数据的存储空间最小值。

    用户空间应用获取全部接口信息时,需要在下发的nlmsghdr结构体成员nlmsg_flags变量中增加NLM_F_DUMP标志:

    1.  
      struct nlmsghdr nlh;
    2.  
       
    3.  
      nlh.nlmsg_type = RTM_GETLINK;
    4.  
      nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;

    用户空间应用调用sendmsg发送rtnetlink消息,相应的内核处理函数为netlink_sendmsg,如下所示其最终调用的函数为rtnetlink初始化时注册的rtnetlink_rcv,准备返回用户的数据:

    rtnetlink_rcv主要功能在函数rtnetlink_rcv_msg中实现,判断NLM_F_DUMP标志,选择执行doit或者dumpit函数:

    1.  
      static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
    2.  
      {
    3.  
      if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
    4.  
      {
    5.  
      struct netlink_dump_control c = {
    6.  
      .dump = dumpit,
    7.  
      .min_dump_alloc = min_dump_alloc,
    8.  
      };
    9.  
      err = netlink_dump_start(rtnl, skb, nlh, &c);
    10.  
      }
    11.  
      rtnl_lock();
    12.  
      return err;
    13.  
      }
    14.  
       
    15.  
      doit = rtnl_get_doit(family, type);
    16.  
      if (doit == NULL)
    17.  
      return -EOPNOTSUPP;
    18.  
       
    19.  
      return doit(skb, nlh);
    20.  
      }

    doit函数即rtnl_getlink(),获取指定设备的链路信息,存储于sk_buff中,调用netlink_sendskb(),挂载到相应sock的sk->sk_receive_queue,等待用户空间应用调用recvmsg()返回。

    dumpit函数即rtnl_dump_ifinfo(),获取指定命名空间的全部接口信息,数据量存在过大情况,分为多次传输完成。在netlink_dump_start函数中初始化传输参数,netlink_sock结构体成员cb_running标示传输开始,cb->args用作记录当前传输的位置,初始化时清零。netlink_dump获取第一次传输数据,挂载到sk_receive_queue,并且更新当前传输位置cb->args:

    1.  
      int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
    2.  
      const struct nlmsghdr *nlh,
    3.  
      struct netlink_dump_control *control)
    4.  
      {
    5.  
      struct netlink_callback *cb;
    6.  
      struct netlink_sock *nlk;
    7.  
       
    8.  
      cb = &nlk->cb;
    9.  
      memset(cb, 0, sizeof(*cb));
    10.  
       
    11.  
      nlk->cb_running = true;
    12.  
          ret = netlink_dump(sk);
    13.  
      }

    用户空间应用调用recvmsg获取数据,相应的内核处理函数为netlink_recvmsg,读取sk_receive_queue上之前准备好的数据返回。除此之外,对于NL_F_DUMP调用,调用netlink_dump从之前记录的位置开始(保存在cb->args),继续准备要返回的数据。如果判断数据已经读取完成,在netlink的头机构的nlmsg_flags成员中设置NLMSG_DONE通知应用程序,清除cb_running标志,结束dump传输。

  • 相关阅读:
    理解ORM的前提:数据库中的范式和约束
    C#复习笔记(4)--C#3:革新写代码的方式(查询表达式和LINQ to object(下))
    设置或者得到CheckBoxList选中了的值
    Gridview中Datakeys 通过主键取得各列的值。
    如何直接在网页中显示PDF文件
    C#日期格式化
    asp.net 基础知识
    WebServers 异步
    asp.net中异步调用webservice
    C#中哈希表(HashTable)的用法详解
  • 原文地址:https://www.cnblogs.com/liuhongru/p/11413263.html
Copyright © 2011-2022 走看看