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