]> git.ipfire.org Git - thirdparty/iproute2.git/blame - tc/m_mirred.c
tc: make action_util arg const
[thirdparty/iproute2.git] / tc / m_mirred.c
CommitLineData
b3a091d1 1/* SPDX-License-Identifier: GPL-2.0-or-later */
00fa8480 2/*
ae665a52 3 * m_egress.c ingress/egress packet mirror/redir actions module
00fa8480 4 *
ae665a52
SH
5 * Authors: J Hadi Salim (hadi@cyberus.ca)
6 *
00fa8480 7 * TODO: Add Ingress support
00fa8480 8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <unistd.h>
00fa8480 13#include <fcntl.h>
14#include <sys/socket.h>
15#include <netinet/in.h>
16#include <arpa/inet.h>
17#include <string.h>
18#include "utils.h"
19#include "tc_util.h"
c1027a75 20#include "tc_common.h"
00fa8480 21#include <linux/tc_act/tc_mirred.h>
22
00fa8480 23static void
24explain(void)
25{
c6a656f4 26 fprintf(stderr,
139a7413 27 "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <TARGET>\n"
c6a656f4
SH
28 "where:\n"
29 "\tDIRECTION := <ingress | egress>\n"
30 "\tACTION := <mirror | redirect>\n"
31 "\tINDEX is the specific policy instance id\n"
139a7413
VN
32 "\tTARGET := <BLOCK | DEVICE>\n"
33 "\tDEVICE := dev DEVICENAME\n"
34 "\tDEVICENAME is the devicename\n"
35 "\tBLOCK := blockid BLOCKID\n"
36 "\tBLOCKID := 32-bit unsigned block ID\n");
00fa8480 37}
38
ebf32083
JHS
39static void
40usage(void)
41{
42 explain();
43 exit(-1);
44}
00fa8480 45
d1f28cf1 46static const char *mirred_n2a(int action)
00fa8480 47{
48 switch (action) {
49 case TCA_EGRESS_REDIR:
50 return "Egress Redirect";
51 case TCA_INGRESS_REDIR:
52 return "Ingress Redirect";
53 case TCA_EGRESS_MIRROR:
54 return "Egress Mirror";
55 case TCA_INGRESS_MIRROR:
56 return "Ingress Mirror";
57 default:
58 return "unknown";
59 }
60}
61
502c4adf
JP
62static const char *mirred_direction(int action)
63{
64 switch (action) {
65 case TCA_EGRESS_REDIR:
66 case TCA_EGRESS_MIRROR:
67 return "egress";
68 case TCA_INGRESS_REDIR:
69 case TCA_INGRESS_MIRROR:
70 return "ingress";
71 default:
72 return "unknown";
73 }
74}
75
76static const char *mirred_action(int action)
77{
78 switch (action) {
79 case TCA_EGRESS_REDIR:
80 case TCA_INGRESS_REDIR:
81 return "redirect";
82 case TCA_EGRESS_MIRROR:
83 case TCA_INGRESS_MIRROR:
84 return "mirror";
85 default:
86 return "unknown";
87 }
88}
89
d1f28cf1 90static int
38b0e6c1 91parse_direction(const struct action_util *a, int *argc_p, char ***argv_p,
5eca0a37 92 int tca_id, struct nlmsghdr *n)
00fa8480 93{
94
95 int argc = *argc_p;
96 char **argv = *argv_p;
5eca0a37 97 int ok = 0, iok = 0, mirror = 0, redir = 0, ingress = 0, egress = 0;
d17b136f 98 struct tc_mirred p = {};
00fa8480 99 struct rtattr *tail;
b317557f 100 char d[IFNAMSIZ] = {};
139a7413 101 __u32 blockid = 0;
00fa8480 102
103 while (argc > 0) {
104
105 if (matches(*argv, "action") == 0) {
75ef7b18 106 NEXT_ARG();
00fa8480 107 break;
5eca0a37
SL
108 } else if (!egress && matches(*argv, "egress") == 0) {
109 egress = 1;
110 if (ingress) {
c6a656f4
SH
111 fprintf(stderr,
112 "Can't have both egress and ingress\n");
5eca0a37
SL
113 return -1;
114 }
115 NEXT_ARG();
116 ok++;
117 continue;
118 } else if (!ingress && matches(*argv, "ingress") == 0) {
119 ingress = 1;
120 if (egress) {
c6a656f4
SH
121 fprintf(stderr,
122 "Can't have both ingress and egress\n");
5eca0a37
SL
123 return -1;
124 }
00fa8480 125 NEXT_ARG();
126 ok++;
127 continue;
128 } else {
129
130 if (matches(*argv, "index") == 0) {
131 NEXT_ARG();
132 if (get_u32(&p.index, *argv, 10)) {
133 fprintf(stderr, "Illegal \"index\"\n");
134 return -1;
135 }
136 iok++;
137 if (!ok) {
138 argc--;
139 argv++;
140 break;
141 }
32a121cb 142 } else if (!ok) {
c6a656f4
SH
143 fprintf(stderr,
144 "was expecting egress or ingress (%s)\n",
145 *argv);
00fa8480 146 break;
147
148 } else if (!mirror && matches(*argv, "mirror") == 0) {
32a121cb 149 mirror = 1;
00fa8480 150 if (redir) {
c6a656f4
SH
151 fprintf(stderr,
152 "Can't have both mirror and redir\n");
00fa8480 153 return -1;
154 }
5eca0a37 155 p.eaction = egress ? TCA_EGRESS_MIRROR :
c6a656f4 156 TCA_INGRESS_MIRROR;
00fa8480 157 p.action = TC_ACT_PIPE;
158 ok++;
159 } else if (!redir && matches(*argv, "redirect") == 0) {
32a121cb 160 redir = 1;
00fa8480 161 if (mirror) {
c6a656f4
SH
162 fprintf(stderr,
163 "Can't have both mirror and redir\n");
00fa8480 164 return -1;
165 }
5eca0a37 166 p.eaction = egress ? TCA_EGRESS_REDIR :
c6a656f4 167 TCA_INGRESS_REDIR;
00fa8480 168 p.action = TC_ACT_STOLEN;
169 ok++;
139a7413
VN
170 } else if ((redir || mirror)) {
171 if (strcmp(*argv, "blockid") == 0) {
172 if (strlen(d)) {
173 fprintf(stderr,
174 "blockid and device are mutually exclusive.\n");
175 return -1;
176 }
177 NEXT_ARG();
178 if (get_u32(&blockid, *argv, 0) ||
179 !blockid) {
180 fprintf(stderr,
181 "invalid block ID");
182 return -1;
183 }
184 argc--;
185 argv++;
186 }
187 if (argc && matches(*argv, "dev") == 0) {
188 if (blockid) {
189 fprintf(stderr,
190 "blockid and device are mutually exclusive.\n");
191 return -1;
192 }
193 NEXT_ARG();
194 if (strlen(d))
195 duparg("dev", *argv);
196
197 strncpy(d, *argv, sizeof(d)-1);
198 argc--;
199 argv++;
200 }
00fa8480 201
202 break;
203
204 }
205 }
206
207 NEXT_ARG();
208 }
209
c6a656f4 210 if (!ok && !iok)
00fa8480 211 return -1;
00fa8480 212
213 if (d[0]) {
214 int idx;
32a121cb 215
00fa8480 216 ll_init_map(&rth);
217
c6a656f4 218 idx = ll_name_to_index(d);
fe99adbc
SP
219 if (!idx)
220 return nodev(d);
00fa8480 221
222 p.ifindex = idx;
00fa8480 223 }
224
225
75ef7b18 226 if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
6eccf7ec
PA
227 parse_action_control_dflt(&argc, &argv, &p.action, false,
228 TC_ACT_PIPE);
00fa8480 229
230 if (argc) {
231 if (iok && matches(*argv, "index") == 0) {
232 fprintf(stderr, "mirred: Illegal double index\n");
233 return -1;
c6a656f4
SH
234 }
235
236 if (matches(*argv, "index") == 0) {
237 NEXT_ARG();
238 if (get_u32(&p.index, *argv, 10)) {
239 fprintf(stderr,
240 "mirred: Illegal \"index\"\n");
241 return -1;
00fa8480 242 }
c6a656f4
SH
243 argc--;
244 argv++;
00fa8480 245 }
246 }
247
c14f9d92 248 tail = addattr_nest(n, MAX_MSG, tca_id);
32a121cb 249 addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p));
139a7413
VN
250 if (blockid)
251 addattr32(n, MAX_MSG, TCA_MIRRED_BLOCKID, blockid);
c14f9d92 252 addattr_nest_end(n, tail);
00fa8480 253
254 *argc_p = argc;
255 *argv_p = argv;
256 return 0;
257}
258
259
d1f28cf1 260static int
38b0e6c1 261parse_mirred(const struct action_util *a, int *argc_p, char ***argv_p,
d1f28cf1 262 int tca_id, struct nlmsghdr *n)
00fa8480 263{
264
265 int argc = *argc_p;
266 char **argv = *argv_p;
267
268 if (argc < 0) {
32a121cb 269 fprintf(stderr, "mirred bad argument count %d\n", argc);
00fa8480 270 return -1;
271 }
272
273 if (matches(*argv, "mirred") == 0) {
274 NEXT_ARG();
275 } else {
32a121cb 276 fprintf(stderr, "mirred bad argument %s\n", *argv);
00fa8480 277 return -1;
278 }
279
280
5eca0a37
SL
281 if (matches(*argv, "egress") == 0 || matches(*argv, "ingress") == 0 ||
282 matches(*argv, "index") == 0) {
283 int ret = parse_direction(a, &argc, &argv, tca_id, n);
32a121cb 284
00fa8480 285 if (ret == 0) {
286 *argc_p = argc;
287 *argv_p = argv;
288 return 0;
289 }
290
ebf32083
JHS
291 } else if (matches(*argv, "help") == 0) {
292 usage();
00fa8480 293 } else {
32a121cb 294 fprintf(stderr, "mirred option not supported %s\n", *argv);
00fa8480 295 }
296
297 return -1;
ae665a52 298
00fa8480 299}
300
d1f28cf1 301static int
38b0e6c1 302print_mirred(const struct action_util *au, FILE *f, struct rtattr *arg)
00fa8480 303{
304 struct tc_mirred *p;
305 struct rtattr *tb[TCA_MIRRED_MAX + 1];
00fa8480 306 const char *dev;
32a121cb 307
a99ebeee 308 print_string(PRINT_ANY, "kind", "%s ", "mirred");
00fa8480 309 if (arg == NULL)
a99ebeee 310 return 0;
00fa8480 311
5cb5ee34 312 parse_rtattr_nested(tb, TCA_MIRRED_MAX, arg);
00fa8480 313
314 if (tb[TCA_MIRRED_PARMS] == NULL) {
d5ddb441 315 fprintf(stderr, "Missing mirred parameters\n");
00fa8480 316 return -1;
317 }
318 p = RTA_DATA(tb[TCA_MIRRED_PARMS]);
319
c6a656f4
SH
320 dev = ll_index_to_name(p->ifindex);
321 if (dev == 0) {
00fa8480 322 fprintf(stderr, "Cannot find device %d\n", p->ifindex);
00fa8480 323 return -1;
324 }
325
502c4adf
JP
326 print_string(PRINT_FP, NULL, "(%s", mirred_n2a(p->eaction));
327 print_string(PRINT_JSON, "mirred_action", NULL,
328 mirred_action(p->eaction));
329 print_string(PRINT_JSON, "direction", NULL,
330 mirred_direction(p->eaction));
139a7413
VN
331 if (tb[TCA_MIRRED_BLOCKID]) {
332 const __u32 *blockid = RTA_DATA(tb[TCA_MIRRED_BLOCKID]);
333
334 print_uint(PRINT_ANY, "to_blockid", " to blockid %u)",
335 *blockid);
336 } else {
337 print_string(PRINT_ANY, "to_dev", " to device %s)", dev);
338 }
339
e67aba55 340 print_action_control(f, " ", p->action, "");
00fa8480 341
7b0d424a
SH
342 print_nl();
343 print_uint(PRINT_ANY, "index", "\tindex %u", p->index);
502c4adf
JP
344 print_int(PRINT_ANY, "ref", " ref %d", p->refcnt);
345 print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt);
00fa8480 346
347 if (show_stats) {
348 if (tb[TCA_MIRRED_TM]) {
349 struct tcf_t *tm = RTA_DATA(tb[TCA_MIRRED_TM]);
32a121cb
SH
350
351 print_tm(f, tm);
00fa8480 352 }
353 }
7b0d424a 354 print_nl();
00fa8480 355 return 0;
356}
357
6ce88ca6 358struct action_util mirred_action_util = {
00fa8480 359 .id = "mirred",
360 .parse_aopt = parse_mirred,
361 .print_aopt = print_mirred,
362};