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#include "tc_util.h" 21#include "tc_bpf.h" 22 23static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_ACT; 24 25static const int nla_tbl[BPF_NLA_MAX] = { 26 [BPF_NLA_OPS_LEN] = TCA_ACT_BPF_OPS_LEN, 27 [BPF_NLA_OPS] = TCA_ACT_BPF_OPS, 28 [BPF_NLA_FD] = TCA_ACT_BPF_FD, 29 [BPF_NLA_NAME] = TCA_ACT_BPF_NAME, 30}; 31 32static void explain(void) 33{ 34 fprintf(stderr, "Usage: ... bpf ... [ index INDEX ]\n"); 35 fprintf(stderr, "\n"); 36 fprintf(stderr, "BPF use case:\n"); 37 fprintf(stderr, " bytecode BPF_BYTECODE\n"); 38 fprintf(stderr, " bytecode-file FILE\n"); 39 fprintf(stderr, "\n"); 40 fprintf(stderr, "eBPF use case:\n"); 41 fprintf(stderr, " object-file FILE [ section ACT_NAME ] [ export UDS_FILE ]"); 42 fprintf(stderr, " [ verbose ]\n"); 43 fprintf(stderr, " object-pinned FILE\n"); 44 fprintf(stderr, "\n"); 45 fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n"); 46 fprintf(stderr, "c,t,f,k and s are decimals; s denotes number of 4-tuples\n"); 47 fprintf(stderr, "\n"); 48 fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string,\n"); 49 fprintf(stderr, "an ELF file containing eBPF map definitions and bytecode, or a\n"); 50 fprintf(stderr, "pinned eBPF program.\n"); 51 fprintf(stderr, "\n"); 52 fprintf(stderr, "Where ACT_NAME refers to the section name containing the\n"); 53 fprintf(stderr, "action (default \'%s\').\n", bpf_default_section(bpf_type)); 54 fprintf(stderr, "\n"); 55 fprintf(stderr, "Where UDS_FILE points to a unix domain socket file in order\n"); 56 fprintf(stderr, "to hand off control of all created eBPF maps to an agent.\n"); 57 fprintf(stderr, "\n"); 58 fprintf(stderr, "Where optionally INDEX points to an existing action, or\n"); 59 fprintf(stderr, "explicitly specifies an action index upon creation.\n"); 60} 61 62static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv, 63 int tca_id, struct nlmsghdr *n) 64{ 65 const char *bpf_obj = NULL, *bpf_uds_name = NULL; 66 struct tc_act_bpf parm; 67 bool seen_run = false; 68 struct rtattr *tail; 69 int argc, ret = 0; 70 char **argv; 71 72 argv = *ptr_argv; 73 argc = *ptr_argc; 74 75 if (matches(*argv, "bpf") != 0) 76 return -1; 77 78 NEXT_ARG(); 79 80 tail = NLMSG_TAIL(n); 81 addattr_l(n, MAX_MSG, tca_id, NULL, 0); 82 83 while (argc > 0) { 84 if (matches(*argv, "run") == 0) { 85 NEXT_ARG(); 86opt_bpf: 87 seen_run = true; 88 if (bpf_parse_common(&argc, &argv, nla_tbl, bpf_type, 89 &bpf_obj, &bpf_uds_name, n)) { 90 fprintf(stderr, "Failed to retrieve (e)BPF data!\n"); 91 return -1; 92 } 93 } else if (matches(*argv, "help") == 0) { 94 explain(); 95 return -1; 96 } else if (matches(*argv, "index") == 0) { 97 break; 98 } else { 99 if (!seen_run) 100 goto opt_bpf; 101 break; 102 } 103 104 NEXT_ARG_FWD(); 105 } 106 107 memset(&parm, 0, sizeof(parm)); 108 parm.action = TC_ACT_PIPE; 109 110 if (argc) { 111 if (matches(*argv, "reclassify") == 0) { 112 parm.action = TC_ACT_RECLASSIFY; 113 NEXT_ARG_FWD(); 114 } else if (matches(*argv, "pipe") == 0) { 115 parm.action = TC_ACT_PIPE; 116 NEXT_ARG_FWD(); 117 } else if (matches(*argv, "drop") == 0 || 118 matches(*argv, "shot") == 0) { 119 parm.action = TC_ACT_SHOT; 120 NEXT_ARG_FWD(); 121 } else if (matches(*argv, "continue") == 0) { 122 parm.action = TC_ACT_UNSPEC; 123 NEXT_ARG_FWD(); 124 } else if (matches(*argv, "pass") == 0 || 125 matches(*argv, "ok") == 0) { 126 parm.action = TC_ACT_OK; 127 NEXT_ARG_FWD(); 128 } 129 } 130 131 if (argc) { 132 if (matches(*argv, "index") == 0) { 133 NEXT_ARG(); 134 if (get_u32(&parm.index, *argv, 10)) { 135 fprintf(stderr, "bpf: Illegal \"index\"\n"); 136 return -1; 137 } 138 139 NEXT_ARG_FWD(); 140 } 141 } 142 143 addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm)); 144 tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; 145 146 if (bpf_uds_name) 147 ret = bpf_send_map_fds(bpf_uds_name, bpf_obj); 148 149 *ptr_argc = argc; 150 *ptr_argv = argv; 151 152 return ret; 153} 154 155static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg) 156{ 157 struct rtattr *tb[TCA_ACT_BPF_MAX + 1]; 158 struct tc_act_bpf *parm; 159 SPRINT_BUF(action_buf); 160 161 if (arg == NULL) 162 return -1; 163 164 parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg); 165 166 if (!tb[TCA_ACT_BPF_PARMS]) { 167 fprintf(f, "[NULL bpf parameters]"); 168 return -1; 169 } 170 171 parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]); 172 fprintf(f, "bpf "); 173 174 if (tb[TCA_ACT_BPF_NAME]) 175 fprintf(f, "%s ", rta_getattr_str(tb[TCA_ACT_BPF_NAME])); 176 else if (tb[TCA_ACT_BPF_FD]) 177 fprintf(f, "pfd %u ", rta_getattr_u32(tb[TCA_ACT_BPF_FD])); 178 179 if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) { 180 bpf_print_ops(f, tb[TCA_ACT_BPF_OPS], 181 rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN])); 182 fprintf(f, " "); 183 } 184 185 fprintf(f, "default-action %s\n", action_n2a(parm->action, action_buf, 186 sizeof(action_buf))); 187 fprintf(f, "\tindex %d ref %d bind %d", parm->index, parm->refcnt, 188 parm->bindcnt); 189 190 if (show_stats) { 191 if (tb[TCA_ACT_BPF_TM]) { 192 struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]); 193 print_tm(f, tm); 194 } 195 } 196 197 fprintf(f, "\n "); 198 return 0; 199} 200 201struct action_util bpf_action_util = { 202 .id = "bpf", 203 .parse_aopt = bpf_parse_opt, 204 .print_aopt = bpf_print_opt, 205}; 206