187 lines · 3.7 KB · C
RawDownload
// 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;} intmain(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;}