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