]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iplink_xdp.c
Merge branch 'iproute2-master' into iproute2-next
[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 "bpf_util.h"
18 #include "utils.h"
19 #include "ip_common.h"
20
21 extern int force;
22
23 struct xdp_req {
24 struct iplink_req *req;
25 __u32 flags;
26 };
27
28 static void xdp_ebpf_cb(void *raw, int fd, const char *annotation)
29 {
30 struct xdp_req *xdp = raw;
31 struct iplink_req *req = xdp->req;
32 struct rtattr *xdp_attr;
33
34 xdp_attr = addattr_nest(&req->n, sizeof(*req), IFLA_XDP);
35 addattr32(&req->n, sizeof(*req), IFLA_XDP_FD, fd);
36 if (xdp->flags)
37 addattr32(&req->n, sizeof(*req), IFLA_XDP_FLAGS, xdp->flags);
38 addattr_nest_end(&req->n, xdp_attr);
39 }
40
41 static const struct bpf_cfg_ops bpf_cb_ops = {
42 .ebpf_cb = xdp_ebpf_cb,
43 };
44
45 static int xdp_delete(struct xdp_req *xdp)
46 {
47 xdp_ebpf_cb(xdp, -1, NULL);
48 return 0;
49 }
50
51 int xdp_parse(int *argc, char ***argv, struct iplink_req *req, __u32 ifindex,
52 bool generic, bool drv, bool offload)
53 {
54 struct bpf_cfg_in cfg = {
55 .type = BPF_PROG_TYPE_XDP,
56 .argc = *argc,
57 .argv = *argv,
58 };
59 struct xdp_req xdp = {
60 .req = req,
61 };
62
63 if (offload) {
64 if (!ifindex)
65 incomplete_command();
66 cfg.ifindex = ifindex;
67 }
68
69 if (!force)
70 xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST;
71 if (generic)
72 xdp.flags |= XDP_FLAGS_SKB_MODE;
73 if (drv)
74 xdp.flags |= XDP_FLAGS_DRV_MODE;
75 if (offload)
76 xdp.flags |= XDP_FLAGS_HW_MODE;
77
78 if (*argc == 1) {
79 if (strcmp(**argv, "none") == 0 ||
80 strcmp(**argv, "off") == 0)
81 return xdp_delete(&xdp);
82 }
83
84 if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &xdp))
85 return -1;
86
87 *argc = cfg.argc;
88 *argv = cfg.argv;
89 return 0;
90 }
91
92 static void xdp_dump_json(struct rtattr *tb[IFLA_XDP_MAX + 1])
93 {
94 __u32 prog_id = 0;
95 __u8 mode;
96
97 mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
98 if (tb[IFLA_XDP_PROG_ID])
99 prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
100
101 open_json_object("xdp");
102 print_uint(PRINT_JSON, "mode", NULL, mode);
103 if (prog_id)
104 bpf_dump_prog_info(NULL, prog_id);
105 close_json_object();
106 }
107
108 void xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details)
109 {
110 struct rtattr *tb[IFLA_XDP_MAX + 1];
111 __u32 prog_id = 0;
112 __u8 mode;
113
114 parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp);
115
116 if (!tb[IFLA_XDP_ATTACHED])
117 return;
118
119 mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
120 if (mode == XDP_ATTACHED_NONE)
121 return;
122 else if (is_json_context())
123 return details ? (void)0 : xdp_dump_json(tb);
124 else if (details && link)
125 fprintf(fp, "%s prog/xdp", _SL_);
126 else if (mode == XDP_ATTACHED_DRV)
127 fprintf(fp, "xdp");
128 else if (mode == XDP_ATTACHED_SKB)
129 fprintf(fp, "xdpgeneric");
130 else if (mode == XDP_ATTACHED_HW)
131 fprintf(fp, "xdpoffload");
132 else
133 fprintf(fp, "xdp[%u]", mode);
134
135 if (tb[IFLA_XDP_PROG_ID])
136 prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
137 if (!details) {
138 if (prog_id && !link)
139 fprintf(fp, "/id:%u", prog_id);
140 fprintf(fp, " ");
141 return;
142 }
143
144 if (prog_id) {
145 fprintf(fp, " ");
146 bpf_dump_prog_info(fp, prog_id);
147 }
148 }