iproute2/tc/m_bpf.c
<<
>>
Prefs
   1/*
   2 * m_bpf.c      BPF based action module
   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:     Jiri Pirko <jiri@resnulli.us>
  10 *              Daniel Borkmann <daniel@iogearbox.net>
  11 */
  12
  13#include <stdio.h>
  14#include <stdlib.h>
  15
  16#include <linux/bpf.h>
  17#include <linux/tc_act/tc_bpf.h>
  18
  19#include "utils.h"
  20
  21#include "tc_util.h"
  22#include "bpf_util.h"
  23
  24static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_ACT;
  25
  26static void explain(void)
  27{
  28        fprintf(stderr,
  29                "Usage: ... bpf ... [ index INDEX ]\n"
  30                "\n"
  31                "BPF use case:\n"
  32                " bytecode BPF_BYTECODE\n"
  33                " bytecode-file FILE\n"
  34                "\n"
  35                "eBPF use case:\n"
  36                " object-file FILE [ section ACT_NAME ] [ export UDS_FILE ]"
  37                " [ verbose ]\n"
  38                " object-pinned FILE\n"
  39                "\n"
  40                "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n"
  41                "c,t,f,k and s are decimals; s denotes number of 4-tuples\n"
  42                "\n"
  43                "Where FILE points to a file containing the BPF_BYTECODE string,\n"
  44                "an ELF file containing eBPF map definitions and bytecode, or a\n"
  45                "pinned eBPF program.\n"
  46                "\n"
  47                "Where ACT_NAME refers to the section name containing the\n"
  48                "action (default \'%s\').\n"
  49                "\n"
  50                "Where UDS_FILE points to a unix domain socket file in order\n"
  51                "to hand off control of all created eBPF maps to an agent.\n"
  52                "\n"
  53                "Where optionally INDEX points to an existing action, or\n"
  54                "explicitly specifies an action index upon creation.\n",
  55                bpf_prog_to_default_section(bpf_type));
  56}
  57
  58static void bpf_cbpf_cb(void *nl, const struct sock_filter *ops, int ops_len)
  59{
  60        addattr16(nl, MAX_MSG, TCA_ACT_BPF_OPS_LEN, ops_len);
  61        addattr_l(nl, MAX_MSG, TCA_ACT_BPF_OPS, ops,
  62                  ops_len * sizeof(struct sock_filter));
  63}
  64
  65static void bpf_ebpf_cb(void *nl, int fd, const char *annotation)
  66{
  67        addattr32(nl, MAX_MSG, TCA_ACT_BPF_FD, fd);
  68        addattrstrz(nl, MAX_MSG, TCA_ACT_BPF_NAME, annotation);
  69}
  70
  71static const struct bpf_cfg_ops bpf_cb_ops = {
  72        .cbpf_cb = bpf_cbpf_cb,
  73        .ebpf_cb = bpf_ebpf_cb,
  74};
  75
  76static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv,
  77                         int tca_id, struct nlmsghdr *n)
  78{
  79        const char *bpf_obj = NULL, *bpf_uds_name = NULL;
  80        struct tc_act_bpf parm = {};
  81        struct bpf_cfg_in cfg = {};
  82        bool seen_run = false;
  83        struct rtattr *tail;
  84        int argc, ret = 0;
  85        char **argv;
  86
  87        argv = *ptr_argv;
  88        argc = *ptr_argc;
  89
  90        if (matches(*argv, "bpf") != 0)
  91                return -1;
  92
  93        NEXT_ARG();
  94
  95        tail = addattr_nest(n, MAX_MSG, tca_id);
  96
  97        while (argc > 0) {
  98                if (matches(*argv, "run") == 0) {
  99                        NEXT_ARG();
 100
 101                        if (seen_run)
 102                                duparg("run", *argv);
 103opt_bpf:
 104                        seen_run = true;
 105                        cfg.type = bpf_type;
 106                        cfg.argc = argc;
 107                        cfg.argv = argv;
 108
 109                        if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, n))
 110                                return -1;
 111
 112                        argc = cfg.argc;
 113                        argv = cfg.argv;
 114
 115                        bpf_obj = cfg.object;
 116                        bpf_uds_name = cfg.uds;
 117                } else if (matches(*argv, "help") == 0) {
 118                        explain();
 119                        return -1;
 120                } else if (matches(*argv, "index") == 0) {
 121                        break;
 122                } else {
 123                        if (!seen_run)
 124                                goto opt_bpf;
 125                        break;
 126                }
 127
 128                NEXT_ARG_FWD();
 129        }
 130
 131        parse_action_control_dflt(&argc, &argv, &parm.action,
 132                                  false, TC_ACT_PIPE);
 133
 134        if (argc) {
 135                if (matches(*argv, "index") == 0) {
 136                        NEXT_ARG();
 137                        if (get_u32(&parm.index, *argv, 10)) {
 138                                fprintf(stderr, "bpf: Illegal \"index\"\n");
 139                                return -1;
 140                        }
 141
 142                        NEXT_ARG_FWD();
 143                }
 144        }
 145
 146        addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm));
 147        addattr_nest_end(n, tail);
 148
 149        if (bpf_uds_name)
 150                ret = bpf_send_map_fds(bpf_uds_name, bpf_obj);
 151
 152        *ptr_argc = argc;
 153        *ptr_argv = argv;
 154
 155        return ret;
 156}
 157
 158static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg)
 159{
 160        struct rtattr *tb[TCA_ACT_BPF_MAX + 1];
 161        struct tc_act_bpf *parm;
 162        int d_ok = 0;
 163
 164        print_string(PRINT_ANY, "kind", "%s ", "bpf");
 165        if (arg == NULL)
 166                return 0;
 167
 168        parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg);
 169
 170        if (!tb[TCA_ACT_BPF_PARMS]) {
 171                fprintf(stderr, "Missing bpf parameters\n");
 172                return -1;
 173        }
 174
 175        parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]);
 176
 177        if (tb[TCA_ACT_BPF_NAME])
 178                print_string(PRINT_ANY, "bpf_name", "%s ",
 179                             rta_getattr_str(tb[TCA_ACT_BPF_NAME]));
 180        if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) {
 181                bpf_print_ops(tb[TCA_ACT_BPF_OPS],
 182                              rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN]));
 183                print_string(PRINT_FP, NULL, "%s", " ");
 184        }
 185
 186        if (tb[TCA_ACT_BPF_ID])
 187                d_ok = bpf_dump_prog_info(f,
 188                                          rta_getattr_u32(tb[TCA_ACT_BPF_ID]));
 189        if (!d_ok && tb[TCA_ACT_BPF_TAG]) {
 190                SPRINT_BUF(b);
 191
 192                print_string(PRINT_ANY, "tag", "tag %s ",
 193                             hexstring_n2a(RTA_DATA(tb[TCA_ACT_BPF_TAG]),
 194                             RTA_PAYLOAD(tb[TCA_ACT_BPF_TAG]),
 195                             b, sizeof(b)));
 196        }
 197
 198        print_action_control(f, "default-action ", parm->action, _SL_);
 199        print_uint(PRINT_ANY, "index", "\t index %u", parm->index);
 200        print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt);
 201        print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt);
 202
 203        if (show_stats) {
 204                if (tb[TCA_ACT_BPF_TM]) {
 205                        struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]);
 206
 207                        print_tm(f, tm);
 208                }
 209        }
 210
 211        fprintf(f, "\n ");
 212        return 0;
 213}
 214
 215struct action_util bpf_action_util = {
 216        .id             = "bpf",
 217        .parse_aopt     = bpf_parse_opt,
 218        .print_aopt     = bpf_print_opt,
 219};
 220