Home | History | Annotate | Download | only in ip
      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