blob: 2d2953aa47a83fa9133d2668f6d910502cfd8a8d [file] [log] [blame]
Daniel Borkmannc7272ca2016-12-06 02:21:57 +01001/*
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
Daniel Borkmannbc2d4d82017-09-21 10:42:29 +020017#include "json_print.h"
Daniel Borkmannc7272ca2016-12-06 02:21:57 +010018#include "xdp.h"
19#include "bpf_util.h"
20
21extern int force;
22
Daniel Borkmanna872b872017-04-28 15:44:29 +020023struct xdp_req {
24 struct iplink_req *req;
25 __u32 flags;
26};
27
Daniel Borkmannc7272ca2016-12-06 02:21:57 +010028static void xdp_ebpf_cb(void *raw, int fd, const char *annotation)
29{
Daniel Borkmanna872b872017-04-28 15:44:29 +020030 struct xdp_req *xdp = raw;
31 struct iplink_req *req = xdp->req;
32 struct rtattr *xdp_attr;
Daniel Borkmannc7272ca2016-12-06 02:21:57 +010033
Daniel Borkmanna872b872017-04-28 15:44:29 +020034 xdp_attr = addattr_nest(&req->n, sizeof(*req), IFLA_XDP);
Daniel Borkmannc7272ca2016-12-06 02:21:57 +010035 addattr32(&req->n, sizeof(*req), IFLA_XDP_FD, fd);
Daniel Borkmanna872b872017-04-28 15:44:29 +020036 if (xdp->flags)
37 addattr32(&req->n, sizeof(*req), IFLA_XDP_FLAGS, xdp->flags);
38 addattr_nest_end(&req->n, xdp_attr);
Daniel Borkmannc7272ca2016-12-06 02:21:57 +010039}
40
41static const struct bpf_cfg_ops bpf_cb_ops = {
42 .ebpf_cb = xdp_ebpf_cb,
43};
44
Daniel Borkmanna872b872017-04-28 15:44:29 +020045static int xdp_delete(struct xdp_req *xdp)
Daniel Borkmannc7272ca2016-12-06 02:21:57 +010046{
Daniel Borkmanna872b872017-04-28 15:44:29 +020047 xdp_ebpf_cb(xdp, -1, NULL);
Daniel Borkmannc7272ca2016-12-06 02:21:57 +010048 return 0;
49}
50
Jakub Kicinski14683812017-06-26 17:23:52 -070051int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic,
Jakub Kicinski1b5e8092017-06-26 17:23:53 -070052 bool drv, bool offload)
Daniel Borkmannc7272ca2016-12-06 02:21:57 +010053{
54 struct bpf_cfg_in cfg = {
55 .argc = *argc,
56 .argv = *argv,
57 };
Daniel Borkmanna872b872017-04-28 15:44:29 +020058 struct xdp_req xdp = {
59 .req = req,
60 };
61
62 if (!force)
63 xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST;
64 if (generic)
65 xdp.flags |= XDP_FLAGS_SKB_MODE;
Jakub Kicinski14683812017-06-26 17:23:52 -070066 if (drv)
67 xdp.flags |= XDP_FLAGS_DRV_MODE;
Jakub Kicinski1b5e8092017-06-26 17:23:53 -070068 if (offload)
69 xdp.flags |= XDP_FLAGS_HW_MODE;
Daniel Borkmannc7272ca2016-12-06 02:21:57 +010070
71 if (*argc == 1) {
72 if (strcmp(**argv, "none") == 0 ||
73 strcmp(**argv, "off") == 0)
Daniel Borkmanna872b872017-04-28 15:44:29 +020074 return xdp_delete(&xdp);
Daniel Borkmannc7272ca2016-12-06 02:21:57 +010075 }
Daniel Borkmanna872b872017-04-28 15:44:29 +020076
77 if (bpf_parse_common(BPF_PROG_TYPE_XDP, &cfg, &bpf_cb_ops, &xdp))
Daniel Borkmannc7272ca2016-12-06 02:21:57 +010078 return -1;
79
80 *argc = cfg.argc;
81 *argv = cfg.argv;
82 return 0;
83}
84
Daniel Borkmannbc2d4d82017-09-21 10:42:29 +020085static void xdp_dump_json(struct rtattr *tb[IFLA_XDP_MAX + 1])
86{
87 __u32 prog_id = 0;
88 __u8 mode;
89
90 mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
91 if (tb[IFLA_XDP_PROG_ID])
92 prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
93
94 open_json_object("xdp");
95 print_uint(PRINT_JSON, "mode", NULL, mode);
96 if (prog_id)
97 bpf_dump_prog_info(NULL, prog_id);
98 close_json_object();
99}
100
Daniel Borkmanna0b5b7c2017-09-05 02:24:32 +0200101void xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details)
Daniel Borkmannc7272ca2016-12-06 02:21:57 +0100102{
103 struct rtattr *tb[IFLA_XDP_MAX + 1];
Daniel Borkmanna0b5b7c2017-09-05 02:24:32 +0200104 __u32 prog_id = 0;
Daniel Borkmann077bb182017-05-13 02:32:34 +0200105 __u8 mode;
Daniel Borkmannc7272ca2016-12-06 02:21:57 +0100106
107 parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp);
Daniel Borkmanna872b872017-04-28 15:44:29 +0200108
Daniel Borkmann077bb182017-05-13 02:32:34 +0200109 if (!tb[IFLA_XDP_ATTACHED])
Daniel Borkmannc7272ca2016-12-06 02:21:57 +0100110 return;
111
Daniel Borkmann077bb182017-05-13 02:32:34 +0200112 mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
Daniel Borkmannbc2d4d82017-09-21 10:42:29 +0200113 if (mode == XDP_ATTACHED_NONE)
114 return;
115 else if (is_json_context())
116 return details ? (void)0 : xdp_dump_json(tb);
117 else if (details && link)
118 fprintf(fp, "%s prog/xdp", _SL_);
119 else if (mode == XDP_ATTACHED_DRV)
120 fprintf(fp, "xdp");
121 else if (mode == XDP_ATTACHED_SKB)
122 fprintf(fp, "xdpgeneric");
123 else if (mode == XDP_ATTACHED_HW)
124 fprintf(fp, "xdpoffload");
125 else
126 fprintf(fp, "xdp[%u]", mode);
Martin KaFai Lau0b4ea602017-06-21 14:29:42 -0700127
Daniel Borkmannbc2d4d82017-09-21 10:42:29 +0200128 if (tb[IFLA_XDP_PROG_ID])
129 prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
130 if (!details) {
131 if (prog_id && !link)
132 fprintf(fp, "/id:%u", prog_id);
133 fprintf(fp, " ");
134 return;
135 }
Martin KaFai Lau0b4ea602017-06-21 14:29:42 -0700136
Daniel Borkmannbc2d4d82017-09-21 10:42:29 +0200137 if (prog_id) {
138 fprintf(fp, " ");
139 bpf_dump_prog_info(fp, prog_id);
Julien Fortin2f260652017-08-17 10:36:05 -0700140 }
Daniel Borkmannc7272ca2016-12-06 02:21:57 +0100141}