• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "json_print.h"
18 #include "xdp.h"
19 #include "bpf_util.h"
20 
21 extern int force;
22 
23 struct xdp_req {
24 	struct iplink_req *req;
25 	__u32 flags;
26 };
27 
xdp_ebpf_cb(void * raw,int fd,const char * annotation)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 
xdp_delete(struct xdp_req * xdp)45 static int xdp_delete(struct xdp_req *xdp)
46 {
47 	xdp_ebpf_cb(xdp, -1, NULL);
48 	return 0;
49 }
50 
xdp_parse(int * argc,char *** argv,struct iplink_req * req,bool generic,bool drv,bool offload)51 int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic,
52 	      bool drv, bool offload)
53 {
54 	struct bpf_cfg_in cfg = {
55 		.argc = *argc,
56 		.argv = *argv,
57 	};
58 	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;
66 	if (drv)
67 		xdp.flags |= XDP_FLAGS_DRV_MODE;
68 	if (offload)
69 		xdp.flags |= XDP_FLAGS_HW_MODE;
70 
71 	if (*argc == 1) {
72 		if (strcmp(**argv, "none") == 0 ||
73 		    strcmp(**argv, "off") == 0)
74 			return xdp_delete(&xdp);
75 	}
76 
77 	if (bpf_parse_common(BPF_PROG_TYPE_XDP, &cfg, &bpf_cb_ops, &xdp))
78 		return -1;
79 
80 	*argc = cfg.argc;
81 	*argv = cfg.argv;
82 	return 0;
83 }
84 
xdp_dump_json(struct rtattr * tb[IFLA_XDP_MAX+1])85 static 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 
xdp_dump(FILE * fp,struct rtattr * xdp,bool link,bool details)101 void xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details)
102 {
103 	struct rtattr *tb[IFLA_XDP_MAX + 1];
104 	__u32 prog_id = 0;
105 	__u8 mode;
106 
107 	parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp);
108 
109 	if (!tb[IFLA_XDP_ATTACHED])
110 		return;
111 
112 	mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
113 	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);
127 
128 	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 	}
136 
137 	if (prog_id) {
138 		fprintf(fp, " ");
139 		bpf_dump_prog_info(fp, prog_id);
140 	}
141 }
142