]>
Commit | Line | Data |
---|---|---|
86ab59a6 JP |
1 | /* |
2 | * m_bpf.c BFP 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 | */ | |
11 | ||
12 | #include <stdio.h> | |
13 | #include <stdlib.h> | |
14 | #include <unistd.h> | |
15 | #include <string.h> | |
16 | #include <stdbool.h> | |
17 | #include <linux/tc_act/tc_bpf.h> | |
18 | ||
19 | #include "utils.h" | |
20 | #include "rt_names.h" | |
21 | #include "tc_util.h" | |
22 | #include "tc_bpf.h" | |
23 | ||
24 | static void explain(void) | |
25 | { | |
26 | fprintf(stderr, "Usage: ... bpf ...\n"); | |
27 | fprintf(stderr, "\n"); | |
28 | fprintf(stderr, " [inline]: run bytecode BPF_BYTECODE\n"); | |
29 | fprintf(stderr, " [from file]: run bytecode-file FILE\n"); | |
30 | fprintf(stderr, "\n"); | |
31 | fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n"); | |
32 | fprintf(stderr, " c,t,f,k and s are decimals; s denotes number of 4-tuples\n"); | |
33 | fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string\n"); | |
86ab59a6 JP |
34 | } |
35 | ||
36 | static void usage(void) | |
37 | { | |
38 | explain(); | |
39 | exit(-1); | |
40 | } | |
41 | ||
42 | static int parse_bpf(struct action_util *a, int *argc_p, char ***argv_p, | |
43 | int tca_id, struct nlmsghdr *n) | |
44 | { | |
45 | int argc = *argc_p; | |
46 | char **argv = *argv_p; | |
47 | struct rtattr *tail; | |
48 | struct tc_act_bpf parm = { 0 }; | |
49 | struct sock_filter bpf_ops[BPF_MAXINSNS]; | |
50 | __u16 bpf_len = 0; | |
51 | ||
52 | if (matches(*argv, "bpf") != 0) | |
53 | return -1; | |
54 | ||
55 | NEXT_ARG(); | |
56 | ||
57 | while (argc > 0) { | |
58 | if (matches(*argv, "run") == 0) { | |
59 | bool from_file; | |
60 | int ret; | |
61 | ||
62 | NEXT_ARG(); | |
63 | if (strcmp(*argv, "bytecode-file") == 0) { | |
64 | from_file = true; | |
65 | } else if (strcmp(*argv, "bytecode") == 0) { | |
66 | from_file = false; | |
67 | } else { | |
68 | fprintf(stderr, "unexpected \"%s\"\n", *argv); | |
69 | explain(); | |
70 | return -1; | |
71 | } | |
72 | NEXT_ARG(); | |
73 | ret = bpf_parse_ops(argc, argv, bpf_ops, from_file); | |
74 | if (ret < 0) { | |
75 | fprintf(stderr, "Illegal \"bytecode\"\n"); | |
76 | return -1; | |
77 | } | |
78 | bpf_len = ret; | |
79 | } else if (matches(*argv, "help") == 0) { | |
80 | usage(); | |
81 | } else { | |
82 | break; | |
83 | } | |
84 | argc--; | |
85 | argv++; | |
86 | } | |
87 | ||
88 | parm.action = TC_ACT_PIPE; | |
89 | if (argc) { | |
90 | if (matches(*argv, "reclassify") == 0) { | |
91 | parm.action = TC_ACT_RECLASSIFY; | |
51cf3675 DB |
92 | argc--; |
93 | argv++; | |
86ab59a6 JP |
94 | } else if (matches(*argv, "pipe") == 0) { |
95 | parm.action = TC_ACT_PIPE; | |
51cf3675 DB |
96 | argc--; |
97 | argv++; | |
86ab59a6 JP |
98 | } else if (matches(*argv, "drop") == 0 || |
99 | matches(*argv, "shot") == 0) { | |
100 | parm.action = TC_ACT_SHOT; | |
51cf3675 DB |
101 | argc--; |
102 | argv++; | |
86ab59a6 JP |
103 | } else if (matches(*argv, "continue") == 0) { |
104 | parm.action = TC_ACT_UNSPEC; | |
51cf3675 DB |
105 | argc--; |
106 | argv++; | |
86ab59a6 JP |
107 | } else if (matches(*argv, "pass") == 0) { |
108 | parm.action = TC_ACT_OK; | |
51cf3675 DB |
109 | argc--; |
110 | argv++; | |
86ab59a6 JP |
111 | } |
112 | } | |
113 | ||
114 | if (argc) { | |
115 | if (matches(*argv, "index") == 0) { | |
116 | NEXT_ARG(); | |
117 | if (get_u32(&parm.index, *argv, 10)) { | |
118 | fprintf(stderr, "bpf: Illegal \"index\"\n"); | |
119 | return -1; | |
120 | } | |
121 | argc--; | |
122 | argv++; | |
123 | } | |
124 | } | |
125 | ||
126 | if (!bpf_len) { | |
127 | fprintf(stderr, "bpf: Bytecode needs to be passed\n"); | |
128 | explain(); | |
129 | return -1; | |
130 | } | |
131 | ||
132 | tail = NLMSG_TAIL(n); | |
133 | addattr_l(n, MAX_MSG, tca_id, NULL, 0); | |
134 | addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm)); | |
135 | addattr16(n, MAX_MSG, TCA_ACT_BPF_OPS_LEN, bpf_len); | |
136 | addattr_l(n, MAX_MSG, TCA_ACT_BPF_OPS, &bpf_ops, | |
137 | bpf_len * sizeof(struct sock_filter)); | |
138 | tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; | |
139 | ||
140 | *argc_p = argc; | |
141 | *argv_p = argv; | |
142 | return 0; | |
143 | } | |
144 | ||
145 | static int print_bpf(struct action_util *au, FILE *f, struct rtattr *arg) | |
146 | { | |
147 | struct rtattr *tb[TCA_ACT_BPF_MAX + 1]; | |
148 | struct tc_act_bpf *parm; | |
149 | ||
150 | if (arg == NULL) | |
151 | return -1; | |
152 | ||
153 | parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg); | |
154 | ||
155 | if (!tb[TCA_ACT_BPF_PARMS]) { | |
156 | fprintf(f, "[NULL bpf parameters]"); | |
157 | return -1; | |
158 | } | |
159 | parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]); | |
160 | ||
161 | fprintf(f, " bpf "); | |
162 | ||
163 | if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) | |
164 | bpf_print_ops(f, tb[TCA_ACT_BPF_OPS], | |
165 | rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN])); | |
166 | ||
167 | fprintf(f, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt, | |
168 | parm->bindcnt); | |
169 | ||
170 | if (show_stats) { | |
171 | if (tb[TCA_ACT_BPF_TM]) { | |
172 | struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]); | |
173 | print_tm(f, tm); | |
174 | } | |
175 | } | |
176 | ||
177 | fprintf(f, "\n "); | |
178 | ||
179 | return 0; | |
180 | } | |
181 | ||
182 | struct action_util bpf_action_util = { | |
183 | .id = "bpf", | |
184 | .parse_aopt = parse_bpf, | |
185 | .print_aopt = print_bpf, | |
186 | }; |