Netlink双工通信

Netlink是Linux提供的一种全双工通信方式,用于在应用程序和内核之间建立连接并进行双工通信。Netlink 的接口分为 应用层接口 和 内核接口,我们需要在 应用程序实现策略,然后在 内核实现机制本文通过具体实例,介绍下Netlink的接口调用过程。

一、数据格式

Netlink 的基本数据单元是 消息,消息 = 消息头 + 有效载荷。其中,消息头 的数据结构如下:

有效载荷是指在 消息头 后面的数据,为真正的业务数据,可以为空,其数据格式由业务定义。 

二、应用层接口调用

Netlink 应用层基本的编程步骤如下:

1、使用 socket 声明套接字,参数定义如下:

  • domain:表示协议簇,在 netlink 中一般为 AF_NETLINK。
  • type:表示套接字类型,在 netlink 中一般为 SOCK_RAW。
  • protocol:表示协议类型,在 netlink 中可以是内核支持的协议,也可以是 自定义协议。
int socket(int domain, int type, int protocol);

2、使用 bind 绑定 本地地址 到套接字

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

//sockaddr_nl 是 netlink 使用的地址数据结构,与网络编程不同
struct sockaddr_nl {
     __kernel_sa_family_t    nl_family;  //一般为AF_NETLINK
     unsigned short          nl_pad;     //无需填充
     __u32                   nl_pid;     //与内核通信的进程的PID,0 则代表地址为内核
     __u32                   nl_groups;  //多播组号,netlink支持多播
};

3、构造和收发消息

Netlink 有 2 套收发消息的接口,分别是 sendto/recvfromsendmsg/recvmsg。

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);

三、内核接口

内核接口与应用层接口相似,其过程和使用的接口如下:

1、创建socket并注册回调

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);
};

/*
** 创建接口,其中,参数net 一般为 &init_net
*/
static inline struct sock *netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)

/*
** 释放接口
*/
void netlink_kernel_release(struct sock *sk);

2、构造和发送消息 

//sk_buff 为内核中 Netlink 使用的数据结构体,下面分别是分配、使用、释放的接口
static inline struct sk_buff *alloc_skb(unsigned int size, gfp_t priority)
static inline struct sk_buff *skb_get(struct sk_buff *skb)
void kfree_skb(struct sk_buff *skb);

//下面为构建消息内容的接口
static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int payload, int flags)

大概的调用方法为: 

//NLMSG_SPACE计算包括消息头在内的消息长度
size_t size = max(NLMSG_SPACE(message_size), (size_t)NLMSG_GOODSIZE);

//分配sk_buff内存
sk_buff * log_skb = alloc_skb(size, GFP_ATOMIC);

//构造消息结构体
nlmsghdr *nlh = nlmsg_put(log_skb, /*pid*/0, /*seq*/0, type,
		message_size, 0);

//将要发送的数据复制到消息结构体上
if(payload != NULL) {
	memcpy(nlmsg_data(nlh),  payload, size);
}

3、发送消息

发送消息有单播、广播两个接口,可以根据实际业务选择使用。

int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock);
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid, __u32 group, gfp_t allocation);

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值