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