]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iplink_xdp.c
ip route: get: allow zero-length subnet mask
[mirror_iproute2.git] / ip / iplink_xdp.c
CommitLineData
c7272ca7
DB
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
c7272ca7 17#include "bpf_util.h"
f7af0dc5
SP
18#include "utils.h"
19#include "ip_common.h"
c7272ca7
DB
20
21extern int force;
22
a872b870
DB
23struct xdp_req {
24 struct iplink_req *req;
25 __u32 flags;
26};
27
c7272ca7
DB
28static void xdp_ebpf_cb(void *raw, int fd, const char *annotation)
29{
a872b870
DB
30 struct xdp_req *xdp = raw;
31 struct iplink_req *req = xdp->req;
32 struct rtattr *xdp_attr;
c7272ca7 33
a872b870 34 xdp_attr = addattr_nest(&req->n, sizeof(*req), IFLA_XDP);
c7272ca7 35 addattr32(&req->n, sizeof(*req), IFLA_XDP_FD, fd);
a872b870
DB
36 if (xdp->flags)
37 addattr32(&req->n, sizeof(*req), IFLA_XDP_FLAGS, xdp->flags);
38 addattr_nest_end(&req->n, xdp_attr);
c7272ca7
DB
39}
40
41static const struct bpf_cfg_ops bpf_cb_ops = {
42 .ebpf_cb = xdp_ebpf_cb,
43};
44
a872b870 45static int xdp_delete(struct xdp_req *xdp)
c7272ca7 46{
a872b870 47 xdp_ebpf_cb(xdp, -1, NULL);
c7272ca7
DB
48 return 0;
49}
50
65083b5f
SH
51int xdp_parse(int *argc, char ***argv, struct iplink_req *req,
52 const char *ifname, bool generic, bool drv, bool offload)
c7272ca7
DB
53{
54 struct bpf_cfg_in cfg = {
658cfebc 55 .type = BPF_PROG_TYPE_XDP,
c7272ca7
DB
56 .argc = *argc,
57 .argv = *argv,
58 };
a872b870
DB
59 struct xdp_req xdp = {
60 .req = req,
61 };
62
4f2eb14f 63 if (offload) {
65083b5f
SH
64 int ifindex = ll_name_to_index(ifname);
65
4f2eb14f
JK
66 if (!ifindex)
67 incomplete_command();
68 cfg.ifindex = ifindex;
69 }
70
a872b870
DB
71 if (!force)
72 xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST;
73 if (generic)
74 xdp.flags |= XDP_FLAGS_SKB_MODE;
14683814
JK
75 if (drv)
76 xdp.flags |= XDP_FLAGS_DRV_MODE;
1b5e8094
JK
77 if (offload)
78 xdp.flags |= XDP_FLAGS_HW_MODE;
c7272ca7
DB
79
80 if (*argc == 1) {
81 if (strcmp(**argv, "none") == 0 ||
82 strcmp(**argv, "off") == 0)
a872b870 83 return xdp_delete(&xdp);
c7272ca7 84 }
a872b870 85
399db839 86 if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &xdp))
c7272ca7
DB
87 return -1;
88
89 *argc = cfg.argc;
90 *argv = cfg.argv;
91 return 0;
92}
93
da083b5a
JK
94static void xdp_dump_json_one(struct rtattr *tb[IFLA_XDP_MAX + 1], __u32 attr,
95 __u8 mode)
96{
97 if (!tb[attr])
98 return;
99
100 open_json_object(NULL);
101 print_uint(PRINT_JSON, "mode", NULL, mode);
102 bpf_dump_prog_info(NULL, rta_getattr_u32(tb[attr]));
103 close_json_object();
104}
105
bc2d4d83
DB
106static void xdp_dump_json(struct rtattr *tb[IFLA_XDP_MAX + 1])
107{
108 __u32 prog_id = 0;
109 __u8 mode;
110
111 mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
112 if (tb[IFLA_XDP_PROG_ID])
113 prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
114
115 open_json_object("xdp");
116 print_uint(PRINT_JSON, "mode", NULL, mode);
117 if (prog_id)
118 bpf_dump_prog_info(NULL, prog_id);
da083b5a
JK
119
120 open_json_array(PRINT_JSON, "attached");
121 if (tb[IFLA_XDP_SKB_PROG_ID] ||
122 tb[IFLA_XDP_DRV_PROG_ID] ||
123 tb[IFLA_XDP_HW_PROG_ID]) {
124 xdp_dump_json_one(tb, IFLA_XDP_SKB_PROG_ID, XDP_ATTACHED_SKB);
125 xdp_dump_json_one(tb, IFLA_XDP_DRV_PROG_ID, XDP_ATTACHED_DRV);
126 xdp_dump_json_one(tb, IFLA_XDP_HW_PROG_ID, XDP_ATTACHED_HW);
127 } else if (tb[IFLA_XDP_PROG_ID]) {
128 /* Older kernel - use IFLA_XDP_PROG_ID */
129 xdp_dump_json_one(tb, IFLA_XDP_PROG_ID, mode);
130 }
131 close_json_array(PRINT_JSON, NULL);
132
bc2d4d83
DB
133 close_json_object();
134}
135
da083b5a
JK
136static void xdp_dump_prog_one(FILE *fp, struct rtattr *tb[IFLA_XDP_MAX + 1],
137 __u32 attr, bool link, bool details,
138 const char *pfx)
139{
140 __u32 prog_id;
141
142 if (!tb[attr])
143 return;
144
145 prog_id = rta_getattr_u32(tb[attr]);
146 if (!details) {
147 if (prog_id && !link && attr == IFLA_XDP_PROG_ID)
148 fprintf(fp, "/id:%u", prog_id);
149 return;
150 }
151
152 if (prog_id) {
153 fprintf(fp, "%s prog/xdp%s ", _SL_, pfx);
154 bpf_dump_prog_info(fp, prog_id);
155 }
156}
157
a0b5b7cf 158void xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details)
c7272ca7
DB
159{
160 struct rtattr *tb[IFLA_XDP_MAX + 1];
077bb180 161 __u8 mode;
c7272ca7
DB
162
163 parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp);
a872b870 164
077bb180 165 if (!tb[IFLA_XDP_ATTACHED])
c7272ca7
DB
166 return;
167
077bb180 168 mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
bc2d4d83
DB
169 if (mode == XDP_ATTACHED_NONE)
170 return;
171 else if (is_json_context())
172 return details ? (void)0 : xdp_dump_json(tb);
173 else if (details && link)
da083b5a 174 /* don't print mode */;
bc2d4d83
DB
175 else if (mode == XDP_ATTACHED_DRV)
176 fprintf(fp, "xdp");
177 else if (mode == XDP_ATTACHED_SKB)
178 fprintf(fp, "xdpgeneric");
179 else if (mode == XDP_ATTACHED_HW)
180 fprintf(fp, "xdpoffload");
da083b5a
JK
181 else if (mode == XDP_ATTACHED_MULTI)
182 fprintf(fp, "xdpmulti");
bc2d4d83
DB
183 else
184 fprintf(fp, "xdp[%u]", mode);
185
da083b5a
JK
186 xdp_dump_prog_one(fp, tb, IFLA_XDP_PROG_ID, link, details, "");
187
188 if (mode == XDP_ATTACHED_MULTI) {
189 xdp_dump_prog_one(fp, tb, IFLA_XDP_SKB_PROG_ID, link, details,
190 "generic");
191 xdp_dump_prog_one(fp, tb, IFLA_XDP_DRV_PROG_ID, link, details,
192 "drv");
193 xdp_dump_prog_one(fp, tb, IFLA_XDP_HW_PROG_ID, link, details,
194 "offload");
bc2d4d83
DB
195 }
196
da083b5a 197 if (!details || !link)
bc2d4d83 198 fprintf(fp, " ");
c7272ca7 199}