]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iplink_xdp.c
bpf: allow requesting XDP HW offload
[mirror_iproute2.git] / ip / iplink_xdp.c
1 /*
2 * iplink_xdp.c XDP program loader
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Daniel Borkmann <daniel@iogearbox.net>
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 #include <linux/bpf.h>
16
17 #include "xdp.h"
18 #include "bpf_util.h"
19
20 extern int force;
21
22 struct xdp_req {
23 struct iplink_req *req;
24 __u32 flags;
25 };
26
27 static void xdp_ebpf_cb(void *raw, int fd, const char *annotation)
28 {
29 struct xdp_req *xdp = raw;
30 struct iplink_req *req = xdp->req;
31 struct rtattr *xdp_attr;
32
33 xdp_attr = addattr_nest(&req->n, sizeof(*req), IFLA_XDP);
34 addattr32(&req->n, sizeof(*req), IFLA_XDP_FD, fd);
35 if (xdp->flags)
36 addattr32(&req->n, sizeof(*req), IFLA_XDP_FLAGS, xdp->flags);
37 addattr_nest_end(&req->n, xdp_attr);
38 }
39
40 static const struct bpf_cfg_ops bpf_cb_ops = {
41 .ebpf_cb = xdp_ebpf_cb,
42 };
43
44 static int xdp_delete(struct xdp_req *xdp)
45 {
46 xdp_ebpf_cb(xdp, -1, NULL);
47 return 0;
48 }
49
50 int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic,
51 bool drv, bool offload)
52 {
53 struct bpf_cfg_in cfg = {
54 .argc = *argc,
55 .argv = *argv,
56 };
57 struct xdp_req xdp = {
58 .req = req,
59 };
60
61 if (!force)
62 xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST;
63 if (generic)
64 xdp.flags |= XDP_FLAGS_SKB_MODE;
65 if (drv)
66 xdp.flags |= XDP_FLAGS_DRV_MODE;
67 if (offload)
68 xdp.flags |= XDP_FLAGS_HW_MODE;
69
70 if (*argc == 1) {
71 if (strcmp(**argv, "none") == 0 ||
72 strcmp(**argv, "off") == 0)
73 return xdp_delete(&xdp);
74 }
75
76 if (bpf_parse_common(BPF_PROG_TYPE_XDP, &cfg, &bpf_cb_ops, &xdp))
77 return -1;
78
79 *argc = cfg.argc;
80 *argv = cfg.argv;
81 return 0;
82 }
83
84 void xdp_dump(FILE *fp, struct rtattr *xdp)
85 {
86 struct rtattr *tb[IFLA_XDP_MAX + 1];
87 __u8 mode;
88
89 parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp);
90
91 if (!tb[IFLA_XDP_ATTACHED])
92 return;
93
94 mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
95 if (mode == XDP_ATTACHED_NONE)
96 return;
97 else if (mode == XDP_ATTACHED_DRV)
98 fprintf(fp, "xdp");
99 else if (mode == XDP_ATTACHED_SKB)
100 fprintf(fp, "xdpgeneric");
101 else if (mode == XDP_ATTACHED_HW)
102 fprintf(fp, "xdpoffload");
103 else
104 fprintf(fp, "xdp[%u]", mode);
105
106 if (tb[IFLA_XDP_PROG_ID])
107 fprintf(fp, "/id:%u",
108 rta_getattr_u32(tb[IFLA_XDP_PROG_ID]));
109
110 fprintf(fp, " ");
111 }