Blame ip/iplink_xdp.c

Packit Service 3880ab
/*
Packit Service 3880ab
 * iplink_xdp.c XDP program loader
Packit Service 3880ab
 *
Packit Service 3880ab
 *              This program is free software; you can redistribute it and/or
Packit Service 3880ab
 *              modify it under the terms of the GNU General Public License
Packit Service 3880ab
 *              as published by the Free Software Foundation; either version
Packit Service 3880ab
 *              2 of the License, or (at your option) any later version.
Packit Service 3880ab
 *
Packit Service 3880ab
 * Authors:     Daniel Borkmann <daniel@iogearbox.net>
Packit Service 3880ab
 */
Packit Service 3880ab
Packit Service 3880ab
#include <stdio.h>
Packit Service 3880ab
#include <stdlib.h>
Packit Service 3880ab
Packit Service 3880ab
#include <linux/bpf.h>
Packit Service 3880ab
Packit Service 3880ab
#include "bpf_util.h"
Packit Service 3880ab
#include "utils.h"
Packit Service 3880ab
#include "ip_common.h"
Packit Service 3880ab
Packit Service 3880ab
extern int force;
Packit Service 3880ab
Packit Service 3880ab
struct xdp_req {
Packit Service 3880ab
	struct iplink_req *req;
Packit Service 3880ab
	__u32 flags;
Packit Service 3880ab
};
Packit Service 3880ab
Packit Service 3880ab
static void xdp_ebpf_cb(void *raw, int fd, const char *annotation)
Packit Service 3880ab
{
Packit Service 3880ab
	struct xdp_req *xdp = raw;
Packit Service 3880ab
	struct iplink_req *req = xdp->req;
Packit Service 3880ab
	struct rtattr *xdp_attr;
Packit Service 3880ab
Packit Service 3880ab
	xdp_attr = addattr_nest(&req->n, sizeof(*req), IFLA_XDP);
Packit Service 3880ab
	addattr32(&req->n, sizeof(*req), IFLA_XDP_FD, fd);
Packit Service 3880ab
	if (xdp->flags)
Packit Service 3880ab
		addattr32(&req->n, sizeof(*req), IFLA_XDP_FLAGS, xdp->flags);
Packit Service 3880ab
	addattr_nest_end(&req->n, xdp_attr);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static const struct bpf_cfg_ops bpf_cb_ops = {
Packit Service 3880ab
	.ebpf_cb = xdp_ebpf_cb,
Packit Service 3880ab
};
Packit Service 3880ab
Packit Service 3880ab
static int xdp_delete(struct xdp_req *xdp)
Packit Service 3880ab
{
Packit Service 3880ab
	xdp_ebpf_cb(xdp, -1, NULL);
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
int xdp_parse(int *argc, char ***argv, struct iplink_req *req,
Packit Service 3880ab
	      const char *ifname, bool generic, bool drv, bool offload)
Packit Service 3880ab
{
Packit Service 3880ab
	struct bpf_cfg_in cfg = {
Packit Service 3880ab
		.type = BPF_PROG_TYPE_XDP,
Packit Service 3880ab
		.argc = *argc,
Packit Service 3880ab
		.argv = *argv,
Packit Service 3880ab
	};
Packit Service 3880ab
	struct xdp_req xdp = {
Packit Service 3880ab
		.req = req,
Packit Service 3880ab
	};
Packit Service 3880ab
Packit Service 3880ab
	if (offload) {
Packit Service 3880ab
		int ifindex = ll_name_to_index(ifname);
Packit Service 3880ab
Packit Service 3880ab
		if (!ifindex)
Packit Service 3880ab
			incomplete_command();
Packit Service 3880ab
		cfg.ifindex = ifindex;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (!force)
Packit Service 3880ab
		xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST;
Packit Service 3880ab
	if (generic)
Packit Service 3880ab
		xdp.flags |= XDP_FLAGS_SKB_MODE;
Packit Service 3880ab
	if (drv)
Packit Service 3880ab
		xdp.flags |= XDP_FLAGS_DRV_MODE;
Packit Service 3880ab
	if (offload)
Packit Service 3880ab
		xdp.flags |= XDP_FLAGS_HW_MODE;
Packit Service 3880ab
Packit Service 3880ab
	if (*argc == 1) {
Packit Service 3880ab
		if (strcmp(**argv, "none") == 0 ||
Packit Service 3880ab
		    strcmp(**argv, "off") == 0)
Packit Service 3880ab
			return xdp_delete(&xdp;;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &xdp))
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	*argc = cfg.argc;
Packit Service 3880ab
	*argv = cfg.argv;
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void xdp_dump_json_one(struct rtattr *tb[IFLA_XDP_MAX + 1], __u32 attr,
Packit Service 3880ab
			      __u8 mode)
Packit Service 3880ab
{
Packit Service 3880ab
	if (!tb[attr])
Packit Service 3880ab
		return;
Packit Service 3880ab
Packit Service 3880ab
	open_json_object(NULL);
Packit Service 3880ab
	print_uint(PRINT_JSON, "mode", NULL, mode);
Packit Service 3880ab
	bpf_dump_prog_info(NULL, rta_getattr_u32(tb[attr]));
Packit Service 3880ab
	close_json_object();
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void xdp_dump_json(struct rtattr *tb[IFLA_XDP_MAX + 1])
Packit Service 3880ab
{
Packit Service 3880ab
	__u32 prog_id = 0;
Packit Service 3880ab
	__u8 mode;
Packit Service 3880ab
Packit Service 3880ab
	mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
Packit Service 3880ab
	if (tb[IFLA_XDP_PROG_ID])
Packit Service 3880ab
		prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
Packit Service 3880ab
Packit Service 3880ab
	open_json_object("xdp");
Packit Service 3880ab
	print_uint(PRINT_JSON, "mode", NULL, mode);
Packit Service 3880ab
	if (prog_id)
Packit Service 3880ab
		bpf_dump_prog_info(NULL, prog_id);
Packit Service 3880ab
Packit Service 3880ab
	open_json_array(PRINT_JSON, "attached");
Packit Service 3880ab
	if (tb[IFLA_XDP_SKB_PROG_ID] ||
Packit Service 3880ab
	    tb[IFLA_XDP_DRV_PROG_ID] ||
Packit Service 3880ab
	    tb[IFLA_XDP_HW_PROG_ID]) {
Packit Service 3880ab
		xdp_dump_json_one(tb, IFLA_XDP_SKB_PROG_ID, XDP_ATTACHED_SKB);
Packit Service 3880ab
		xdp_dump_json_one(tb, IFLA_XDP_DRV_PROG_ID, XDP_ATTACHED_DRV);
Packit Service 3880ab
		xdp_dump_json_one(tb, IFLA_XDP_HW_PROG_ID, XDP_ATTACHED_HW);
Packit Service 3880ab
	} else if (tb[IFLA_XDP_PROG_ID]) {
Packit Service 3880ab
		/* Older kernel - use IFLA_XDP_PROG_ID */
Packit Service 3880ab
		xdp_dump_json_one(tb, IFLA_XDP_PROG_ID, mode);
Packit Service 3880ab
	}
Packit Service 3880ab
	close_json_array(PRINT_JSON, NULL);
Packit Service 3880ab
Packit Service 3880ab
	close_json_object();
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void xdp_dump_prog_one(FILE *fp, struct rtattr *tb[IFLA_XDP_MAX + 1],
Packit Service 3880ab
			      __u32 attr, bool link, bool details,
Packit Service 3880ab
			      const char *pfx)
Packit Service 3880ab
{
Packit Service 3880ab
	__u32 prog_id;
Packit Service 3880ab
Packit Service 3880ab
	if (!tb[attr])
Packit Service 3880ab
		return;
Packit Service 3880ab
Packit Service 3880ab
	prog_id = rta_getattr_u32(tb[attr]);
Packit Service 3880ab
	if (!details) {
Packit Service 3880ab
		if (prog_id && !link && attr == IFLA_XDP_PROG_ID)
Packit Service 3880ab
			fprintf(fp, "/id:%u", prog_id);
Packit Service 3880ab
		return;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (prog_id) {
Packit Service 3880ab
		fprintf(fp, "%s    prog/xdp%s ", _SL_, pfx);
Packit Service 3880ab
		bpf_dump_prog_info(fp, prog_id);
Packit Service 3880ab
	}
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
void xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *tb[IFLA_XDP_MAX + 1];
Packit Service 3880ab
	__u8 mode;
Packit Service 3880ab
Packit Service 3880ab
	parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp);
Packit Service 3880ab
Packit Service 3880ab
	if (!tb[IFLA_XDP_ATTACHED])
Packit Service 3880ab
		return;
Packit Service 3880ab
Packit Service 3880ab
	mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
Packit Service 3880ab
	if (mode == XDP_ATTACHED_NONE)
Packit Service 3880ab
		return;
Packit Service 3880ab
	else if (is_json_context())
Packit Service 3880ab
		return details ? (void)0 : xdp_dump_json(tb);
Packit Service 3880ab
	else if (details && link)
Packit Service 3880ab
		/* don't print mode */;
Packit Service 3880ab
	else if (mode == XDP_ATTACHED_DRV)
Packit Service 3880ab
		fprintf(fp, "xdp");
Packit Service 3880ab
	else if (mode == XDP_ATTACHED_SKB)
Packit Service 3880ab
		fprintf(fp, "xdpgeneric");
Packit Service 3880ab
	else if (mode == XDP_ATTACHED_HW)
Packit Service 3880ab
		fprintf(fp, "xdpoffload");
Packit Service 3880ab
	else if (mode == XDP_ATTACHED_MULTI)
Packit Service 3880ab
		fprintf(fp, "xdpmulti");
Packit Service 3880ab
	else
Packit Service 3880ab
		fprintf(fp, "xdp[%u]", mode);
Packit Service 3880ab
Packit Service 3880ab
	xdp_dump_prog_one(fp, tb, IFLA_XDP_PROG_ID, link, details, "");
Packit Service 3880ab
Packit Service 3880ab
	if (mode == XDP_ATTACHED_MULTI) {
Packit Service 3880ab
		xdp_dump_prog_one(fp, tb, IFLA_XDP_SKB_PROG_ID, link, details,
Packit Service 3880ab
				  "generic");
Packit Service 3880ab
		xdp_dump_prog_one(fp, tb, IFLA_XDP_DRV_PROG_ID, link, details,
Packit Service 3880ab
				  "drv");
Packit Service 3880ab
		xdp_dump_prog_one(fp, tb, IFLA_XDP_HW_PROG_ID, link, details,
Packit Service 3880ab
				  "offload");
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (!details || !link)
Packit Service 3880ab
		fprintf(fp, " ");
Packit Service 3880ab
}