netlink
来源:互联网 发布:网络进度计划波浪线 编辑:程序博客网 时间:2024/05/21 14:42
用以实现用户进程与内核进程通信
netlink 套接字的最大特点是对中断过程的支持
内核与用户数据交换
sysfs、sysctl、netlink、procfs、seq_file、debugfs和relayfs
优点
- Netlink通过socket API;而ioctl和proc文件系统均需要通过程序加入相应的设备或文件
- Netlink使用socket缓存队列,是一种异步通信机制,而ioctl是同步通信机制,如果传输的数据量较大,会影响系统性能
- Netlink支持多播,属于一个Netlink组的模块和进程都能获得该多播消息
- Netlink允许内核发起会话,而ioctl和系统调用只能由用户空间进程发起
用户空间
int socket(int domain, int type, int protocol);
domain:PF_NETLINK
struct sockaddr_nl{ sa_family_t nl_family; unsigned short nl_pad; __u32 nl_pid; __u32 nl_groups;};int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
nl_pid:接收或发送消息的进程ID,如果希望内核处理消息或多播消息,就把该字段设置为 0,否则设置为处理消息的进程ID(线程使用pthread_self() << 16 | getpid())
nl_groups:指定多播组。bind 函数把调用进程加入到该字段指定的多播组,如果设置为 0,表示调用者不加入任何多播组
//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 *///源端口};/*总长度*/#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))/*字节对齐*/#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
nlmsg_len:消息的总长度(包含消息头)。一般地,使用NLMSG_LENGTH来计算对齐后的总长度
nlmsg_type:应用内部定义的消息类型
#define NLMSG_NOOP 0x1 /* Nothing. */#define NLMSG_ERROR 0x2 /* Error */#define NLMSG_DONE 0x3 /* End of a dump */#define NLMSG_OVERRUN 0x4 /* Data lost */
nlmsg_flags:附加在消息上的额外说明信息
nlmsg_seq 和 nlmsg_pid:用于应用追踪消息,前者表示顺序号,后者为消息来源进程 ID
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
举例
#include <linux/types.h>#include <linux/netlink.h>#define NL_IMP2 31#define IMP2_U_PID 0 //消息类型static int skfd;skfd = socket(PF_NETLINK, SOCK_RAW, NL_IMP2);if(skfd < 0){ printf("can not create a netlink socket\n"); exit(0);}struct sockaddr_nl local;memset(&local, 0, sizeof(local));local.nl_family = AF_NETLINK;local.nl_pid = 0; //向内核发送local.nl_groups = 0;if(bind(skfd, (struct sockaddr*)&local, sizeof(local)) != 0){ printf("bind() error\n"); return -1;}struct nlmsghdr hdr;memset(&hdr, 0, sizeof(hdr));hdr.nlmsg_len = NLMSG_LENGTH(0); //没有多余的数据hdr.nlmsg_flags = 0;hdr.nlmsg_type = NL_T_XX; //自定义消息类型hdr.nlmsg_pid = getpid(); //发送者的PIDsendto(skfd, &hdr, hdr.nlmsg_len, 0, (struct sockaddr*)&local, sizeof(local));
//接收typedef struct{ struct nlmsghdr hdr; struct packet_info icmp_info;}info;while(1){ len = sizeof(struct sockaddr_nl); rcvlen = recvfrom(skfd, &info, sizeof(info), 0, (struct sockaddr*)&local, &len);}
内核空间
struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));
unit:netlink协议类型
input:当有消息到达,会被引用
sk:和返回值一致
在input中,你可以直接处理收到的数据,也可以不处理,在大量数据传输的情况下,在input中处理是不明智的,正确的方式应该是建立一个内核线程专门接收数据,没有数据的时候该内核线程睡眠,一旦有了数据,input回调函数唤醒这个内核线程就是了
内核空间发送数据使用独立创建的sk_buff缓冲区
#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
NLMSG_ALIGN(len):得到不小于len且字节对齐的最小数值
NLMSG_LENGTH(len):计算数据部分长度为len时实际的消息长度
NLMSG_SPACE(len):返回不小于NLMSG_LENGTH(len)且字节对齐的最小数值
#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
取得消息的数据部分首地址
#define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb))NETLINK_CB(skb).pid = 0;NETLINK_CB(skb).dst_pid = 0;NETLINK_CB(skb).dst_group = 1;
pid:发送者进程ID,对于内核,它为0
dst_pid:接收者进程ID,如果目标为组或内核,它为0
dst_group:目标组地址,如果目标为某一进程或内核,它为0
netlink_unicast()发布单播消息
int netlink_unicast(struct sock *sk, struct sk_buff *skb, u32 pid, int nonblock);
pid:接收消息进程的pid
nonblock:该函数是否为非阻塞。如果为1,该函数将在没有接收缓存可利用时立即返回,而如果为0,该函数在没有接收缓存可利用时睡眠
void netlink_broadcast(struct sock *sk, struct sk_buff *skb, u32 pid, u32 group, int allocation);
group:接收消息的多播组。如果发送给多个多播组,就把该参数设置为多个多播组组ID的位或
allocation:GFP_ATOMIC用于原子的上下文(即不可以睡眠);GFP_KERNEL用于非原子上下文
#define NLMSG_PUT(skb, pid, seq, type, len)\({ if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) goto nlmsg_failure; __nlmsg_put(skb, pid, seq, type, len); })static __inline__ struct nlmsghdr *__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len){ struct nlmsghdr *nlh; int size = NLMSG_LENGTH(len); nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size)); nlh->nlmsg_type = type; nlh->nlmsg_len = size; nlh->nlmsg_flags = 0; nlh->nlmsg_pid = pid; nlh->nlmsg_seq = seq; return nlh;}
程序中应该定义nlmsg_failure标签
举例
#include <linux/netfilter_ipv4.h> #include <linux/netlink.h>#include <net/sock.h>nlfd = netlink_kernel_create(NL_IMP2, kernel_receive);if(!nlfd){ printk("can not create a netlink socket/n"); return -1;}static void kernel_receive(struct sock *sk, int len){ do { struct sk_buff *skb; while((skb = skb_dequeue(&sk->receive_queue)) != NULL) { struct nlmsghdr *nlh = NULL; if(skb->len >= sizeof(struct nlmsghdr) { nlh = (struct nlmsghdr *)skb->data; if((nlh->nlmsg_len >= sizeof(struct nlmsghdr)) && (skb->len >= nlh->nlmsg_len)) { //自定义消息 if(nlh->nlmsg_type == IMP2_U_PID) { ; } //socket关闭 else if(nlh->nlmsg_type == IMP2_CLOSE) { ; } } } } kfree_skb(skb); }while(nlfd && nlfd->receive_queue.qlen);}if(nlfd){ sock_release(nlfd->socket);}
//发送struct sk_buff *skb;struct nlmsghdr *nlh;struct packet_info *packet;/*计算消息总长*/size = NLMSG_SPACE(sizeof(*info));/*分配一个新的套接字缓存*/skb = alloc_skb(size, GFP_ATOMIC);/*初始化一个netlink消息首部*/nlh = NLMSG_PUT(skb, 0, 0, NL_T_XX, size-sizeof(*nlh));nlh->nlmsg_len = size;/*跳过消息首部,指向数据区*/packet = NLMSG_DATA(nlh);/*初始化数据区*/memset(packet, 0, sizeof(struct packet_info));/*填充待发送的数据*/packet->src = info->src;packet->dest = info->dest;/*设置控制字段*/NETLINK_CB(skb).dst_groups = 0;/*发送数据到目的pid*/ret = netlink_unicast(nlfd, skb, pid, MSG_DONTWAIT);
2.6内核netlink
从2.6.24开始,linux内部对netlink的实现机制和调用接口进行了很大的调整,特别是函数 netlink_kernel_create(),最新的参数有6个之多
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);
net:使用&init_net,定义在linux/net/core/net_namespace.c 中,此外在linux/include/net/net_namespace.h中也有外部定义,直接作为参数使用即可
unit:同上
input:同上,但不需要自己调用调度的方法,让内核进程阻塞以便等待消息到来了
module:THIS_MODULE,定义在module.h,表示当前模块
- netlink
- netlink
- netlink
- netlink
- netlink
- netlink
- netlink
- netlink
- netlink
- netlink
- Netlink
- netlink
- netlink (转)
- NetLink socket
- NETLINK usage
- netlink wiki
- hotplug --- netlink
- Netlink Socket
- C#对txt的操作
- 排序问题-冒泡排序
- 真实感球绘制
- 安装完ubunut14.04后要做的14件事情
- Quartz之Cron表达式详解
- netlink
- oracle学习 第一章 简单的查询语句 ——02
- CSS3_边框
- OpenGL 基础图形绘制与投影变换
- 后缀自动机 小结
- 分享DCT,DST,Walsh,Hadamard,Haar和Slant图像处理程序
- Android学习中遇到的坑
- Maven常用仓库地址以及手动添加jar包到仓库
- Kafka源码分析之RecordAccumulator