forked from mirrors/linux
		
	tools/bpf: move bpf/lib netlink related functions into a new file
There are no functionality change for this patch. In the subsequent patches, more netlink related library functions will be added and a separate file is better than cluttering bpf.c. Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
		
							parent
							
								
									52b7b7843d
								
							
						
					
					
						commit
						f7010770fb
					
				
					 3 changed files with 166 additions and 130 deletions
				
			
		| 
						 | 
					@ -1 +1 @@
 | 
				
			||||||
libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o
 | 
					libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o netlink.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,16 +28,8 @@
 | 
				
			||||||
#include <linux/bpf.h>
 | 
					#include <linux/bpf.h>
 | 
				
			||||||
#include "bpf.h"
 | 
					#include "bpf.h"
 | 
				
			||||||
#include "libbpf.h"
 | 
					#include "libbpf.h"
 | 
				
			||||||
#include "nlattr.h"
 | 
					 | 
				
			||||||
#include <linux/rtnetlink.h>
 | 
					 | 
				
			||||||
#include <linux/if_link.h>
 | 
					 | 
				
			||||||
#include <sys/socket.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef SOL_NETLINK
 | 
					 | 
				
			||||||
#define SOL_NETLINK 270
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * When building perf, unistd.h is overridden. __NR_bpf is
 | 
					 * When building perf, unistd.h is overridden. __NR_bpf is
 | 
				
			||||||
 * required to be defined explicitly.
 | 
					 * required to be defined explicitly.
 | 
				
			||||||
| 
						 | 
					@ -499,127 +491,6 @@ int bpf_raw_tracepoint_open(const char *name, int prog_fd)
 | 
				
			||||||
	return sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr));
 | 
						return sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct sockaddr_nl sa;
 | 
					 | 
				
			||||||
	int sock, seq = 0, len, ret = -1;
 | 
					 | 
				
			||||||
	char buf[4096];
 | 
					 | 
				
			||||||
	struct nlattr *nla, *nla_xdp;
 | 
					 | 
				
			||||||
	struct {
 | 
					 | 
				
			||||||
		struct nlmsghdr  nh;
 | 
					 | 
				
			||||||
		struct ifinfomsg ifinfo;
 | 
					 | 
				
			||||||
		char             attrbuf[64];
 | 
					 | 
				
			||||||
	} req;
 | 
					 | 
				
			||||||
	struct nlmsghdr *nh;
 | 
					 | 
				
			||||||
	struct nlmsgerr *err;
 | 
					 | 
				
			||||||
	socklen_t addrlen;
 | 
					 | 
				
			||||||
	int one = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&sa, 0, sizeof(sa));
 | 
					 | 
				
			||||||
	sa.nl_family = AF_NETLINK;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
 | 
					 | 
				
			||||||
	if (sock < 0) {
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
 | 
					 | 
				
			||||||
		       &one, sizeof(one)) < 0) {
 | 
					 | 
				
			||||||
		fprintf(stderr, "Netlink error reporting not supported\n");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
 | 
					 | 
				
			||||||
		ret = -errno;
 | 
					 | 
				
			||||||
		goto cleanup;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	addrlen = sizeof(sa);
 | 
					 | 
				
			||||||
	if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
 | 
					 | 
				
			||||||
		ret = -errno;
 | 
					 | 
				
			||||||
		goto cleanup;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (addrlen != sizeof(sa)) {
 | 
					 | 
				
			||||||
		ret = -LIBBPF_ERRNO__INTERNAL;
 | 
					 | 
				
			||||||
		goto cleanup;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&req, 0, sizeof(req));
 | 
					 | 
				
			||||||
	req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
 | 
					 | 
				
			||||||
	req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
 | 
					 | 
				
			||||||
	req.nh.nlmsg_type = RTM_SETLINK;
 | 
					 | 
				
			||||||
	req.nh.nlmsg_pid = 0;
 | 
					 | 
				
			||||||
	req.nh.nlmsg_seq = ++seq;
 | 
					 | 
				
			||||||
	req.ifinfo.ifi_family = AF_UNSPEC;
 | 
					 | 
				
			||||||
	req.ifinfo.ifi_index = ifindex;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* started nested attribute for XDP */
 | 
					 | 
				
			||||||
	nla = (struct nlattr *)(((char *)&req)
 | 
					 | 
				
			||||||
				+ NLMSG_ALIGN(req.nh.nlmsg_len));
 | 
					 | 
				
			||||||
	nla->nla_type = NLA_F_NESTED | IFLA_XDP;
 | 
					 | 
				
			||||||
	nla->nla_len = NLA_HDRLEN;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* add XDP fd */
 | 
					 | 
				
			||||||
	nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
 | 
					 | 
				
			||||||
	nla_xdp->nla_type = IFLA_XDP_FD;
 | 
					 | 
				
			||||||
	nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
 | 
					 | 
				
			||||||
	memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
 | 
					 | 
				
			||||||
	nla->nla_len += nla_xdp->nla_len;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* if user passed in any flags, add those too */
 | 
					 | 
				
			||||||
	if (flags) {
 | 
					 | 
				
			||||||
		nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
 | 
					 | 
				
			||||||
		nla_xdp->nla_type = IFLA_XDP_FLAGS;
 | 
					 | 
				
			||||||
		nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
 | 
					 | 
				
			||||||
		memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
 | 
					 | 
				
			||||||
		nla->nla_len += nla_xdp->nla_len;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
 | 
					 | 
				
			||||||
		ret = -errno;
 | 
					 | 
				
			||||||
		goto cleanup;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	len = recv(sock, buf, sizeof(buf), 0);
 | 
					 | 
				
			||||||
	if (len < 0) {
 | 
					 | 
				
			||||||
		ret = -errno;
 | 
					 | 
				
			||||||
		goto cleanup;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
 | 
					 | 
				
			||||||
	     nh = NLMSG_NEXT(nh, len)) {
 | 
					 | 
				
			||||||
		if (nh->nlmsg_pid != sa.nl_pid) {
 | 
					 | 
				
			||||||
			ret = -LIBBPF_ERRNO__WRNGPID;
 | 
					 | 
				
			||||||
			goto cleanup;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (nh->nlmsg_seq != seq) {
 | 
					 | 
				
			||||||
			ret = -LIBBPF_ERRNO__INVSEQ;
 | 
					 | 
				
			||||||
			goto cleanup;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		switch (nh->nlmsg_type) {
 | 
					 | 
				
			||||||
		case NLMSG_ERROR:
 | 
					 | 
				
			||||||
			err = (struct nlmsgerr *)NLMSG_DATA(nh);
 | 
					 | 
				
			||||||
			if (!err->error)
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			ret = err->error;
 | 
					 | 
				
			||||||
			nla_dump_errormsg(nh);
 | 
					 | 
				
			||||||
			goto cleanup;
 | 
					 | 
				
			||||||
		case NLMSG_DONE:
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cleanup:
 | 
					 | 
				
			||||||
	close(sock);
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size,
 | 
					int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size,
 | 
				
			||||||
		 bool do_log)
 | 
							 bool do_log)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										165
									
								
								tools/lib/bpf/netlink.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								tools/lib/bpf/netlink.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,165 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: LGPL-2.1
 | 
				
			||||||
 | 
					/* Copyright (c) 2018 Facebook */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <memory.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <linux/bpf.h>
 | 
				
			||||||
 | 
					#include <linux/rtnetlink.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "bpf.h"
 | 
				
			||||||
 | 
					#include "libbpf.h"
 | 
				
			||||||
 | 
					#include "nlattr.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef SOL_NETLINK
 | 
				
			||||||
 | 
					#define SOL_NETLINK 270
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bpf_netlink_open(__u32 *nl_pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sockaddr_nl sa;
 | 
				
			||||||
 | 
						socklen_t addrlen;
 | 
				
			||||||
 | 
						int one = 1, ret;
 | 
				
			||||||
 | 
						int sock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&sa, 0, sizeof(sa));
 | 
				
			||||||
 | 
						sa.nl_family = AF_NETLINK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
 | 
				
			||||||
 | 
						if (sock < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
 | 
				
			||||||
 | 
							       &one, sizeof(one)) < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "Netlink error reporting not supported\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
 | 
				
			||||||
 | 
							ret = -errno;
 | 
				
			||||||
 | 
							goto cleanup;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addrlen = sizeof(sa);
 | 
				
			||||||
 | 
						if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
 | 
				
			||||||
 | 
							ret = -errno;
 | 
				
			||||||
 | 
							goto cleanup;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (addrlen != sizeof(sa)) {
 | 
				
			||||||
 | 
							ret = -LIBBPF_ERRNO__INTERNAL;
 | 
				
			||||||
 | 
							goto cleanup;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*nl_pid = sa.nl_pid;
 | 
				
			||||||
 | 
						return sock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cleanup:
 | 
				
			||||||
 | 
						close(sock);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nlmsgerr *err;
 | 
				
			||||||
 | 
						struct nlmsghdr *nh;
 | 
				
			||||||
 | 
						char buf[4096];
 | 
				
			||||||
 | 
						int len, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							len = recv(sock, buf, sizeof(buf), 0);
 | 
				
			||||||
 | 
							if (len < 0) {
 | 
				
			||||||
 | 
								ret = -errno;
 | 
				
			||||||
 | 
								goto done;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
 | 
				
			||||||
 | 
							     nh = NLMSG_NEXT(nh, len)) {
 | 
				
			||||||
 | 
								if (nh->nlmsg_pid != nl_pid) {
 | 
				
			||||||
 | 
									ret = -LIBBPF_ERRNO__WRNGPID;
 | 
				
			||||||
 | 
									goto done;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (nh->nlmsg_seq != seq) {
 | 
				
			||||||
 | 
									ret = -LIBBPF_ERRNO__INVSEQ;
 | 
				
			||||||
 | 
									goto done;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								switch (nh->nlmsg_type) {
 | 
				
			||||||
 | 
								case NLMSG_ERROR:
 | 
				
			||||||
 | 
									err = (struct nlmsgerr *)NLMSG_DATA(nh);
 | 
				
			||||||
 | 
									if (!err->error)
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									ret = err->error;
 | 
				
			||||||
 | 
									nla_dump_errormsg(nh);
 | 
				
			||||||
 | 
									goto done;
 | 
				
			||||||
 | 
								case NLMSG_DONE:
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = 0;
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int sock, seq = 0, ret;
 | 
				
			||||||
 | 
						struct nlattr *nla, *nla_xdp;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct nlmsghdr  nh;
 | 
				
			||||||
 | 
							struct ifinfomsg ifinfo;
 | 
				
			||||||
 | 
							char             attrbuf[64];
 | 
				
			||||||
 | 
						} req;
 | 
				
			||||||
 | 
						__u32 nl_pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sock = bpf_netlink_open(&nl_pid);
 | 
				
			||||||
 | 
						if (sock < 0)
 | 
				
			||||||
 | 
							return sock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&req, 0, sizeof(req));
 | 
				
			||||||
 | 
						req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
 | 
				
			||||||
 | 
						req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
 | 
				
			||||||
 | 
						req.nh.nlmsg_type = RTM_SETLINK;
 | 
				
			||||||
 | 
						req.nh.nlmsg_pid = 0;
 | 
				
			||||||
 | 
						req.nh.nlmsg_seq = ++seq;
 | 
				
			||||||
 | 
						req.ifinfo.ifi_family = AF_UNSPEC;
 | 
				
			||||||
 | 
						req.ifinfo.ifi_index = ifindex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* started nested attribute for XDP */
 | 
				
			||||||
 | 
						nla = (struct nlattr *)(((char *)&req)
 | 
				
			||||||
 | 
									+ NLMSG_ALIGN(req.nh.nlmsg_len));
 | 
				
			||||||
 | 
						nla->nla_type = NLA_F_NESTED | IFLA_XDP;
 | 
				
			||||||
 | 
						nla->nla_len = NLA_HDRLEN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* add XDP fd */
 | 
				
			||||||
 | 
						nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
 | 
				
			||||||
 | 
						nla_xdp->nla_type = IFLA_XDP_FD;
 | 
				
			||||||
 | 
						nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
 | 
				
			||||||
 | 
						memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
 | 
				
			||||||
 | 
						nla->nla_len += nla_xdp->nla_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* if user passed in any flags, add those too */
 | 
				
			||||||
 | 
						if (flags) {
 | 
				
			||||||
 | 
							nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
 | 
				
			||||||
 | 
							nla_xdp->nla_type = IFLA_XDP_FLAGS;
 | 
				
			||||||
 | 
							nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
 | 
				
			||||||
 | 
							memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
 | 
				
			||||||
 | 
							nla->nla_len += nla_xdp->nla_len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
 | 
				
			||||||
 | 
							ret = -errno;
 | 
				
			||||||
 | 
							goto cleanup;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = bpf_netlink_recv(sock, nl_pid, seq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cleanup:
 | 
				
			||||||
 | 
						close(sock);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in a new issue