linux 内核中Netlink
目录
套接字Netlink地址 sockaddr_nl
协议簇
常使用的宏
内核常用的函数
创建流程
Netlink套接字
uevent内核事件
套接字监视接口
demo
Netlink套接字接口最初是Linux内核2.2引入的,作用用户空间进程与内核间通信方法。
相对于ioctl,sysfs,proc的优势
优势:
- IOCTL处理程序不能从内核向用户空间发送异步消息,而Netlink套接字则可以。
- 用户与内核间的通信方式,不需要轮询,用户空间应用程序打开套接字,调用recvmsg(),如果没有来自内核的消息,就进入阻塞状态。
- 内核可以主动向用户空间发送异步消息,而不需要用户空间来触发。
- 支持组播传输。
命令iproute2包含命令(ip tc ss lnstat bridge)主要使用netlink套接字从用户空间向内核空间发送请求并获得应答。
套接字Netlink地址 sockaddr_nl
struct sockaddr_nl {__kernel_sa_family_t nl_family; /* AF_NETLINK */unsigned short nl_pad; /* zero */__u32 nl_pid; /* port ID */__u32 nl_groups; /* multicast groups mask */
};
消息头
struct nlmsghdr {__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 port ID */
};
协议簇
#define NETLINK_ROUTE 0 /* Routing/device hook */
#define NETLINK_UNUSED 1 /* Unused number */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */
#define NETLINK_SOCK_DIAG 4 /* socket monitoring */
#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
#define NETLINK_XFRM 6 /* ipsec */
#define NETLINK_SELINUX 7 /* SELinux event notifications */
#define NETLINK_ISCSI 8 /* Open-iSCSI */
#define NETLINK_AUDIT 9 /* auditing */
#define NETLINK_FIB_LOOKUP 10
#define NETLINK_CONNECTOR 11
#define NETLINK_NETFILTER 12 /* netfilter subsystem */
#define NETLINK_IP6_FW 13
#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
#define NETLINK_GENERIC 16
/* leave room for NETLINK_DM (DM Events) */
#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
#define NETLINK_ECRYPTFS 19
#define NETLINK_RDMA 20
#define NETLINK_CRYPTO 21 /* Crypto layer */
#define NETLINK_SMC 22 /* SMC monitoring */
常使用的宏
#define NLMSG_ALIGNTO 4U
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \(nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \(nlh)->nlmsg_len <= (len))
#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
内核常用的函数
//内核创建socket
static inline struct sock * netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)//nlmsg_new - Allocate a new netlink message
static inline struct sk_buff *nlmsg_new(size_t payload, gfp_t flags)//Add a new netlink message to an skb
static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,int type, int payload, int flags)//单播
extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock);//多播
extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid,__u32 group, gfp_t allocation);
创建流程
Netlink套接字
在内核网络栈中,可以创建多种Netlink套接字,每种套接字处理不同类型消息。如NETLINK_ROUTE消息的套接字创建过程
static int __net_init rtnetlink_net_init(struct net *net)
{struct sock *sk;struct netlink_kernel_cfg cfg = {.groups = RTNLGRP_MAX,.input = rtnetlink_rcv,.cb_mutex = &rtnl_mutex,.flags = NL_CFG_F_NONROOT_RECV,.bind = rtnetlink_bind,};sk = netlink_kernel_create(net, NETLINK_ROUTE, &cfg);if (!sk)return -ENOMEM;net->rtnl = sk;return 0;
}
- 在netlink_kernel_create种第二个参数 NETLINK_ROUTE表示rtnetlink消息,此外还有NETLINK_XFRM表示IPsec子系统,NETLINK_AUDIT表示审计子系统。
- 成员input函数用于指定回调函数,rtnetlink_rcv用于接收用户空间的信息。
uevent内核事件
只需要从内核向用户发送数据即可,初始化为
static int uevent_net_init(struct net *net)
{struct uevent_sock *ue_sk;struct netlink_kernel_cfg cfg = {.groups = 1,.input = uevent_net_rcv,.flags = NL_CFG_F_NONROOT_RECV};ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL);if (!ue_sk)return -ENOMEM;ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, &cfg);if (!ue_sk->sk) {pr_err("kobject_uevent: unable to create netlink socket!\n");kfree(ue_sk);return -ENODEV;}
...
}
套接字监视接口
//支持SS 监视接口 NETLINK_SOCK_DIAG
static int __net_init diag_net_init(struct net *net)
{struct netlink_kernel_cfg cfg = {.groups = SKNLGRP_MAX,.input = sock_diag_rcv,.bind = sock_diag_bind,.flags = NL_CFG_F_NONROOT_RECV,};net->diag_nlsk = netlink_kernel_create(net, NETLINK_SOCK_DIAG, &cfg);return net->diag_nlsk == NULL ? -ENOMEM : 0;
}
demo
内核程序实例
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <net/sock.h>
#include <linux/netlink.h>#define NETLINK_USER 22
#define USER_MSG (NETLINK_USER + 1)
#define USER_PORT 50static struct sock *netlinkfd = NULL;int send_msg(int8_t *pbuf, uint16_t len)
{struct sk_buff *nl_skb;struct nlmsghdr *nlh;int ret;//创建sk_buffernl_skb = nlmsg_new(len, GFP_ATOMIC);if(!nl_skb){printk("nlmsg_new error\n");return -1;}//设置netlink头nlh = nlmsg_put(nl_skb, 0, 0, USER_MSG, len, 0);if(nlh == NULL){printk("netlink header error\n");nlmsg_free(nl_skb);return -1;}//拷贝数据memcpy(nlmsg_data(nlh), pbuf, len);//单播发送数据ret = netlink_unicast(netlinkfd, nl_skb, USER_PORT, MSG_DONTWAIT);return ret;
}//接收数据
static void recv_cb(struct sk_buff *skb)
{struct nlmsghdr *nlh = NULL;void *data = NULL;//打印接收数据的长度printk("recv_datalen:%u\n", skb->len);if(skb->len >= nlmsg_total_size(0)){nlh = nlmsg_hdr(skb);//宏 获取数据data = NLMSG_DATA(nlh);if(data){printk("kernel receive data: %s\n", (int8_t *)data);//将数据发送给用户send_msg(data, nlmsg_len(nlh));}}
} //cfg参数 注册了input
struct netlink_kernel_cfg cfg =
{.input = recv_cb,
};//初始化
static int __init netlink_init(void)
{//创建socketnetlinkfd = netlink_kernel_create(&init_net, USER_MSG, &cfg);if(!netlinkfd){printk(KERN_ERR "create a netlink socket error!\n");return -1;}printk("init netlink ok!\n");return 0;
}
//退出
static void __exit netlink_exit(void)
{sock_release(netlinkfd->sk_socket);printk(KERN_DEBUG "netlink exit\n!");
}module_init(netlink_init);
module_exit(netlink_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("wy");
MODULE_DESCRIPTION("netlink");
linux 内核中Netlink相关推荐
- Linux内核中锁机制之完成量、互斥量
在上一篇博文中笔者分析了关于信号量.读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题. 八.完成量 下面讨论完成量的内容,首先需明确完成量表示为一个执行单元需要等 ...
- 简单谈一点linux内核中套接字的bind机制--数据结构以及端口确定
众所周知,创建一个套接字可以bind到一个特定的ip地址和端口,实际上套接字这一概念代表了TCP/IP协议栈的应用层标识,协议栈中的应用层就是通过一个ip地址和一个端口号标识的,当然这仅仅是对于TCP ...
- Linux 内核中的 Device Mapper 机制
本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...
- 如何放出Linux内核中的链表大招
前言 上回,我们说到Linux内核中max()宏的终极奥义,Linux内核链表也不甘示弱,那么接下来,让我们看看Linux内核中的链表大招. 如何放出Linux内核中的链表大招 前言 一.链表简介 ( ...
- Linux内核中max()宏的奥妙何在?(一)
Linux内核中max()宏的奥妙何在?(一) 1.max()宏那点事 在Linux内核中,有这样四个比较大小的函数,如下: max(x,y) //两个数求最大值 min(x,y) //两个数求最小值 ...
- Linux内核中max()宏的奥妙何在?(二)——大神Linus对这个宏怎么看?
最新max()宏 上回,我们在<Linux内核中max()宏的奥妙何在?(一)>一文中说到,在3.18.34版Linux内核源码中的max()宏,采用了GCC的扩展特性,可以避免一些错误. ...
- Linux中文件描述符1,linux内核中的文件描述符(一)--基础知识简介
原标题:linux内核中的文件描述符(一)--基础知识简介 Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blo ...
- Linux 内核中的 GCC 特性(zz)
from:http://www.ibm.com/developerworks/cn/linux/l-gcc-hacks/ GCC 和 Linux 是出色的组合.尽管它们是独立的软件,但是 Linux ...
- 【Linux 内核】进程管理 ( Linux 内核中的进程状态 | TASK_RUNNING | TASK_INTERRUPTIBLE | __TASK_STOPPED | EXIT_ZOMBIE )
文章目录 一.Linux 内核中的进程状态 二.TASK_RUNNING 状态 三.TASK_RUNNING 状态 四.TASK_UNINTERRUPTIBLE 状态 五.__TASK_STOPPED ...
最新文章
- 电磁学讲义6:高斯定理计算电场
- 常用[js,css,jquery,html]
- webstorm 修改端口号
- 如何进行网站的安全测试
- CTFshow php特性 web110
- 测试MVC3时关于Model Builder语句的更改
- Cocos2d-x 3.x plist+png 做动画
- optee中断处理的介绍(概念篇)
- ES6_Promise
- 计算机网络网际协议实验报告,计算机网络课程网际协议IP地址实验报告.doc
- c语言 rgb颜色渐变_这种渐变噪点的质感,咋做的?
- user_agent
- 非极大值抑制(PyTorch-YOLOv3代码解析一)
- win7 虚拟wifi服务器,在win7系统下创建虚拟wifi的方法
- pattern.compile java_Java Pattern compile(String)用法及代码示例
- rbenv安装Ruby2.3.5报错BUILD FAILED (Ubuntu 18.04 using ruby-build 20191225-1-gbac1f1c) openssl
- 三、Python复习教程(重点)- 前端框架实战
- 128 黙齎 李貴 曷若親征
- Unity Google VR Cardboard 后台挂起时陀螺仪仍然占用问题解决
- gabor滤波器 opencv 实现