本文主要目的是初步认识netlink,并用尽量少的API实现了一个R3-R0通信的demo
概述
$ man 7 netlink
NAME top
netlink - communication between kernel and user space (AF_NETLINK)
SYNOPSIS top
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
netlink_socket = socket(AF_NETLINK, socket_type, netlink_family);
DESCRIPTION top
Netlink is used to transfer information between the kernel and user-
space processes.
...
- R0和R3之间通讯的机制
- R3程序通过socket使用
基本使用
用户态 (Ring3)
API 列表
struct nlmsghdr
struct sockaddr_nl
NLMSG_DATA
socket
bind
sendto
recvfrom
API 细节
创建AF_NETLINK socket
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
netlink_socket = socket(AF_NETLINK, socket_type, netlink_family);
socket_type:
Both SOCK_RAW and SOCK_DGRAM are valid values for socket_type.
However, the netlink protocol does not distinguish between datagram and raw sockets.
netlink_family:
NETLINK_GENERIC
...
NETLINK_TEST (self-defined: 22~31)
/* netlink_family共32个,0~21由系统占用,自定义的范围在22~31 */
Netlink消息头
struct nlmsghdr {
__u32 nlmsg_len; /* Length of message including header */
__u16 nlmsg_type; /* Type of message content */
__u16 nlmsg_flags; /* Additional flags */
__u32 nlmsg_seq; /* Sequence number */
__u32 nlmsg_pid; /* Sender port ID */
};
Netlink通信地址格式
struct sockaddr_nl {
sa_family_t nl_family; /* AF_NETLINK */
unsigned short nl_pad; /* Zero */
pid_t nl_pid; /* Port ID */
__u32 nl_groups; /* Multicast groups mask */
};
通信相关API
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
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);
数据处理相关API
int NLMSG_SPACE(size_t len);
Return the number of bytes that a netlink message with payload of len would occupy.
void *NLMSG_DATA(struct nlmsghdr *nlh);
Return a pointer to the payload associated with the passed nlmsghdr.
内核模块 ( Ring0 )
API 列表
struct netlink_kernel_cfg
struct sk_buff
struct nlmsghdr
netlink_kernel_create
netlink_kernel_release
nlmsg_new
nlmsg_put
nlmsg_data
netlink_unicast
API 细节
用于配置回调函数
struct netlink_kernel_cfg {
unsigned int groups;
unsigned int flags;
void (*input)(struct sk_buff *skb);
struct mutex *cb_mutex;
int (*bind)(struct net *net, int group);
void (*unbind)(struct net *net, int group);
bool (*compare)(struct net *net, struct sock *sk);
};
input:
callbacks for receive and send netlink messages
创建和销毁netlink_socket
static inline struct sock *
netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)
void netlink_kernel_release(struct sock *sk)
创建netlink message
/**
* nlmsg_new - Allocate a new netlink message
* @payload: size of the message payload
* @flags: the type of memory to allocate.
*
* Use NLMSG_DEFAULT_SIZE if the size of the payload isn't known
* and a good default is needed.
*/
static inline struct sk_buff *nlmsg_new(size_t payload, gfp_t flags)
将netlink message添加的 skb
/**
* nlmsg_put - Add a new netlink message to an skb
* @skb: socket buffer to store message in
* @portid: netlink PORTID of requesting application
* @seq: sequence number of message
* @type: message type
* @payload: length of message payload
* @flags: message flags
*
* Returns NULL if the tailroom of the skb is insufficient to store
* the message header and payload.
*/
static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int payload, int flags)
剔除nlmsg header获取message部分指针
/**
* nlmsg_data - head of message payload
* @nlh: netlink message header
*/
static inline void *nlmsg_data(const struct nlmsghdr *nlh)
通过unicast发送到user 进程
int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 portid, int nonblock)
Demo
git clone https://github.com/invincible1900/linux-kernel-study.git
cd linux-kernel-study/netlink/netlink/demo1/kernel && make
insmod nl.ko
cd ../user && make
./nl
dmesg |tail
rmmod nl
cd ../../../../../ && rm -r linux-kernel-study
参考
man 7 netlink
man 3 netlink