]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/m_mirred.c
Merge branch 'master' into net-next
[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, "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME>\n");
32 fprintf(stderr, "where:\n");
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");
36 fprintf(stderr, "\tDEVICENAME is the devicename\n");
37
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 int
64 parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
65 int tca_id, struct nlmsghdr *n)
66 {
67
68 int argc = *argc_p;
69 char **argv = *argv_p;
70 int ok = 0, iok = 0, mirror = 0, redir = 0, ingress = 0, egress = 0;
71 struct tc_mirred p = {};
72 struct rtattr *tail;
73 char d[16] = {};
74
75 while (argc > 0) {
76
77 if (matches(*argv, "action") == 0) {
78 break;
79 } else if (!egress && matches(*argv, "egress") == 0) {
80 egress = 1;
81 if (ingress) {
82 fprintf(stderr, "Can't have both egress and ingress\n");
83 return -1;
84 }
85 NEXT_ARG();
86 ok++;
87 continue;
88 } else if (!ingress && matches(*argv, "ingress") == 0) {
89 ingress = 1;
90 if (egress) {
91 fprintf(stderr, "Can't have both ingress and egress\n");
92 return -1;
93 }
94 NEXT_ARG();
95 ok++;
96 continue;
97 } else {
98
99 if (matches(*argv, "index") == 0) {
100 NEXT_ARG();
101 if (get_u32(&p.index, *argv, 10)) {
102 fprintf(stderr, "Illegal \"index\"\n");
103 return -1;
104 }
105 iok++;
106 if (!ok) {
107 argc--;
108 argv++;
109 break;
110 }
111 } else if (!ok) {
112 fprintf(stderr, "was expecting egress or ingress (%s)\n", *argv);
113 break;
114
115 } else if (!mirror && matches(*argv, "mirror") == 0) {
116 mirror = 1;
117 if (redir) {
118 fprintf(stderr, "Can't have both mirror and redir\n");
119 return -1;
120 }
121 p.eaction = egress ? TCA_EGRESS_MIRROR :
122 TCA_INGRESS_MIRROR;
123 p.action = TC_ACT_PIPE;
124 ok++;
125 } else if (!redir && matches(*argv, "redirect") == 0) {
126 redir = 1;
127 if (mirror) {
128 fprintf(stderr, "Can't have both mirror and redir\n");
129 return -1;
130 }
131 p.eaction = egress ? TCA_EGRESS_REDIR :
132 TCA_INGRESS_REDIR;
133 p.action = TC_ACT_STOLEN;
134 ok++;
135 } else if ((redir || mirror) && matches(*argv, "dev") == 0) {
136 NEXT_ARG();
137 if (strlen(d))
138 duparg("dev", *argv);
139
140 strncpy(d, *argv, sizeof(d)-1);
141 argc--;
142 argv++;
143
144 break;
145
146 }
147 }
148
149 NEXT_ARG();
150 }
151
152 if (!ok && !iok) {
153 return -1;
154 }
155
156
157
158 if (d[0]) {
159 int idx;
160
161 ll_init_map(&rth);
162
163 if ((idx = ll_name_to_index(d)) == 0) {
164 fprintf(stderr, "Cannot find device \"%s\"\n", d);
165 return -1;
166 }
167
168 p.ifindex = idx;
169 }
170
171
172 if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
173 parse_action_control(&argc, &argv, &p.action, false);
174
175 if (argc) {
176 if (iok && matches(*argv, "index") == 0) {
177 fprintf(stderr, "mirred: Illegal double index\n");
178 return -1;
179 } else {
180 if (matches(*argv, "index") == 0) {
181 NEXT_ARG();
182 if (get_u32(&p.index, *argv, 10)) {
183 fprintf(stderr, "mirred: Illegal \"index\"\n");
184 return -1;
185 }
186 argc--;
187 argv++;
188 }
189 }
190 }
191
192 tail = NLMSG_TAIL(n);
193 addattr_l(n, MAX_MSG, tca_id, NULL, 0);
194 addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p));
195 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
196
197 *argc_p = argc;
198 *argv_p = argv;
199 return 0;
200 }
201
202
203 static int
204 parse_mirred(struct action_util *a, int *argc_p, char ***argv_p,
205 int tca_id, struct nlmsghdr *n)
206 {
207
208 int argc = *argc_p;
209 char **argv = *argv_p;
210
211 if (argc < 0) {
212 fprintf(stderr, "mirred bad argument count %d\n", argc);
213 return -1;
214 }
215
216 if (matches(*argv, "mirred") == 0) {
217 NEXT_ARG();
218 } else {
219 fprintf(stderr, "mirred bad argument %s\n", *argv);
220 return -1;
221 }
222
223
224 if (matches(*argv, "egress") == 0 || matches(*argv, "ingress") == 0 ||
225 matches(*argv, "index") == 0) {
226 int ret = parse_direction(a, &argc, &argv, tca_id, n);
227
228 if (ret == 0) {
229 *argc_p = argc;
230 *argv_p = argv;
231 return 0;
232 }
233
234 } else if (matches(*argv, "help") == 0) {
235 usage();
236 } else {
237 fprintf(stderr, "mirred option not supported %s\n", *argv);
238 }
239
240 return -1;
241
242 }
243
244 static int
245 print_mirred(struct action_util *au, FILE * f, struct rtattr *arg)
246 {
247 struct tc_mirred *p;
248 struct rtattr *tb[TCA_MIRRED_MAX + 1];
249 const char *dev;
250
251 if (arg == NULL)
252 return -1;
253
254 parse_rtattr_nested(tb, TCA_MIRRED_MAX, arg);
255
256 if (tb[TCA_MIRRED_PARMS] == NULL) {
257 fprintf(f, "[NULL mirred parameters]");
258 return -1;
259 }
260 p = RTA_DATA(tb[TCA_MIRRED_PARMS]);
261
262 /*
263 ll_init_map(&rth);
264 */
265
266
267 if ((dev = ll_index_to_name(p->ifindex)) == 0) {
268 fprintf(stderr, "Cannot find device %d\n", p->ifindex);
269 return -1;
270 }
271
272 fprintf(f, "mirred (%s to device %s)", mirred_n2a(p->eaction), dev);
273 print_action_control(f, " ", p->action, "");
274
275 fprintf(f, "\n ");
276 fprintf(f, "\tindex %u ref %d bind %d", p->index, p->refcnt,
277 p->bindcnt);
278
279 if (show_stats) {
280 if (tb[TCA_MIRRED_TM]) {
281 struct tcf_t *tm = RTA_DATA(tb[TCA_MIRRED_TM]);
282
283 print_tm(f, tm);
284 }
285 }
286 fprintf(f, "\n ");
287 return 0;
288 }
289
290 struct action_util mirred_action_util = {
291 .id = "mirred",
292 .parse_aopt = parse_mirred,
293 .print_aopt = print_mirred,
294 };