numactl:NETLINK示例源码

Posted rtoax

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了numactl:NETLINK示例源码相关的知识,希望对你有一定的参考价值。

【转】内核通信之 Netlink 源码分析和实例分析

目录

rtnetlink.h

rtnetlink.c


什么是 netlink

linux 内核一直存在的一个严重问题就是内核态和用户态的交互的问题,对于这个问题内核大佬们一直在研究各种方法,想让内核和用户态交互能够安全高效的进行。如系统调用,proc,sysfs等内存文件系统,但是这些方式一般都比较简单,只能在用户空间轮询访问内核的变化,内核的变化无法主动的推送出来。

而 netlink 的出现比较好的解决了这个问题,而且 netlink 还有以下一些优势:

  1. 可以直接使用 socket 套接字的 API 进行内核和用户态的通信,开发使用上相对简单了很多。

  2. 利用内核协议栈有了缓冲队列,是一种异步通信机制。

  3. 可以是内核和用户态的双向通信,内核可以主动向用户态进程发送消息。这个是以往通信方式不具备的。

  4. 针对同一个协议类型的所有用户进程,内核可以广播消息给所有的进程,也可以指定进程 pid 进行消息发送。

目前 netlink 的这种机制被广泛使用在各种场景中,在 Linux 内核中使用 netlink 进行应用与内核通信的应用很多;

包括:

  1. 路由 daemon(NETLINK_ROUTE),
  2. 用户态 socket 协议(NETLINK_USERSOCK),
  3. 防火墙(NETLINK_FIREWALL),
  4. netfilter 子系统(NETLINK_NETFILTER),
  5. 内核事件向用户态通知(NETLINK_KOBJECT_UEVENT)等。

具体支持的类型可以查看这个文件 include/uapi/linux/netlink.h

rtnetlink.h

hidden int
rta_put_address(struct nlmsghdr *msg, int type, struct sockaddr *adr);
hidden struct rtattr *rta_get(struct nlmsghdr *m, struct rtattr *p, int offset);
hidden void *rta_put(struct nlmsghdr *m, int type, int len);
hidden int rtnetlink_request(struct nlmsghdr *msg, int buflen, struct sockaddr_nl *adr);

rtnetlink.c

/* Simple LPGLed rtnetlink library */
#include <sys/socket.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#define hidden __attribute__((visibility("hidden")))
#include "rtnetlink.h"

hidden void *rta_put(struct nlmsghdr *m, int type, int len)
{
	struct rtattr *rta = (void *)m + NLMSG_ALIGN(m->nlmsg_len);
	int rtalen = RTA_LENGTH(len);

	rta->rta_type = type;
	rta->rta_len = rtalen;
	m->nlmsg_len = NLMSG_ALIGN(m->nlmsg_len) + RTA_ALIGN(rtalen);
	return RTA_DATA(rta);
}

hidden struct rtattr *rta_get(struct nlmsghdr *m, struct rtattr *p, int offset)
{
	struct rtattr *rta;

	if (p) {
		rta = RTA_NEXT(p, m->nlmsg_len);
		if (!RTA_OK(rta, m->nlmsg_len))
			return NULL;
	} else {
		rta = (void *)m + NLMSG_ALIGN(offset);
	}
	return rta;
}

hidden int
rta_put_address(struct nlmsghdr *msg, int type, struct sockaddr *adr)
{
	switch (adr->sa_family) {
	case AF_INET: {
		struct in_addr *i = rta_put(msg, type, 4);
		*i = ((struct sockaddr_in *)adr)->sin_addr;
		break;
	}
	case AF_INET6: {
		struct in6_addr *i6 = rta_put(msg, type, 16);
		*i6 = ((struct sockaddr_in6 *)adr)->sin6_addr;
		break;
	}
	default:
		return -1;
	}
	return 0;
}

/* Assumes no truncation. Make the buffer large enough. */
hidden int
rtnetlink_request(struct nlmsghdr *msg, int buflen, struct sockaddr_nl *adr)
{
	int rsk;
	int n;
	int e;

	/* Use a private socket to avoid having to keep state
	   for a sequence number. */
	rsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (rsk < 0)
		return -1;
	n = sendto(rsk, msg, msg->nlmsg_len, 0, (struct sockaddr *)adr,
		   sizeof(struct sockaddr_nl));
	if (n >= 0) {
		socklen_t adrlen = sizeof(struct sockaddr_nl);
		n = recvfrom(rsk, msg, buflen, 0, (struct sockaddr *)adr,
			     &adrlen);
	}
	e = errno;
	close(rsk);
	errno = e;
	if (n < 0)
		return -1;
	/* Assume we only get a single reply back. This is (hopefully?)
	   safe because it's a single use socket. */
	if (msg->nlmsg_type == NLMSG_ERROR) {
		struct nlmsgerr *err = NLMSG_DATA(msg);
		errno = -err->error;
		return -1;
	}
	return 0;
}

 

以上是关于numactl:NETLINK示例源码的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Linux NETLINK 手册页提供 C++ 示例而不提供 C?

Linux用户与内核空间交互—netlink

Linux用户与内核空间交互—netlink

宋宝华:为什么numactl内存绑定对代码段不起作用

netlink与tcp_diag编程

如何使用netlink进行IPC?