iproute2/ip/iplink_xdp.c
<<
>>
Prefs
   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 "bpf_util.h"
  18#include "utils.h"
  19#include "ip_common.h"
  20
  21extern int force;
  22
  23struct xdp_req {
  24        struct iplink_req *req;
  25        __u32 flags;
  26};
  27
  28static 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
  41static const struct bpf_cfg_ops bpf_cb_ops = {
  42        .ebpf_cb = xdp_ebpf_cb,
  43};
  44
  45static int xdp_delete(struct xdp_req *xdp)
  46{
  47        xdp_ebpf_cb(xdp, -1, NULL);
  48        return 0;
  49}
  50
  51int xdp_parse(int *argc, char ***argv, struct iplink_req *req,
  52              const char *ifname, bool generic, bool drv, bool offload)
  53{
  54        struct bpf_cfg_in cfg = {
  55                .type = BPF_PROG_TYPE_XDP,
  56                .argc = *argc,
  57                .argv = *argv,
  58        };
  59        struct xdp_req xdp = {
  60                .req = req,
  61        };
  62
  63        if (offload) {
  64                int ifindex = ll_name_to_index(ifname);
  65
  66                if (!ifindex)
  67                        incomplete_command();
  68                cfg.ifindex = ifindex;
  69        }
  70
  71        if (!force)
  72                xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST;
  73        if (generic)
  74                xdp.flags |= XDP_FLAGS_SKB_MODE;
  75        if (drv)
  76                xdp.flags |= XDP_FLAGS_DRV_MODE;
  77        if (offload)
  78                xdp.flags |= XDP_FLAGS_HW_MODE;
  79
  80        if (*argc == 1) {
  81                if (strcmp(**argv, "none") == 0 ||
  82                    strcmp(**argv, "off") == 0)
  83                        return xdp_delete(&xdp);
  84        }
  85
  86        if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &xdp))
  87                return -1;
  88
  89        *argc = cfg.argc;
  90        *argv = cfg.argv;
  91        return 0;
  92}
  93
  94static void xdp_dump_json_one(struct rtattr *tb[IFLA_XDP_MAX + 1], __u32 attr,
  95                              __u8 mode)
  96{
  97        if (!tb[attr])
  98                return;
  99
 100        open_json_object(NULL);
 101        print_uint(PRINT_JSON, "mode", NULL, mode);
 102        bpf_dump_prog_info(NULL, rta_getattr_u32(tb[attr]));
 103        close_json_object();
 104}
 105
 106static void xdp_dump_json(struct rtattr *tb[IFLA_XDP_MAX + 1])
 107{
 108        __u32 prog_id = 0;
 109        __u8 mode;
 110
 111        mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
 112        if (tb[IFLA_XDP_PROG_ID])
 113                prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
 114
 115        open_json_object("xdp");
 116        print_uint(PRINT_JSON, "mode", NULL, mode);
 117        if (prog_id)
 118                bpf_dump_prog_info(NULL, prog_id);
 119
 120        open_json_array(PRINT_JSON, "attached");
 121        if (tb[IFLA_XDP_SKB_PROG_ID] ||
 122            tb[IFLA_XDP_DRV_PROG_ID] ||
 123            tb[IFLA_XDP_HW_PROG_ID]) {
 124                xdp_dump_json_one(tb, IFLA_XDP_SKB_PROG_ID, XDP_ATTACHED_SKB);
 125                xdp_dump_json_one(tb, IFLA_XDP_DRV_PROG_ID, XDP_ATTACHED_DRV);
 126                xdp_dump_json_one(tb, IFLA_XDP_HW_PROG_ID, XDP_ATTACHED_HW);
 127        } else if (tb[IFLA_XDP_PROG_ID]) {
 128                /* Older kernel - use IFLA_XDP_PROG_ID */
 129                xdp_dump_json_one(tb, IFLA_XDP_PROG_ID, mode);
 130        }
 131        close_json_array(PRINT_JSON, NULL);
 132
 133        close_json_object();
 134}
 135
 136static void xdp_dump_prog_one(FILE *fp, struct rtattr *tb[IFLA_XDP_MAX + 1],
 137                              __u32 attr, bool link, bool details,
 138                              const char *pfx)
 139{
 140        __u32 prog_id;
 141
 142        if (!tb[attr])
 143                return;
 144
 145        prog_id = rta_getattr_u32(tb[attr]);
 146        if (!details) {
 147                if (prog_id && !link && attr == IFLA_XDP_PROG_ID)
 148                        fprintf(fp, "/id:%u", prog_id);
 149                return;
 150        }
 151
 152        if (prog_id) {
 153                fprintf(fp, "%s    prog/xdp%s ", _SL_, pfx);
 154                bpf_dump_prog_info(fp, prog_id);
 155        }
 156}
 157
 158void xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details)
 159{
 160        struct rtattr *tb[IFLA_XDP_MAX + 1];
 161        __u8 mode;
 162
 163        parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp);
 164
 165        if (!tb[IFLA_XDP_ATTACHED])
 166                return;
 167
 168        mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
 169        if (mode == XDP_ATTACHED_NONE)
 170                return;
 171        else if (is_json_context())
 172                return details ? (void)0 : xdp_dump_json(tb);
 173        else if (details && link)
 174                /* don't print mode */;
 175        else if (mode == XDP_ATTACHED_DRV)
 176                fprintf(fp, "xdp");
 177        else if (mode == XDP_ATTACHED_SKB)
 178                fprintf(fp, "xdpgeneric");
 179        else if (mode == XDP_ATTACHED_HW)
 180                fprintf(fp, "xdpoffload");
 181        else if (mode == XDP_ATTACHED_MULTI)
 182                fprintf(fp, "xdpmulti");
 183        else
 184                fprintf(fp, "xdp[%u]", mode);
 185
 186        xdp_dump_prog_one(fp, tb, IFLA_XDP_PROG_ID, link, details, "");
 187
 188        if (mode == XDP_ATTACHED_MULTI) {
 189                xdp_dump_prog_one(fp, tb, IFLA_XDP_SKB_PROG_ID, link, details,
 190                                  "generic");
 191                xdp_dump_prog_one(fp, tb, IFLA_XDP_DRV_PROG_ID, link, details,
 192                                  "drv");
 193                xdp_dump_prog_one(fp, tb, IFLA_XDP_HW_PROG_ID, link, details,
 194                                  "offload");
 195        }
 196
 197        if (!details || !link)
 198                fprintf(fp, " ");
 199}
 200