Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 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 | |
Daniel Borkmann | bc2d4d8 | 2017-09-21 10:42:29 +0200 | [diff] [blame] | 17 | #include "json_print.h" |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 18 | #include "xdp.h" |
| 19 | #include "bpf_util.h" |
| 20 | |
| 21 | extern int force; |
| 22 | |
Daniel Borkmann | a872b87 | 2017-04-28 15:44:29 +0200 | [diff] [blame] | 23 | struct xdp_req { |
| 24 | struct iplink_req *req; |
| 25 | __u32 flags; |
| 26 | }; |
| 27 | |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 28 | static void xdp_ebpf_cb(void *raw, int fd, const char *annotation) |
| 29 | { |
Daniel Borkmann | a872b87 | 2017-04-28 15:44:29 +0200 | [diff] [blame] | 30 | struct xdp_req *xdp = raw; |
| 31 | struct iplink_req *req = xdp->req; |
| 32 | struct rtattr *xdp_attr; |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 33 | |
Daniel Borkmann | a872b87 | 2017-04-28 15:44:29 +0200 | [diff] [blame] | 34 | xdp_attr = addattr_nest(&req->n, sizeof(*req), IFLA_XDP); |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 35 | addattr32(&req->n, sizeof(*req), IFLA_XDP_FD, fd); |
Daniel Borkmann | a872b87 | 2017-04-28 15:44:29 +0200 | [diff] [blame] | 36 | if (xdp->flags) |
| 37 | addattr32(&req->n, sizeof(*req), IFLA_XDP_FLAGS, xdp->flags); |
| 38 | addattr_nest_end(&req->n, xdp_attr); |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 39 | } |
| 40 | |
| 41 | static const struct bpf_cfg_ops bpf_cb_ops = { |
| 42 | .ebpf_cb = xdp_ebpf_cb, |
| 43 | }; |
| 44 | |
Daniel Borkmann | a872b87 | 2017-04-28 15:44:29 +0200 | [diff] [blame] | 45 | static int xdp_delete(struct xdp_req *xdp) |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 46 | { |
Daniel Borkmann | a872b87 | 2017-04-28 15:44:29 +0200 | [diff] [blame] | 47 | xdp_ebpf_cb(xdp, -1, NULL); |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 48 | return 0; |
| 49 | } |
| 50 | |
Jakub Kicinski | 1468381 | 2017-06-26 17:23:52 -0700 | [diff] [blame] | 51 | int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic, |
Jakub Kicinski | 1b5e809 | 2017-06-26 17:23:53 -0700 | [diff] [blame] | 52 | bool drv, bool offload) |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 53 | { |
| 54 | struct bpf_cfg_in cfg = { |
| 55 | .argc = *argc, |
| 56 | .argv = *argv, |
| 57 | }; |
Daniel Borkmann | a872b87 | 2017-04-28 15:44:29 +0200 | [diff] [blame] | 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; |
Jakub Kicinski | 1468381 | 2017-06-26 17:23:52 -0700 | [diff] [blame] | 66 | if (drv) |
| 67 | xdp.flags |= XDP_FLAGS_DRV_MODE; |
Jakub Kicinski | 1b5e809 | 2017-06-26 17:23:53 -0700 | [diff] [blame] | 68 | if (offload) |
| 69 | xdp.flags |= XDP_FLAGS_HW_MODE; |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 70 | |
| 71 | if (*argc == 1) { |
| 72 | if (strcmp(**argv, "none") == 0 || |
| 73 | strcmp(**argv, "off") == 0) |
Daniel Borkmann | a872b87 | 2017-04-28 15:44:29 +0200 | [diff] [blame] | 74 | return xdp_delete(&xdp); |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 75 | } |
Daniel Borkmann | a872b87 | 2017-04-28 15:44:29 +0200 | [diff] [blame] | 76 | |
| 77 | if (bpf_parse_common(BPF_PROG_TYPE_XDP, &cfg, &bpf_cb_ops, &xdp)) |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 78 | return -1; |
| 79 | |
| 80 | *argc = cfg.argc; |
| 81 | *argv = cfg.argv; |
| 82 | return 0; |
| 83 | } |
| 84 | |
Daniel Borkmann | bc2d4d8 | 2017-09-21 10:42:29 +0200 | [diff] [blame] | 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 | |
Daniel Borkmann | a0b5b7c | 2017-09-05 02:24:32 +0200 | [diff] [blame] | 101 | void xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details) |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 102 | { |
| 103 | struct rtattr *tb[IFLA_XDP_MAX + 1]; |
Daniel Borkmann | a0b5b7c | 2017-09-05 02:24:32 +0200 | [diff] [blame] | 104 | __u32 prog_id = 0; |
Daniel Borkmann | 077bb18 | 2017-05-13 02:32:34 +0200 | [diff] [blame] | 105 | __u8 mode; |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 106 | |
| 107 | parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp); |
Daniel Borkmann | a872b87 | 2017-04-28 15:44:29 +0200 | [diff] [blame] | 108 | |
Daniel Borkmann | 077bb18 | 2017-05-13 02:32:34 +0200 | [diff] [blame] | 109 | if (!tb[IFLA_XDP_ATTACHED]) |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 110 | return; |
| 111 | |
Daniel Borkmann | 077bb18 | 2017-05-13 02:32:34 +0200 | [diff] [blame] | 112 | mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]); |
Daniel Borkmann | bc2d4d8 | 2017-09-21 10:42:29 +0200 | [diff] [blame] | 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); |
Martin KaFai Lau | 0b4ea60 | 2017-06-21 14:29:42 -0700 | [diff] [blame] | 127 | |
Daniel Borkmann | bc2d4d8 | 2017-09-21 10:42:29 +0200 | [diff] [blame] | 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 | } |
Martin KaFai Lau | 0b4ea60 | 2017-06-21 14:29:42 -0700 | [diff] [blame] | 136 | |
Daniel Borkmann | bc2d4d8 | 2017-09-21 10:42:29 +0200 | [diff] [blame] | 137 | if (prog_id) { |
| 138 | fprintf(fp, " "); |
| 139 | bpf_dump_prog_info(fp, prog_id); |
Julien Fortin | 2f26065 | 2017-08-17 10:36:05 -0700 | [diff] [blame] | 140 | } |
Daniel Borkmann | c7272ca | 2016-12-06 02:21:57 +0100 | [diff] [blame] | 141 | } |