numactl:NETLINK示例源码
Posted rtoax
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了numactl:NETLINK示例源码相关的知识,希望对你有一定的参考价值。
目录
什么是 netlink
linux 内核一直存在的一个严重问题就是内核态和用户态的交互的问题,对于这个问题内核大佬们一直在研究各种方法,想让内核和用户态交互能够安全高效的进行。如系统调用,proc,sysfs等内存文件系统,但是这些方式一般都比较简单,只能在用户空间轮询访问内核的变化,内核的变化无法主动的推送出来。
而 netlink 的出现比较好的解决了这个问题,而且 netlink 还有以下一些优势:
-
可以直接使用 socket 套接字的 API 进行内核和用户态的通信,开发使用上相对简单了很多。
-
利用内核协议栈有了缓冲队列,是一种异步通信机制。
-
可以是内核和用户态的双向通信,内核可以主动向用户态进程发送消息。这个是以往通信方式不具备的。
-
针对同一个协议类型的所有用户进程,内核可以广播消息给所有的进程,也可以指定进程 pid 进行消息发送。
目前 netlink 的这种机制被广泛使用在各种场景中,在 Linux 内核中使用 netlink 进行应用与内核通信的应用很多;
包括:
- 路由 daemon(NETLINK_ROUTE),
- 用户态 socket 协议(NETLINK_USERSOCK),
- 防火墙(NETLINK_FIREWALL),
- netfilter 子系统(NETLINK_NETFILTER),
- 内核事件向用户态通知(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示例源码的主要内容,如果未能解决你的问题,请参考以下文章