1c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann/*
2c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann * iplink_xdp.c XDP program loader
3c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann *
4c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann *              This program is free software; you can redistribute it and/or
5c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann *              modify it under the terms of the GNU General Public License
6c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann *              as published by the Free Software Foundation; either version
7c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann *              2 of the License, or (at your option) any later version.
8c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann *
9c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann * Authors:     Daniel Borkmann <daniel@iogearbox.net>
10c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann */
11c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
12c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann#include <stdio.h>
13c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann#include <stdlib.h>
14c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
15c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann#include <linux/bpf.h>
16c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
17bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann#include "json_print.h"
18c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann#include "xdp.h"
19c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann#include "bpf_util.h"
20c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
21c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmannextern int force;
22c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
23a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmannstruct xdp_req {
24a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	struct iplink_req *req;
25a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	__u32 flags;
26a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann};
27a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann
28c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmannstatic void xdp_ebpf_cb(void *raw, int fd, const char *annotation)
29c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann{
30a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	struct xdp_req *xdp = raw;
31a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	struct iplink_req *req = xdp->req;
32a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	struct rtattr *xdp_attr;
33c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
34a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	xdp_attr = addattr_nest(&req->n, sizeof(*req), IFLA_XDP);
35c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	addattr32(&req->n, sizeof(*req), IFLA_XDP_FD, fd);
36a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	if (xdp->flags)
37a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann		addattr32(&req->n, sizeof(*req), IFLA_XDP_FLAGS, xdp->flags);
38a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	addattr_nest_end(&req->n, xdp_attr);
39c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann}
40c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
41c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmannstatic const struct bpf_cfg_ops bpf_cb_ops = {
42c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	.ebpf_cb = xdp_ebpf_cb,
43c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann};
44c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
45a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmannstatic int xdp_delete(struct xdp_req *xdp)
46c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann{
47a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	xdp_ebpf_cb(xdp, -1, NULL);
48c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	return 0;
49c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann}
50c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
511468381415766001383aa332863601066b4427eaJakub Kicinskiint xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic,
521b5e809466376df1be0e9e7e5460605c974ad42bJakub Kicinski	      bool drv, bool offload)
53c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann{
54c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	struct bpf_cfg_in cfg = {
55c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann		.argc = *argc,
56c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann		.argv = *argv,
57c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	};
58a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	struct xdp_req xdp = {
59a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann		.req = req,
60a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	};
61a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann
62a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	if (!force)
63a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann		xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST;
64a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	if (generic)
65a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann		xdp.flags |= XDP_FLAGS_SKB_MODE;
661468381415766001383aa332863601066b4427eaJakub Kicinski	if (drv)
671468381415766001383aa332863601066b4427eaJakub Kicinski		xdp.flags |= XDP_FLAGS_DRV_MODE;
681b5e809466376df1be0e9e7e5460605c974ad42bJakub Kicinski	if (offload)
691b5e809466376df1be0e9e7e5460605c974ad42bJakub Kicinski		xdp.flags |= XDP_FLAGS_HW_MODE;
70c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
71c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	if (*argc == 1) {
72c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann		if (strcmp(**argv, "none") == 0 ||
73c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann		    strcmp(**argv, "off") == 0)
74a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann			return xdp_delete(&xdp);
75c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	}
76a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann
77a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann	if (bpf_parse_common(BPF_PROG_TYPE_XDP, &cfg, &bpf_cb_ops, &xdp))
78c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann		return -1;
79c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
80c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	*argc = cfg.argc;
81c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	*argv = cfg.argv;
82c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	return 0;
83c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann}
84c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
85bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmannstatic void xdp_dump_json(struct rtattr *tb[IFLA_XDP_MAX + 1])
86bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann{
87bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	__u32 prog_id = 0;
88bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	__u8 mode;
89bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann
90bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
91bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	if (tb[IFLA_XDP_PROG_ID])
92bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
93bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann
94bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	open_json_object("xdp");
95bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	print_uint(PRINT_JSON, "mode", NULL, mode);
96bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	if (prog_id)
97bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		bpf_dump_prog_info(NULL, prog_id);
98bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	close_json_object();
99bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann}
100bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann
101a0b5b7cf5c05c7aa29c683c52f896c74ab7924b0Daniel Borkmannvoid xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details)
102c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann{
103c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	struct rtattr *tb[IFLA_XDP_MAX + 1];
104a0b5b7cf5c05c7aa29c683c52f896c74ab7924b0Daniel Borkmann	__u32 prog_id = 0;
105077bb1803cf98deea2f1a8be40f2590120bfb4b5Daniel Borkmann	__u8 mode;
106c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
107c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann	parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp);
108a872b870a51135cde29e595a4782d910a9d39393Daniel Borkmann
109077bb1803cf98deea2f1a8be40f2590120bfb4b5Daniel Borkmann	if (!tb[IFLA_XDP_ATTACHED])
110c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann		return;
111c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann
112077bb1803cf98deea2f1a8be40f2590120bfb4b5Daniel Borkmann	mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
113bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	if (mode == XDP_ATTACHED_NONE)
114bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		return;
115bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	else if (is_json_context())
116bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		return details ? (void)0 : xdp_dump_json(tb);
117bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	else if (details && link)
118bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		fprintf(fp, "%s    prog/xdp", _SL_);
119bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	else if (mode == XDP_ATTACHED_DRV)
120bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		fprintf(fp, "xdp");
121bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	else if (mode == XDP_ATTACHED_SKB)
122bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		fprintf(fp, "xdpgeneric");
123bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	else if (mode == XDP_ATTACHED_HW)
124bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		fprintf(fp, "xdpoffload");
125bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	else
126bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		fprintf(fp, "xdp[%u]", mode);
127bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann
128bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	if (tb[IFLA_XDP_PROG_ID])
129bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
130bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	if (!details) {
131bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		if (prog_id && !link)
132bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann			fprintf(fp, "/id:%u", prog_id);
133bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		fprintf(fp, " ");
134bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		return;
135bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	}
136bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann
137bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann	if (prog_id) {
138bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		fprintf(fp, " ");
139bc2d4d838ff717f4003b039725df454a4a75109eDaniel Borkmann		bpf_dump_prog_info(fp, prog_id);
140a0b5b7cf5c05c7aa29c683c52f896c74ab7924b0Daniel Borkmann	}
141c7272ca72009940faa79bc4db2296d27789455cdDaniel Borkmann}
142