mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Introduce a sample program to demonstrate the control and data plane split. For the control plane part a new program called xdpsock_ctrl_proc is introduced. For the data plane part, some code was added to xdpsock_user.c to act as the data plane entity. Application xdpsock_ctrl_proc works as control entity with sudo privileges (CAP_SYS_ADMIN and CAP_NET_ADMIN are sufficient) and the extended xdpsock as data plane entity with CAP_NET_RAW capability only. Usage example: sudo ./samples/bpf/xdpsock_ctrl_proc -i <interface> sudo ./samples/bpf/xdpsock -i <interface> -q <queue_id> -n <interval> -N -l -R Signed-off-by: Mariusz Dudek <mariuszx.dudek@intel.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Magnus Karlsson <magnus.karlsson@intel.com> Link: https://lore.kernel.org/bpf/20201203090546.11976-3-mariuszx.dudek@intel.com
		
			
				
	
	
		
			187 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
/* Copyright(c) 2017 - 2018 Intel Corporation. */
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
#include <getopt.h>
 | 
						|
#include <libgen.h>
 | 
						|
#include <net/if.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <sys/socket.h>
 | 
						|
#include <sys/un.h>
 | 
						|
#include <unistd.h>
 | 
						|
 | 
						|
#include <bpf/bpf.h>
 | 
						|
#include <bpf/xsk.h>
 | 
						|
#include "xdpsock.h"
 | 
						|
 | 
						|
static const char *opt_if = "";
 | 
						|
 | 
						|
static struct option long_options[] = {
 | 
						|
	{"interface", required_argument, 0, 'i'},
 | 
						|
	{0, 0, 0, 0}
 | 
						|
};
 | 
						|
 | 
						|
static void usage(const char *prog)
 | 
						|
{
 | 
						|
	const char *str =
 | 
						|
		"  Usage: %s [OPTIONS]\n"
 | 
						|
		"  Options:\n"
 | 
						|
		"  -i, --interface=n	Run on interface n\n"
 | 
						|
		"\n";
 | 
						|
	fprintf(stderr, "%s\n", str);
 | 
						|
 | 
						|
	exit(0);
 | 
						|
}
 | 
						|
 | 
						|
static void parse_command_line(int argc, char **argv)
 | 
						|
{
 | 
						|
	int option_index, c;
 | 
						|
 | 
						|
	opterr = 0;
 | 
						|
 | 
						|
	for (;;) {
 | 
						|
		c = getopt_long(argc, argv, "i:",
 | 
						|
				long_options, &option_index);
 | 
						|
		if (c == -1)
 | 
						|
			break;
 | 
						|
 | 
						|
		switch (c) {
 | 
						|
		case 'i':
 | 
						|
			opt_if = optarg;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			usage(basename(argv[0]));
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int send_xsks_map_fd(int sock, int fd)
 | 
						|
{
 | 
						|
	char cmsgbuf[CMSG_SPACE(sizeof(int))];
 | 
						|
	struct msghdr msg;
 | 
						|
	struct iovec iov;
 | 
						|
	int value = 0;
 | 
						|
 | 
						|
	if (fd == -1) {
 | 
						|
		fprintf(stderr, "Incorrect fd = %d\n", fd);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
	iov.iov_base = &value;
 | 
						|
	iov.iov_len = sizeof(int);
 | 
						|
 | 
						|
	msg.msg_name = NULL;
 | 
						|
	msg.msg_namelen = 0;
 | 
						|
	msg.msg_iov = &iov;
 | 
						|
	msg.msg_iovlen = 1;
 | 
						|
	msg.msg_flags = 0;
 | 
						|
	msg.msg_control = cmsgbuf;
 | 
						|
	msg.msg_controllen = CMSG_LEN(sizeof(int));
 | 
						|
 | 
						|
	struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
 | 
						|
 | 
						|
	cmsg->cmsg_level = SOL_SOCKET;
 | 
						|
	cmsg->cmsg_type = SCM_RIGHTS;
 | 
						|
	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
 | 
						|
 | 
						|
	*(int *)CMSG_DATA(cmsg) = fd;
 | 
						|
	int ret = sendmsg(sock, &msg, 0);
 | 
						|
 | 
						|
	if (ret == -1) {
 | 
						|
		fprintf(stderr, "Sendmsg failed with %s", strerror(errno));
 | 
						|
		return -errno;
 | 
						|
	}
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
main(int argc, char **argv)
 | 
						|
{
 | 
						|
	struct sockaddr_un server;
 | 
						|
	int listening = 1;
 | 
						|
	int rval, msgsock;
 | 
						|
	int ifindex = 0;
 | 
						|
	int flag = 1;
 | 
						|
	int cmd = 0;
 | 
						|
	int sock;
 | 
						|
	int err;
 | 
						|
	int xsks_map_fd;
 | 
						|
 | 
						|
	parse_command_line(argc, argv);
 | 
						|
 | 
						|
	ifindex = if_nametoindex(opt_if);
 | 
						|
	if (ifindex == 0) {
 | 
						|
		fprintf(stderr, "Unable to get ifindex for Interface %s. Reason:%s",
 | 
						|
			opt_if, strerror(errno));
 | 
						|
		return -errno;
 | 
						|
	}
 | 
						|
 | 
						|
	sock = socket(AF_UNIX, SOCK_STREAM, 0);
 | 
						|
	if (sock < 0) {
 | 
						|
		fprintf(stderr, "Opening socket stream failed: %s", strerror(errno));
 | 
						|
		return -errno;
 | 
						|
	}
 | 
						|
 | 
						|
	server.sun_family = AF_UNIX;
 | 
						|
	strcpy(server.sun_path, SOCKET_NAME);
 | 
						|
 | 
						|
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int));
 | 
						|
 | 
						|
	if (bind(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_un))) {
 | 
						|
		fprintf(stderr, "Binding to socket stream failed: %s", strerror(errno));
 | 
						|
		return -errno;
 | 
						|
	}
 | 
						|
 | 
						|
	listen(sock, MAX_NUM_OF_CLIENTS);
 | 
						|
 | 
						|
	err = xsk_setup_xdp_prog(ifindex, &xsks_map_fd);
 | 
						|
	if (err) {
 | 
						|
		fprintf(stderr, "Setup of xdp program failed\n");
 | 
						|
		goto close_sock;
 | 
						|
	}
 | 
						|
 | 
						|
	while (listening) {
 | 
						|
		msgsock = accept(sock, 0, 0);
 | 
						|
		if (msgsock == -1) {
 | 
						|
			fprintf(stderr, "Error accepting connection: %s", strerror(errno));
 | 
						|
			err = -errno;
 | 
						|
			goto close_sock;
 | 
						|
		}
 | 
						|
		err = send_xsks_map_fd(msgsock, xsks_map_fd);
 | 
						|
		if (err <= 0) {
 | 
						|
			fprintf(stderr, "Error %d sending xsks_map_fd\n", err);
 | 
						|
			goto cleanup;
 | 
						|
		}
 | 
						|
		do {
 | 
						|
			rval = read(msgsock, &cmd, sizeof(int));
 | 
						|
			if (rval < 0) {
 | 
						|
				fprintf(stderr, "Error reading stream message");
 | 
						|
			} else {
 | 
						|
				if (cmd != CLOSE_CONN)
 | 
						|
					fprintf(stderr, "Recv unknown cmd = %d\n", cmd);
 | 
						|
				listening = 0;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		} while (rval > 0);
 | 
						|
	}
 | 
						|
	close(msgsock);
 | 
						|
	close(sock);
 | 
						|
	unlink(SOCKET_NAME);
 | 
						|
 | 
						|
	/* Unset fd for given ifindex */
 | 
						|
	err = bpf_set_link_xdp_fd(ifindex, -1, 0);
 | 
						|
	if (err) {
 | 
						|
		fprintf(stderr, "Error when unsetting bpf prog_fd for ifindex(%d)\n", ifindex);
 | 
						|
		return err;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
 | 
						|
cleanup:
 | 
						|
	close(msgsock);
 | 
						|
close_sock:
 | 
						|
	close(sock);
 | 
						|
	unlink(SOCKET_NAME);
 | 
						|
	return err;
 | 
						|
}
 |