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 (at) 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 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, 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 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 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