netlink socket编程之why & how

来源:互联网 发布:丁红玉淘宝 编辑:程序博客网 时间:2024/06/06 10:45

netlink socket编程之why & how
作者: Kevin Kaichuan He@2005-1-5
翻译整理:duanjigang @2008-9-15<duanjigang1983@126.com>
原文: http://www.linuxjournal.com/article/7356

   
开发和维护内核是一件很繁杂的工作,因此,只有那些最重要或者与系统性能息息相关的代码才将其安排在内核中。其它程序,比如GUI,管理以及控制部分的代码,一般都会作为用户态程序。在linux系统中,把系统的某个特性分割成在内核中和在用户空间中分别实现一部分的做法是很常见的(比如linux系统的防火墙就分成了内核态的Netfilter和用户态的iptables)。然而,内核程序与用户态的程序又是怎样行通讯的呢?
答案就是通过各种各样的用户态和内核态的IPC(interprocess  communication  )机制来实现。比如系统调用,ioctl接口,proc文件系统以及netlinksocket,本文就是要讨论netlink socekt并向读者展示这种用网络
通讯接口方式实现的IPC机制的优点。

介绍:
netlink socekt是一种用于在内核态和用户态进程之间进行数据传输的特殊的IPC。它通过为内核模块提
供一组特殊的API,并为用户程序提供了一组标准的socket 接口的方式,实现了一种全双工的通讯连接。类似于TCP/IP中使用AF_INET地址族一样,netlink socket使用地址族AF_NETLINK。每一个netlink
socket在内核头文件

[Copy to clipboard] [ - ]
CODE:
include/linux/netlink.h


中定义自己的协议类型。
下面是netlink socket 目前的特性集合以及它支持的协议类型:

NETLINK_ROUTE 用户空间的路由守护程序之间的通讯通道,比如BGP,OSPF,RIP以及内核数据转发模块。用户态的路由守护程序通过此类型的协议来更新内核中的路由表。
NETLINK_FIREWALL:接收IPV4防火墙代码发送的数据包。
NETLINK_NFLOG:用户态的iptables管理工具和内核中的netfilter模块之间通讯的通道。
NETLINK_ARPD:用来从用户空间管理内核中的ARP表。


   为什么以上的功能在实现用户程序和内核程序通讯时,都使用netlink方法而不是系统调用,ioctls
或者proc文件系统呢?原因在于:为新的特性添加一个新的系统调用,ioctls或者一个proc文件的做法并不是很容易的一件事情,因为我们要冒着污染内核代码并且可能破坏系统稳定性的风险去完成这件事情。
然而,netlink socket却是如此的简单,你只需要在文件netlink.h中添加一个常量来标识你的协议类型,然后,内核模块和用户程序就可以立刻使用socket风格的API进行通讯了!
        Netlink提供了一种异步通讯方式,与其他socket API一样,它提供了一个socket队列来缓冲或者平滑
瞬时的消息高峰。发送netlink消息的系统调用在把消息加入到接收者的消息对列后,会触发接收者的接收处理函数。接收者在接收处理函数上下文中,可以决定立即处理消息还是把消息放在队列中,在以后其它上下文去处理它(因为我们希望接收处理函数执行的尽可能快)。系统调用与netlink不同,它需要一个同步的处理,因此,当我们使用一个系统调用来从用户态传递消息到内核时,如果处理这个消息的时间很长的话,内核调度的粒度就会受到影响。
       内核中实现系统调用的代码都是在编译时静态链接到内核的,因此,在动态加载模块中去包含一个系统调用的做法是不合适的,那是大多数设备驱动的做法。使用netlink socket时,动态加载模块中的netlink程序不会和linux内核中的netlink部分产生任何编译时依赖关系。
Netlink优于系统调用,ioctls和proc文件系统的另外一个特点就是它支持多点传送。一个进程可以把消息传输给一个netlink组地址,然后任意多个进程都可以监听那个组地址(并且接收消息)。这种机制为内核到用户态的事件分发提供了一种近乎完美的解决方案。
系统调用和ioctl都属于单工方式的IPC,也就是说,这种IPC会话的发起者只能是用户态程序。但是,如果内核有一个紧急的消息想要通知给用户态程序时,该怎么办呢?如果直接使用这些IPC的话,是没办法做到这点的。通常情况下,应用程序会周期性的轮询内核以获取状态的改变,然而,高频度的轮询势必会增加系统的负载。Netlink 通过允许内核初始化会话的方式完美的解决了此问题,我们称之为netlink socket的双工特性。
        最后,netlink socket提供了一组开发者熟悉的BSD风格的API函数,因此,相对于使用神秘的系统调用API或者ioctl而言,netlink开发培训的费用会更低些。
        与BSD的Routing socket的关系
在BSD TCP/IP的协议栈实现中,有一种特殊的socket叫做Routing socket.它的地址族为AF_ROUTE,协议族为PF_ROUTE, socket类型为SOCK_RAW. 这种Routingsocket是用户态进程用来向内核中的路由表增加或者删除路由信息用的。在Linux系统中,netlinksocket通过协议类型NETLINK_ROUTE实现了与Routing socket相同的功能,可以说,netlinksocket提供了BSD Routing socket功能的超集。

原创粉丝点击