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