当前位置:文档之家› netlink学习

netlink学习

netlink学习
netlink学习

Netlink

开发和维护内核是一件很繁杂的工作,因此,只有那些最重要或者与系统性能息息相关的代码才将其安排在内核中。其它程序,比如GUI,管理以及控制部分的代码,一般都会作为用户态程序。在linux系统中,把系统的某个特性分割成在内核中和在用户空间中分别实现一部分的做法是很常见的(比如linux系统的防火墙就分成了内核态的Netfilter和用户态的iptables)。然而,内核程序与用户态的程序又是怎样行通讯的呢?

答案就是通过各种各样的用户态和内核态的

IPC(interprocess communication )机制来实现。比如系统调用,ioctl接口,proc文件系统以及netlink socket,本文就是要讨论netlink socekt并向读者展示这种用网络

通讯接口方式实现的IPC机制的优点。

介绍:

netlink socekt是一种用于在内核态和用户态进程之间进行数据传输的特殊的IPC。它通过为内核模块提

供一组特殊的API,并为用户程序提供了一组标准的socket 接口的方式,实现了一种全双工的通讯连接。类似于TCP/IP中使用AF_INET地址族一样,netlink socket使用地址族AF_NETLINK。每一个netlink

socket在内核头文件

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. 这种Routing socket是用户态进程用来向内核中的路由表增加或者删除路由信息用的。在Linux系统中,netlink socket通过协议类型NETLINK_ROUTE实现了与Routing socket相同的功能,可以说,netlink socket提供了BSD Routing socket 功能的超集。

Netlink Socket 的API

标准的socket API函数-

socket(), sendmsg(), recvmsg()和close()

- 都能够被用户态程序直接调用来访问netlink socket.你可以访问man手册来获取这些函数的详细定义。在本文,我们只讨论怎样在netlink socket的上下文中为这些函数选择参数。这些API对于使用TCP/IP socket写过一些简单网络

程序的读者来说应该很熟悉了。

使用socket()函数创建一个socket,输入:

int socket(int domain,int type,int protocol)

socket域(地址族)是AF_NETLINK,socket的类型是SOCK_RAW或者SOCK_DGRAM,因为netlink是一种面向数据包的服务。

协议类型选择netlink要使用的类型即可。下面是一些预定义的netlink协议类型:

NETLINK_ROUTE, NETLINK_FIREWALL, NETLINK_ARPD,

NETLINK_ROUTE6

和NETLINK_IP6_FW.

你同样可以很轻松的在netlink.h中添加自定义的协议类型。

每个netlink协议类型可以定义高达32个多点传输的组。每个组用一个比特位来表示,1<

当一组用户态进程和内核态进程协同实现一个相同的特性时,这个方法很有用,因为发送多点传输的netlink消息可以减少系统调用的次数,并且减少了相关应用程序的个数,这些程序本来是要用来处理维护多点传输组之间关系而带来的负载的。

bind()函数

跟TCP/IP中的socket一样,netlink的bind()函数把一个本地socket地址(源socket地址)与一个打开的socket进行关联,netlink地址结构体如下:

struct sockaddr_nl

{

sa_family_t nl_family;/* AF_NETLINK */

unsigned short nl_pad;/* zero */

__u32 nl_pid;/* process pid */

__u32 nl_groups;/* mcast groups mask */

} nladdr;

当上面的结构体被bind()函数调用时,sockaddr_nl的nl_pid属性的值可以设置为访问netlink socket的当前进程的PID,nl_pid作为这个netlink socket 的本地地址。应用程序应该选择一个唯一的32位整数来填充nl_pid的值。

NL_PID 公式1: nl_pid = getpid();

公式一使用进程的PID作为nl_pid的值,如果这个进程只需要一个该类型协议的netlink socket的话,选用进程pid作为nl_pid是一个很自然的做法。

换一种情形,如果一个进程的多个线程想要创建属于各个线程的相同协议类型的netlink socket的话,公式二可以用来为每个线程的netlink socket产生nl_pid 值。

NL_PID 公式2: pthread_self() << 16 | getpid();

采用这种方法,同一进程的不同线程都能获取属于它们的相同协议类型的不同netlink socket。事实上,即便是在一个单独的线程里,也可能需要创建同一协议类型的多个netlink socket。所以开发人员需要更多聪明才智去创建不同的nl_pid值,然而本文中不会就如何创建多个不同的nl_pid的值进行过多的讨论如果应用程序想要接收特定协议类型的发往指定多播组的netlink消息的话,所有接收组的比特位应该进行与运算,形成sockaddr_nl的 nl_groups域的值。否则的话,nl_groups应该设置为0,以便应用程序只能够收到发送给它的netlink消息。在填充完结构体 nladdr后,作如下的绑定工作:

bind(fd,(struct sockaddr*)&nladdr,sizeof(nladdr));

发送一个netlink 消息

为了能够把一个netlink消息发送给内核或者别的用户进程,类似于UDP数据包发送的sendmsg()函数一样,我们需要另外一个结构体 struct sockaddr_nl nladdr作为目的地址。如果这个netlink消息是发往内核的话,nl_pid属性和nl_groups属性都应该设置为0。

如果这个消息是发往另外一个进程的单点传输消息,nl_pid应该设置为接收者进程的PID,nl_groups应该设置为0,假设系统中使用了公式1。

如果消息是发往一个或者多个多播组的话,应该用所有目的多播组的比特位与运算形成nl_groups的值。然后我们就可以将netlink地址应用到结构体struct msghdr msg中,供函数sendmsg()来调用:

struct msghdr msg;

msg.msg_name =(void*)&(nladdr);

msg.msg_namelen =sizeof(nladdr);

netlink消息同样也需要它自身的消息头,这样做是为了给所有协议类型的netlink消息提供一个通用的背景。

由于linux内核的netlink部分总是认为在每个netlink消息体中已经包含了下面的消息头,所以每个应用程序在发送netlink消息之前需要提供这个头信息:struct nlmsghdr

{

__u32 nlmsg_len;/* Length of message */

__u16 nlmsg_type;/* Message type*/

__u16 nlmsg_flags;/* Additional flags */

__u32 nlmsg_seq;/* Sequence number */

__u32 nlmsg_pid;/* Sending process PID */

};

nlmsg_len 需要用netlink 消息体的总长度来填充,包含头信息在内,这个是netlink核心需要的信息。mlmsg_type可以被应用程序所用,它对于netlink

核心来说是一个透明的值。Nsmsg_flags 用来该对消息体进行另外的控制,会被netlink核心代码读取并更新。Nlmsg_seq和nlmsg_pid同样对于netlink核心部分来说是透明的,应用程序用它们来跟踪消息。

因此,一个netlink消息体由nlmsghdr和消息的payload部分组成。一旦输入一个消息,它就会进入一个被nlh指针指向的缓冲区。我们同样可以把消息发送个结构体struct msghdr msg:

struct iovec iov;

iov.iov_base =(void*)nlh;

iov.iov_len = nlh->nlmsg_len;

msg.msg_iov =&iov;

msg.msg_iovlen = 1;

在完成了以上步骤后,调用一次sendmsg()函数就能把netlink消息发送出去:sendmsg(fd,&msg, 0);

接收netlink消息:

接收程序需要申请足够大的空间来存储netlink消息头和消息的payload部分。它会用如下的方式填充结构体 struct msghdr msg,然后使用标准函数接口recvmsg()来接收netlink消息,假设nlh指向缓冲区:

struct sockaddr_nl nladdr;

struct msghdr msg;

struct iovec iov;

iov.iov_base =(void*)nlh;

iov.iov_len = MAX_NL_MSG_LEN;

msg.msg_name =(void*)&(nladdr);

msg.msg_namelen =sizeof(nladdr);

msg.msg_iov =&iov;

msg.msg_iovlen = 1;

recvmsg(fd,&msg, 0);

当消息正确接收后,nlh应该指向刚刚接收到的netlink消息的头部分。Nladdr 应该包含接收到消息体的目的地信息,这个目的地信息由pid和消息将要发往的多播组的值组成。Netlink.h中的宏定义NLMSG_DATA(nlh)返回指向netlink消息体的payload的指针。调用

close(fd)

就可以关闭掉fd描述符代表的netlink socket.

内核空间的netlink API接口

内核空间的netlink API是由内核中的netlink核心代码支持的,在

net/core/af_netlink.c中实现。从内核的角度来说,API接口与用户空间的 API 是不一样的。内核模块通过这些API访问netlink socket并且与用户空间的程序进行通讯。如果你不想使用netlink预定义好的协议类型的话,可以在netlink.h中添加一个自定义的协议类型。例如,我们可以通过在netlink.h中插入下面的代码行,添加一个测试用的协议类型:

#define NETLINK_TEST 17

然后,就可以在linux内核的任何部分访问这个协议类型了。

在用户空间,我们通过socket()调用来创建一个netlink socket,但是在内核空间,我们调用如下的API:

struct sock * netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));

参数uint是netlink协议类型,例如NETLINK_TEST。函数指针,input,是netlink socket在收到消息时调用的处理消息的回调函数指针。

在内核创建了一个NETLINK_TEST类型的netlink socket后,无论什么时候,只要用户程序发送一个NETLINK_TEST类型的netlink消息到内核的话,通过netlink_kernel_create()函数注册的回调函数input()都会被调用。下面是一个实现了消息处理函数input的例子。

void input (struct sock *sk,int len)

{

struct sk_buff *skb;

struct nlmsghdr *nlh =NULL;

u8 *payload =NULL;

while((skb = skb_dequeue(&sk->receive_queue))!=NULL)

{

/* process netlink message pointed by skb->data */

nlh =(struct nlmsghdr *)skb->data;

payload = NLMSG_DATA(nlh);

/* process netlink message with header pointed by

* nlh and payload pointed by payload

*/

}

}

回调函数input()是在发送进程的系统调用sendmsg()的上下文被调用的。如果input函数中处理消息很快的话,一切都没有问题。但是如果处理netlink消息花费很长时间的话,我们则希望把消息的处理部分放在input()函数的外面,因为长时间的消息处理过程可能会阻止其它系统调用进入内核。取而代之,我们可以牺牲一个内核线程来完成后续的无限的的处理动作。

使用

skb = skb_recv_datagram(nl_sk)

来接收消息。nl_sk是netlink_kernel_create()函数返回的netlink socket,然后,只需要处理skb->data指针指向的netlink消息就可以了。

这个内核线程会在nl_sk中没有消息的时候睡眠。因此,在回调函数input()中我们要做的事情就是唤醒睡眠的内核线程,像这样的方式:

void input (struct sock *sk,int len)

{

wake_up_interruptible(sk->sleep);

}

这就是一个升级版的内核与用户空间的通讯模型,它提高了上下文切换的粒度。从内核中发送netlink消息

就像从用户空间发送消息一样,内核在发送netlink消息时也需要设置源netlink地址和目的netlink地址。假设结构体struct sk_buff * skb指向存储着要发送的netlink消息的缓冲区,源地址可以这样设置:

NETLINK_CB(skb).groups = local_groups;

NETLINK_CB(skb).pid = 0;/* from kernel */

目的地址可以这样设置:

NETLINK_CB(skb).dst_groups = dst_groups;

NETLINK_CB(skb).dst_pid = dst_pid;

这些信息并不存储在 skb->data中,相反,它们存储在socket缓冲区的netlink 控制块skb中.

发送一个单播消息,使用:

int netlink_unicast(struct sock *ssk,struct sk_buff *skb, u32 pid,int nonblock);

ssk是by netlink_kernel_create()函数返回的netlink socket, skb->data

指向需要发送的netlink消息体,如果使用公式一的话,pid是接收程序的pid,noblock表明当接收缓冲区不可用时是否应该阻塞还是立即返回一个失败信息。

你同样可以从内核发送一个多播消息。下面的函数同时把一个netlink消息发送给pid指定的进程和group标识的多个组。

void netlink_broadcast(struct sock *ssk,struct sk_buff *skb, u32 pid, u32 group,int allocation);

group的值是接收消息的各个组的比特位进行与运算的结果。Allocation是内核内存的申请类型。通常情况下在中断上下文使用 GFP_ATOMIC,否则使用

GFP_KERNEL。这是由于发送多播消息时,API可能需要申请一个或者多个socket 缓冲区并进行拷贝所引起的。

从内核空间关闭netlink socket

netlink_kernel_create()函数返回的netlink socket为struct sock *nl_sk,我们可以通过访问下面的API来从内核空间关闭这个netlink socket:

sock_release(nl_sk->socket);

到目前为止,我们已经演示了netlink编程概念的最小代码框架。接着我们会使用NETLINK_TEST协议类型,并且假设它已经被添加到内核头文件中了。这里列举的内核模块代码只是与netlink相关的,所以,你应该把它插入到一个完整的内核模块代码当中去,这样的完整代码在其它代码中可以找到很多。

实例:

struct sk_buff *skb;

struct nlmsghdr *nlh;

u32 pid;

int rc;

int len = NLMSG_SPACE(1200);

char str[100];

printk("net_link: data is ready to read.\n");

skb = skb_get(__skb);

if(skb->len >= NLMSG_SPACE(0)){

nlh = nlmsg_hdr(skb);

printk("net_link: recv %s.\n",(char*)NLMSG_DATA(nlh));

memcpy(str,NLMSG_DATA(nlh),sizeof(str));

pid = nlh->nlmsg_pid;/*pid of sending process */

printk("net_link: pid is %d\n", pid);

kfree_skb(skb);

skb = alloc_skb(len, GFP_ATOMIC);

if(!skb){

printk(KERN_ERR "net_link: allocate failed.\n");

return;

}

nlh = nlmsg_put(skb,0,0,0,1200,0);

NETLINK_CB(skb).pid = 0;/* from kernel */

memcpy(NLMSG_DATA(nlh), str,sizeof(str));

printk("net_link: going to send.\n");

rc = netlink_unicast(nl_sk, skb, pid,MSG_DONTWAIT);

if(rc < 0){

printk(KERN_ERR "net_link: can not unicast skb (%d)\n", rc);

}

printk("net_link: send is ok.\n");

}

return;

}

static int test_netlink(void){

nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 0,

nl_data_ready,NULL, THIS_MODULE);

if(!nl_sk){

printk(KERN_ERR "net_link: Cannot create netlink socket.\n");

return-EIO;

}

printk("net_link: create socket ok.\n");

return 0;

}

int init_module()

{

test_netlink();

return 0;

}

void cleanup_module()

{

if(nl_sk !=NULL){

sock_release(nl_sk->sk_socket);

}

printk("net_link: remove ok.\n");

}

MODULE_LICENSE("GPL");

MODULE_AUTHOR("kidoln");

sender.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define MAX_PAYLOAD 1024 /* maximum payload size*/ struct sockaddr_nl src_addr, dest_addr;

struct nlmsghdr *nlh =NULL;

struct iovec iov;

int sock_fd;

struct msghdr msg;

int main(int argc,char* argv[])

{

sock_fd =socket(PF_NETLINK,SOCK_RAW, 21);

memset(&msg, 0,sizeof(msg));

memset(&src_addr, 0,sizeof(src_addr));

src_addr.nl_family =AF_NETLINK;

src_addr.nl_pid = getpid();/* self pid */

src_addr.nl_groups = 0;/* not in mcast groups */ bind(sock_fd,(struct sockaddr*)&src_addr,

sizeof(src_addr));

memset(&dest_addr, 0,sizeof(dest_addr));

dest_addr.nl_family =AF_NETLINK;

dest_addr.nl_pid = 0;/* For Linux Kernel */

dest_addr.nl_groups = 0;/* unicast */

nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));

/* Fill the netlink message header */

nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);

nlh->nlmsg_pid = getpid();/* self pid */

nlh->nlmsg_flags = 0;

/* Fill in the netlink message payload */

strcpy(NLMSG_DATA(nlh),"Hello you!");

iov.iov_base =(void*)nlh;

iov.iov_len = nlh->nlmsg_len;

msg.msg_name =(void*)&dest_addr;

msg.msg_namelen =sizeof(dest_addr);

msg.msg_iov =&iov;

msg.msg_iovlen = 1;

printf(" Sending message. ...\n");

sendmsg(sock_fd,&msg, 0);

C语言socket()函数:建立一个socket通信 相关函数:accept, bind, connect, listen 头文件:#include #include 定义函数:int socket(int domain, int type, int protocol); 函数说明:socket()用来建立一个新的socket, 也就是向系统注册, 通知系统建立一通信端口. 参数domain 指定使用何种的地址类型, 完整的定义在/usr/include/bits/socket.h 内, 底下是常见的协议: PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL UNIX 进程通信协议 PF_INET?AF_INET Ipv4 网络协议 PF_INET6/AF_INET6 Ipv6 网络协议 PF_IPX/AF_IPX IPX-Novell 协议 PF_NETLINK/AF_NETLINK 核心用户接口装置 PF_X25/AF_X25 ITU-T X. 25/ISO-8208 协议 PF_AX25/AF_AX25 业余无线AX. 25 协议 PF_ATMPVC/AF_ATMPVC 存取原始ATM PVCs PF_APPLETALK/AF_APPLETALK appletalk (DDP)协议 PF_PACKET/AF_PACKET 初级封包接口

参数type 有下列几种数值: 1、SOCK_STREAM 提供双向连续且可信赖的数据流, 即TCP. 支持OOB 机制, 在所有数据传送前必须使用connect()来建立连线状态. 2、SOCK_DGRAM 使用不连续不可信赖的数据包连接 3、SOCK_SEQPACKET 提供连续可信赖的数据包连接 4、SOCK_RAW 提供原始网络协议存取 5、SOCK_RDM 提供可信赖的数据包连接 6、SOCK_PACKET 提供和网络驱动程序直接通信. protocol 用来指定socket 所使用的传输协议编号, 通常此参考不用管它, 设为0 即可. 返回值:成功则返回socket 处理代码, 失败返回-1. 错误代码: 1、EPROTONOSUPPORT 参数domain 指定的类型不支持参数type 或protocol 指定的协议 2、ENFILE 核心内存不足, 无法建立新的socket 结构 3、EMFILE 进程文件表溢出, 无法再建立新的socket 4、EACCESS 权限不足, 无法建立type 或protocol 指定的协议 5、ENOBUFS/ENOMEM 内存不足 6、EINVAL 参数domain/type/protocol 不合法 范例:参考connect().

目录 1、Open vSwitch各模块简要介绍如下: (1) 2、基于 Open vSwitch 的 OpenFlow 实践(ubuntu 14.04) (1) 2.1 OpenvSwitch安装 (1) 2.2 OpenFlow 命令 (3) 2.4修改数据包 (9) 2.5重定向数据包 (10) 2.6修改vlan tag (11) 3、Open vSwitch连接到OpenDaylight (14) 4、Open vSwitch常用操作 (17)

1、OVS 各模块简要介绍如下: ovs-vswitchd :主要模块,实现switch 的daemon ,包括一个支持流交换的Linux 内核模块; ovsdb-server :轻量级数据库服务器,提供ovs-vswitchd 获取配置信息; ovs-dpctl :用来配置switch 内核模块; 一些Scripts and specs 辅助OVS 安装在Citrix XenServer 上,作为默认switch ; ovs-vsctl :查询和更新ovs-vswitchd 的配置; ovs-appctl :发送命令消息,运行相关daemon 。 OVS 提供了支持OpenFlow 的特性实现,包括: ovs-ofctl :查询和控制OpenFlow 交换机和控制器; ovs-pki :OpenFlow 交换机创建和管理公钥框架; ovs-tcpundump :tcpdump 的补丁,解析OpenFlow 的消息。 2、基于 Open vSwitch 的 OpenFlow 实践(ubuntu 14.04) 1.OpenFlow 命令如何创建交换机? 2.如何将一个端口添加到交换机上? 3.如何查看ovs 结构? 2.1 OpenvSwitch 安装 查看ubuntu 版本 : Ubuntu 14.04的OVS 版本,已经是2.02,所以默认安装就可以。不过不同的发行版,ovs 的名字会有点不同。

Linux内核QoS实现机制 1.QoS介绍 QoS(Quality of Service)即服务质量。对于网络业务,服务质量包括传输的带宽、传送的时延、数据的丢包率等。在网络中可以通过保证传输的带宽、降低传送的时延、降低数据的丢包率以及时延抖动等措施来提高服务质量。 网络资源总是有限的,只要存在抢夺网络资源的情况,就会出现服务质量的要求。服务质量是相对网络业务而言的,在保证某类业务的服务质量的同时,可能就是在损害其它业务的服务质量。例如,在网络总带宽固定的情况下,如果某类业务占用的带宽越多,那么其他业务能使用的带宽就越少,可能会影响其他业务的使用。因此,网络管理者需要根据各种业务的特点来对网络资源进行合理的规划和分配,从而使网络资源得到高效利用。 流量控制包括以下几种方式: ?SHAPING(限制) 当流量被限制,它的传输速率就被控制在某个值以下。限制值可以大大小于有效带宽,这样可以平滑突发数据流量,使网络更为稳定。shaping(限制)只适用于向外的流量。 ?SCHEDULING(调度) 通过调度数据包的传输,可以在带宽范围内,按照优先级分配带宽。SCHEDULING(调度)也只适于向外的流量。 ?POLICING(策略) SHAPING用于处理向外的流量,而POLICIING(策略)用于处理接收到的数据。 ?DROPPING(丢弃) 如果流量超过某个设定的带宽,就丢弃数据包,不管是向内还是向外。

2.内核实现过程 图表 1 流量控制过程 绿色部分就是Linux内核实现的QoS模块,其中ingress policing 是处理输入数据包的,而output queueing 则是处理输出数据包的。 2.1.Ingress实现机制 Ingress QOS在内核的入口点有两个,但是不能同时启用,这取决于内核编译选项。当打开了CONFIG_NET_CLS_ACT(from 2.6.8 release still available on 2.6.39 release)时,入口点在src/net/core/dev.c的netif_receive_skb函数中;当没有打开CONFIG_NET_CLS_ACT,而是打开了CONFIG_NET_CLS_POLICE (from 2.6.9 release to 2.6.24, thus this is an obsolete configuration)和CONFIG_NETFILTER时,就会在netfilter的PREROUTING钩子点处调用ing_hook函数。

Netlink 是一种特殊的socket,它是Linux 所特有的,类似于BSD 中的 AF_ROUTE 但又远比它的功能强大,目前在最新的Linux 内核(2.6.14)中使用netlink 进行应用与内核通信的应用很多,包括:路由daemon (NETLINK_ROUTE),1-wire 子系统(NETLINK_W1),用户态socket 协议(NETLINK_USERSOCK),防火墙(NETLINK_FIREWALL),socket 监视(NETLINK_INET_DIAG),netfilter 日志(NETLINK_NFLOG),ipsec 安全策略(NETLINK_XFRM),SELinux 事件通知(NETLINK_SELINUX),iSCSI 子系统(NETLINK_ISCSI),进程审计(NETLINK_AUDIT),转发信息表查询(NETLINK_FIB_LOOKUP),netlink connector(NETLINK_CONNECTOR),netfilter 子系统(NETLINK_NETFILTER),IPv6 防火墙(NETLINK_IP6_FW),DECnet 路由信息(NETLINK_DNRTMSG),内核事件向用户态通知(NETLINK_KOBJECT_UEVENT),通用netlink (NETLINK_GENERIC)。 Netlink 是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的socket API 就可以使用netlink 提供的强大功能,内核态需要使用专门的内核API 来使用netlink。 Netlink 相对于系统调用,ioctl 以及/proc 文件系统而言具有以下优点: 1,为了使用netlink,用户仅需要在include/linux/netlink.h 中增加一个新类型的netlink 协议定义即可,如#define NETLINK_MYTEST 17 然后,内核和用户态应用就可以立即通过socket API 使用该netlink 协议类型进行数据交换。但系统调用需要增加新的系统调用,ioctl 则需要增加设备或文件,那需要不少代码,

本文档的Copyleft归wwwlkk所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁用于任何商业用途。 E-mail: wwwlkk@https://www.doczj.com/doc/e917712797.html, 来源: https://www.doczj.com/doc/e917712797.html,/?business&aid=6&un=wwwlkk#7 netlink实现分析 (1)网络file对象。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。1 (2)netlink网络file对象。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。3 (3)netlink消息接收端。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。5 (3.1)内核路径注册netlink接收端。。。。。。。。。。。。。。。。。。。。6 (3.2)用户进程注册netlink接收端。。。。。。。。。。。。。。。。。。。。6 (3.3)内核netlink接收端接收消息。。。。。。。。。。。。。。。。。。。。6 (3.4)用户进程netlink接收端接收消息。。。。。。。。。。。。。。。。6 (4)通信效率分析。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。7 (5)实现零拷贝的两个理论方案。。。。。。。。。。。。。。。。。。。。。。。。。。。7 (1)网络file对象 当网络双方的通信线路建立好之后,双发就可以开始互相传递数据,可以使用write()和read()传递数据。可见网络通信也同样使用了文件系统的架构,这里的file对象是比较特殊的,结构如图1所示: 图1 网络file对象结构 其中static const struct file_operations socket_file_ops = { .owner = THIS_MODULE,

IT 类设备采购标准管理制度 一. 目的及适用范围 为适应公司信息化总体建设规划、规范公司计算机及相关IT设备统一购买程序,降低总体采购成本,合理调配相关资源,提高设备使用率与维护效率,特制定本办法。 本办法适用于XXXX公司及其下属分、子公司。 二. 定义术语 2.1 计算机设备 具有正常办公使用的计算机。包括服务器、计算机主机(台式机电脑、笔记本电脑)、显示器等。 2.2 计算机外设 辅助计算机设备输入输出的外部设备。包括复印机、打印机、传真机、扫描仪、投影仪、一体机等。(鼠标、键盘、移动硬盘、U盘等损耗类外设不在此范围内) 2.3 网络设备 连接网络中的物理实体进行相互信息交换的物理设备。包括交换机、无线接入点、企业级路由器、安全防御设备、网络接口卡、光纤收发器等。(网线、水晶头等损耗类外设不在此范围内) 2.4 其它设备 配合公司信息化运行的其它设备。包括考勤机、消费机、门禁机、智能门锁等辅助管理设备。 三. 职责与流程 经营部:核实各部门的采购申请是否符合采购标准及申购部门的需求。 信息部:调配公司内各类IT 设备资源。核实各部门IT 设备使用情况,判断是否需要采购新设备。 本办法所涉及流程严格按照公司采购流程执行。 四. 采购配置标准 4.1 计算机设备配置原则 4.1.1、公司IT 设备选型与配置标准依据公司的岗位需求,并结合市场品牌与价格变化情况制定,经测试完全满足公司各岗位日常办公需求。 4.1.2、办公用电脑、服务器实行公司统一标准、统一采购、统一规范品牌。 4.1.3、为减少设备闲置浪费情况,使用人申请办公用电脑限一人一台。如有经常移动办公需求的人员,须经相关领导审批同意后,方可调配笔记本电脑。 4.1.4、为降低公司采购与维护成本,不再采购笔记本电脑。库存笔记本电脑可继续使用,直至报废为止。 4.1.5、如有移动办公需求,且无库存笔记本电脑可调配,可自备笔记本电脑;公司对自备笔记本电脑的员工实行补贴机制,详见本制度第5项笔记本电脑补贴。 4.1.6、已配置办公电脑的人员,如性能无法满足工作需求,优先进行硬件升级,如升级后仍不能满足需求,可考虑采购新电脑,需全部满足以下情况,方可进入采购流程: A库存电脑不足;

?双向传输,异步通信 ?用户空间中使用标准socket API ?内核空间中使用专门的API ?支持多播 ?可由内核端发起通信 ?支持32种协议类型 netlink仅支持32种协议类型,这在实际应用中可能并不足够。因此产生了generic netlink(以下简称为genl)。 generic netlink支持1023个子协议号,弥补了netlink协议类型较少的缺陷。支持协议号自动分配。它基于netlink,但是在内核中,generic netlink的接口与netlink并不相同。 1. Generic Netlink框架概述 图1表示了Generic Netlink框架。Kernel socket API向用户空间和内核空间分别提供接口。Netlink子系统(1)是所有genl通信的基础。Netlink子系统中收到的所有Generic类型的netlink数据都被送到genl总线(2)上;从内核发出的数据也经由genl总线送至netlink子系统,再打包送至用户空间。 Generic Netlink控制器(4)作为内核的一部分,负责动态地分配genl通道(即genl family id),并管理genl任务。genl控制器是一个特殊的genl内核用户,它负责监听genl bus上的通信通道。genl通信建立在一系列的通信通道的基础上,每个genl family对应多个通道,这些通道由genl控制器动态分配。 +---------------------+ +---------------------+ | (3) application "A" | | (3) application "B" | +------+--------------+ +--------------+------+ | | \ /

netlink socket编程why & how 作者: Kevin Kaichuan He@2005-1-5 翻译整理:duanjigang @2008-9-15 原文:https://www.doczj.com/doc/e917712797.html,/article/7356 开发和维护内核是一件很繁杂的工作,因此,只有那些最重要或者与系统性能息息相关的代码才将其安排在内核中。其它程序,比如GUI,管理以及控制部分的代码,一般都会作为用户态程序。在linux系统中,把系统的某个特性分割成在内核中和在用户空间中分别实现一部分的做法是很常见的(比如linux系统的防火墙就分成了内核态的Netfilter和用户态的iptables)。然而,内核程序与用户态的程序又是怎样行通讯的呢? 答案就是通过各种各样的用户态和内核态的IPC(interprocess communication )机制来实现。比如系统调用,ioctl接口,proc文件系统以及netlink socket,本文就是要讨论netlink socekt并向读者展示这种用网络通讯接口方式实现的IPC机制的优点。 介绍: netlink socekt是一种用于在内核态和用户态进程之间进行数据传输的特殊的IPC。它通过为内核模块提供一组特殊的API,并为用户程序提供了一组标准的socket 接口的方式,实现了一种全双工的通讯连接。类似于TCP/IP中使用AF_INET地址族一样,netlink socket使用地址族AF_NETLINK。每一个netlink socket在内核头文件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进行通讯了!

基于工业以太网交换机的SNMP代理实现 1引言 尹雪,于海 (国网电力科学研究院信通所,南京211100) 摘要:SNMP(简单网络管理协议)是当今最流行的网络管理协议。该文以工业以太网交换机为平台,构建了以太网交换机的SNMP网络管理模型,实现了基于以太网交换机的SNMP代理。读者可以了解到带有网络管理功能的交换机的软硬件体系结构,MIB 库的构建,在Linux下SNMP代理软件的实现方法。同时,也介绍了在Linux下Netlink socket的应用及设备驱动程序的编写。 关键词:以太网交换机;简单网络管理协议;管理信息库 SNMP Agent Realization Based on Industry Ethernet Switch YIN Xue, YU Hai (Research Institute of Information Technology & Communication, SGEPRI, Nanjing 211100, China) Abstract: SNMP is the most popular network management protocol now. This paper take the industry Ethernet switch as a platform, An Ethernet switch's network management model is constructed based on the SNMP, the SNMP agent is realized on the Ethernet switch. The reader could know the software and hardware architecture of managed switch, how to build MIB and the achieving of the SNMP agent software on Linux platform. At the same time, the application of Netlink socket on Linux, and the writing of Linux device driver are also proposed. Keywords: ethernet switch, SNMP, MIB 网络是一个非常复杂的分布式系统,为了对网络资源进行监视、测试、配置、评价和控制,我们需要对网络进行必要的管理,这便是人们熟知的网管的概念。它可以让网络管理员通过网络管理程序对网络上的资源进行集中化管理,这一过程通常包括数据收集、数据处理, 然后提交给管理者;它可能还包括分析数据并提供解决方案,甚至可以不需要打扰管理者而自动处理某些情况。 工业以太网交换机主要是应用于复杂的工业环境中的实时以太网数据传输。以太网在设计时,由于其采用载波侦听多路复用冲突检测(CSMA/CD机制),在复杂的工业环境中应用,其可靠性大大降低,从而导致以太网不能使用。工业以太网交换机采用存储转换交换方式,同时提高以太网通信速度,并且内置智能报警设计监控网络运行状况,使得在恶劣危险的工业环境中保证以太网可靠稳定的运行。 交换机中加入网络管理功能是当今交换机的发展趋势。工业以太网交换机不但要具备命令行方式作者简介:尹雪,男,硕士,助理工程师,从事信息通信产品研发;E-mail: yinxue200610@https://www.doczj.com/doc/e917712797.html,

本文介绍了在Linux环境下根据EABI标准进行call trace调试的一般性原理。 本文所说的call trace是指程序出问题时能把当前的函数调用栈打印出来。 本文只介绍了得到函数调用栈的一般性原理,没有涉及Linux的core dump机制。 下面简单介绍powerpc环境中如何实现call trace。 内核态call trace 内核态有三种出错情况,分别是bug,oops和panic。 bug属于轻微错误,比如在spin_lock期间调用了sleep,导致潜在的死锁问题,等等。oops代表某一用户进程出现错误,需要杀死用户进程。这时如果用户进程占用了某些信号锁,所以这些信号锁将永远不会得到释放,这会导致系统潜在的不稳定性。 panic是严重错误,代表整个系统崩溃。 OOPS 先介绍下oops情况的处理。Linux oops时,会进入traps.c中的die函数。 int die(const char*str,struct pt_regs*regs,long err) 。。。 show_regs(regs); void show_regs(struct pt_regs*regs)函数中,会调用show_stack函数,这个函数会打印系统的内核态堆栈。 具体原理为: 从寄存器里找到当前栈,在栈指针里会有上一级调用函数的栈指针,根据这个指针回溯到上一级的栈,依次类推。 在powerpc的EABI标准中,当前栈的栈底(注意是栈底,不是栈顶,即Frame Header的地址)指针保存在寄存器GPR1中。在GPR1指向的栈空间,第一个DWORD为上一级调用函数的Frame Header指针(Back Chain Word),第二个DWORD是当前函数在上一级函数中的返回地址(LR Save Word)。通过此种方式一级级向上回溯,完成整个call dump。除了这种方法,内建函数__builtin_frame_address函数理论上也应该能用,虽然在内核中没有见到。(2.6.29的ftrace模块用到了__builtin_return_address函数)。 show_regs函数在call trace的时候,只是用printk打印了一下栈中的信息。如果当前系统没有终端,那就需要修改内核,把这些栈信息根据需求保存到其它地方。 例如,可以在系统的flash中开出一块空间专门用于打印信息的保存。然后,写一个内核模块,再在die函数中加一个回调函数。这样,每当回调函数被调用,就通知自定义的内核模块,在模块中可以把调用栈还有其它感兴趣的信息保存到那块专用flash空间中去。这里有一点需要注意的是,oops时内核可能不稳定,所以为了确保信息能被正确写入flash,在写flash的函数中尽量不要用中断,而用轮循的方式。另外信号量、sleep等可能导致阻塞的函数也不要使用。 此外,由于oops时系统还在运行,所以可以发一个消息(信号,netlink等)到用户空间,通知用户空间做一些信息收集工作。 Panic Panic时,Linux处于更最严重的错误状态,标志着整个系统不可用,即中断、进程调度等

Linux内核空间与用户空间通信机制的研究 Linux kernel space and user space communication mechanism 摘要 Linux是一个源码开放的操作系统,无论是普通用户还是企业用户都可以编写自己的内核代码,再加上对标准内核的裁剪从而制作出适合自己的操作系统,深受大家喜爱。Linux系统中,在使用虚拟内存技术的多任务系统上,内核和用户有不同的地址空间,因此,在内核与用户之间进行数据交换需要专门的机制来实现。一个或多个内核模块的实现并不能满足一般Linux 系统软件的需要,因为内核的局限性太大,内核空间与用户空间进程通信的方法就显得尤为重要。本文将列举几种内核态与用户态进程通信的方法:Netlink通信机制,基于文件系统的通信机制,内核启动参数通信机制,并用实验板对几种重要的通信机制进行验证,详细分析它们的实现和适用环境,优缺点,并做出比较。提供用户适合使用这种通信机制的环境,以便更好的运用Linux操作系统。

关键字内核空间用户空间地址空间

ABSTRACT Linux is an open source operating system, whether ordinary users or business users can write your own kernel code, with the modification of the standard kernel,everyone can make up their own operating system, which makes Linux popular.In Linux systems, in the use of multi-tasking system with virtual memory technology, the kernel and the user have different address spaces, so the change of data between kernel and user needs Special Method to achieve. One or more kernel modules can not meet the general needs of Linux system software, just because the limitations of the kernel, make it important that the process communication method between kernel space and user space. In this article I will list some kernel mode and user mode process communication methods: Netlink communication mechanism, communication mechanism based on the file system, the kernel boot parameters of communication mechanism. I will analysis of their implementation, application environment, the advantages and disadvantages in detail, and make the comparison. I will provide users with suitable environment for each communication mechanism in order to let others make good use of Linux operating system. Keywords kernel space user space address spaces

1 引言 Linux 是一类Unix计算机操作系统的统称。Linux 操作系统的内核的名字也是“Linux”。Linux 操作系统也是自由软件和开放源代码发展中最著名的例子。Linux 是一套免费使用和自由传播的类Unix 操作系统。无论是普通用户还是企业用户都可以编写自己的内核代码,再加上对标准内核的裁剪从而制作出适合自己的操作系统。 一个或多个内核模块的实现并不能满足一般 Linux 系统软件的需要,因为内核的局限性太大,如不能在终端上打印,不能做大延时的处理等等。当需要做这些的时候,就需要将在内核态采集到的数据传送到用户态的一个或多个进程中进行处理。这样,内核态与用空间进程通信的方法就显得尤为重要。将列举 Linux 下基于 Netlink 机制的内核态与用户态进程通信的方法以及如何实现用户态和内核态的内存共享。 2 用户态和内核态 用户态与内核态是操作系统的两种运行级别,IntelCPU提供Ring0-Ring33种级别的运行模式。Ring0级别最高Ring3最低。 用户态:当进程在执行用户自己的代码时,则称其处于用户运行态即用户态。此时处理器在特权级最低的(3 级)用户代码中运行。 内核态:当一个任务(进程)执行系统调用而陷入内核代码中执行时,就称进程处于内核运行态或简称为内核态。此时处理器处于特权级最高的 0 级内核代码中执行。当进程处于内核态时,执行

的内核代码会使用当前进程的内核栈。 在内核态下 CPU 可执行任何指令,在用户态下 CPU 只能执行非特权指令。当 CPU 处于内核态,可以随意进入用户态;而当 CPU 处于用户态时,用户从用户态切换到内核态只有在系统调用和中断两种情况下发生,一般程序一开始都是运行于用户态,当程序需要使用系统资源时,就必须通过调用软中断进入内核态。 3 Linux 的用户态和内核态 Linux 使用了 Ring3 级别运行用户态,Ring0 作为内核态。Ring3状态不能访问 Ring0的地址空间包括代码和数据 Linux 进程的 4GB 地址空间,3GB-4GB 部分是共享的,是内核态的地址空间,这里存放着整个内核的代码和所有的内核模块,以及内核所维护的数据。 用户运行一个程序,该程序所创建的进程开始是运行在用户态的,如果要执行文件操作,网络数据发送等操作,必须通过 write,send 等系统调用,这些系统调用会利用内核中的代码来完操作,这时,必须切换到Ring0,然后进入3GB-4GB 中的内核地址空间去执行这些代码,完成操作,完成后,切换回 Ring3,回到用户态。这样,用户态的程序就不 能随意操作内核地址空间,具有一定的安全保护作用。 4实现内核态与用户态的通信 内核与用户空间共享内存的关键是,用户空间必须知道共享内存的起始地址,这就要求内核空间应该有一种通信机制来通知用户空

内核编译配置选项简介(2.4.18-rmk7-pxal) 来源: ChinaUnix博客作者:发布时间:2007-01-02 Code maturity level options 代码成熟度选项 Prompt for development and/or incomplete code/drivers 显示尚在研发中或尚未完成的代码和驱动.除非您是测试人员或研发者,否则请勿选择 我是研发者,所以选 [ ]Prompt for obsolete code/drivers 显示废弃的代码或驱动 Loadable module support 可加载模块支持 Enable loadable module support 打开可加载模块支持,假如打开他则必须通过"make modules_install"把内核模块安装在 /lib/modules/中 [ ]Set version information on all module symbols 允许使用其他内核版本的模块(可能会出问题) 建议不选,能够避免模块版本不匹配 kernel module loader 让内核通过运行modprobe来自动加载所需要的模块,比如能够自动解决模块的依赖关系 System Type 系统类型 (S3C2410-based) ARM system type ARM系统,基于S3C2410 ---S3C2410 Implementation 基于S3C2410架构的实现 SMDK (MERI TECH BOARD) SMDK2410是Samsung的S3C2410的Reference board,即公板 公板是芯片厂家提供的样板卡。现在市面上的产品绝大多数都是公板的,因为使用公板能够减少研发成本,特别是现在产品的推 陈出新速度很快,造成绝大多数生产厂商为了追新,只能使用公板。 change AIJI 支持AIJI的更新 韩国爱极(AIJI)系统有限公司是三星公司最重要的技术合作伙伴,能够提供基于任何三星处理器尤其是三星ARM处理器的研发 解决方案,如基于44B0、2410、2412、2413、2440、PSA926EJ和PSA920T等处理器的研发板 by threewater--] 三水==刘淼,呵呵,博创技术总监 S3C2410 USB function support 支持S3C2410的USB功能 Support for S3C2410 USB character device emulation 支持S3C2410的USB字符设备仿真 ---Processor Type 处理器类型

一、Socket()函数 函数原型int socket(int domain, int type, int protocol); 参数: Domain:指定用何种地址类型,完整的定义在/usr/include/bits/socket.h内 PF——UNIX/PF_LOCAL/AF_ UINIX进程通讯协议 UNIX/AF_LOCAL PF_INET/AF_INET IPV4网络协议 PF_INET6/AF_INET6 IPV6网络协议 PF_IPX/AF_IPX IPX-Novell协议 PF_NETLINK/AF_NETLINK 核心用户接口装置 PF_X25/AF_X25 ITU-TX.25/ISO-8208协议 PF_AX25/AF_AX25 业余无线AX.25协议 PF_ATMPVC/AF_ATMPVC 存取原始ATM PVCs PF_APPLETALK/AF_APPLETALK Appletalk(DDP)协议 PF_PACKET/AF_PACKET 初始封包接口 Type: SOCK_STREAM 提供双向连续且可信赖的数据流,即TCP。支持OOB(out-of-band)机制。在所有数据传输前必须使用connect()来建立连线状态。 SOCK_DGRAM 使用不连续不可信连的数据包连接UDP。 SOCK_SEQP ACKET 提供连续可信赖的数据包连接 SOCK_RAW 提供原始网络协议存取 SOCK_RDM 提供可信赖的数据包连接 SOCK_P ACKET 提供网络驱动程序直接通信 Protocol用来指定socket所使用的传输协议编号,通常此参考不用管它,设为0即可。 返回值: 成功执行时,返回0。失败返回-1,errno被设为以下的某个值 EPROTONOSUPPORT 参数domain指定的类型不支持参数type或protocol指定的协 议 ENFILE 核心内存不足,无法建立新的socket结构 EACCESS 权限不足,无法建立参数type或protocol指定的协议 ENOBUFS/ENOMEM 内存不足 EINV AL 参数domain/type/protocol不合法 执行流程: 当我们在应用程序调用API函数socket(AF_INET, SOCK_STREAM,IPPROTO_TCP)时就会调用socket的系统调用进入统一的入口函数sys_socketcall,如果是创建套接字,就会调用sys_socket,sys_socket然后就调用sock_create,这个才是真正执行socket创建的函数。 Sock_create函数调用socket_alloc创建socket,主要分配两个主要数据,一个是套接字socket,另一个是socket对应的inode。Socket的结构为: struct socket { socket_state state; unsigned long flags; struct proto_ops *ops;

Linux中与内核通信的Netlink机制 Netlink在2.6版本的内核中变化也是很大的,在最新的2.6.37内核中,其定义已经改成下面这种形式,传递的参数已经达到6个。其中第一个参数和mutex参数都是最新添加的。Mutex 也可以为空。这里主要是关于内核空间中的netlink函数的使用。 extern struct sock *netlink_kernel_create(struct net *net, int unit,unsigned int groups, void (*input)(struct sk_buff *skb), struct mutex *cb_mutex, struct module *module); struct net是一个网络名字空间namespace,在不同的名字空间里面可以有自己的转发信息库,有自己的一套net_device等等。默认情况下都是使用init_net这个全局变量,下面是内核中调用netlink_kernel_create()函数的一个示例。 在内核中, audit_sock = netlink_kernel_create(&init_net, NETLINK_AUDIT, 0, audit_receive, NULL, THIS_MODULE); 模块调用函数netlink_unicast 来发送单播消息:int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock) 参数ssk为函数netlink_kernel_create()返回的socket,参数skb存放消息,它的data字段指向要发送的netlink消息结构,而skb的控制块保存了消息的地址信息,前面的宏NETLINK_CB(skb)就用于方便设置该控制块,参数pid为接收消息进程的pid,参数nonblock 表示该函数是否为非阻塞,如果为1,该函数将在没有接收缓存可利用时立即返回,而如果为0,该函数在没有接收缓存可利用定时睡眠。 netlink的内核实现在.c文件net/core/af_netlink.c中,内核模块要想使用netlink,也必须包含头文件linux/netlink.h。内核使用netlink需要专门的API,这完全不同于用户态应用对netlink的使用。如果用户需要增加新的netlink协议类型,必须通过修改linux/netlink.h来实现,当然,目前的netlink实现已经包含了一个通用的协议类型NETLINK_GENERIC以方便用户使用,用户可以直接使用它而不必增加新的协议类型。前面讲到,为了增加新的netlink 协议类型,用户仅需增加如下定义到linux/netlink.h就可以: 只要增加这个定义之后,用户就可以在内核的任何地方引用该协议。 在内核中,为了创建一个netlink socket用户需要调用如下函数: extern struct sock *netlink_kernel_create(struct net *net, int unit,unsigned int groups, void (*input)(struct sk_buff *skb), struct mutex *cb_mutex,

1.如何编写一个LINUX驱动? 2.Linux设备中字符设备与块设备有什么主要的区别?请分别列举一些实际的设备说出它们是属于哪一类设备。 字符设备:字符设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序来实现这种特性。字符设备驱动程序通常至少实现open,close,read和write系统调用。字符终端、串口、鼠标、键盘、摄像头、声卡和显卡等就是典型的字符设备。 块设备:和字符设备类似,块设备也是通过/dev目录下的文件系统节点来访问。块设备上能够容纳文件系统,如:u盘,SD卡,磁盘等。 字符设备和块设备的区别仅仅在于内核内部管理数据的方式,也就是内核及驱动程序之间的软件接口,而这些不同对用户来讲是透明的。 3.查看驱动模块中打印信息应该使用什么命令?如何查看内核中已有的字符设备的信息?如何查看正在使用的有哪些中断号? 1)查看驱动模块中打印信息的命令:dmesg 2)查看字符设备信息可以用lsmod和modprobe,lsmod可以查看模块的依赖关系,modprobe 在加载模块时会加载其他依赖的模块。 3)显示当前使用的中断号cat/proc/interrupt 4.请简述主设备号和次设备号的用途。如果执行mknodchartestc464,创建chartest 使用的是那一类设备驱动程序。 1)主设备号:主设备号标识设备对应的驱动程序。虽然现代的linux内核允许多个驱动程序共享主设备号,但我们看待的大多数设备仍然按照“一个主设备对应一个驱动程序”的原则组织。 次设备号:次设备号由内核使用,用于正确确定设备文件所指的设备。依赖于驱动程序的编写方式,我们可以通过次设备号获得一个指向内核设备的直接指针,也可将此设备号当作设备本地数组的索引。 2)chartest由驱动程序4管理,该文件所指的设备是64号设备。(感觉类似于串口终端或者字符设备终端)。 5.设备驱动程序中如何注册一个字符设备?分别解释一下它的几个参数的含义。 注册一个字符设备驱动有两种方法: 1)voidcdev_init(structcdev*cdev,structfile_operations*fops) 该注册函数可以将cdev结构嵌入到自己的设备特定的结构中。cdev是一个指向结构体cdev 的指针,而fops是指向一个类似于file_operations结构(可以是file_operations结构,但不限于该结构)的指针.

相关主题
文本预览
相关文档 最新文档