]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/m_mirred.c
Import patch mirred.patch
[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 <syslog.h>
19 #include <fcntl.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <string.h>
24 #include "utils.h"
25 #include "tc_util.h"
26 #include <linux/tc_act/tc_mirred.h>
27
28 int mirred_d = 1;
29
30 static void
31 explain(void)
32 {
33 fprintf(stderr, "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME> \n");
34 fprintf(stderr, "where: \n");
35 fprintf(stderr, "DIRECTION := <ingress | egress>\n");
36 fprintf(stderr, "aCTION := <mirror | redirect>\n");
37 fprintf(stderr, " : INDEX is the specific policy instance id\n");
38 fprintf(stderr, " : DEVICENAME is the devicename \n");
39 }
40
41 #define usage() return(-1)
42
43 char *mirred_n2a(int action)
44 {
45 switch (action) {
46 case TCA_EGRESS_REDIR:
47 return "Egress Redirect";
48 case TCA_INGRESS_REDIR:
49 return "Ingress Redirect";
50 case TCA_EGRESS_MIRROR:
51 return "Egress Mirror";
52 case TCA_INGRESS_MIRROR:
53 return "Ingress Mirror";
54 default:
55 return "unknown";
56 }
57 }
58
59 int
60 parse_egress(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
61 {
62
63 int argc = *argc_p;
64 char **argv = *argv_p;
65 int ok = 0, iok = 0, mirror=0,redir=0;
66 struct tc_mirred p;
67 struct rtattr *tail;
68 char d[16];
69 struct rtnl_handle rth;
70
71 memset(d,0,sizeof(d)-1);
72 memset(&p,0,sizeof(struct tc_mirred));
73
74 while (argc > 0) {
75
76 if (matches(*argv, "action") == 0) {
77 break;
78 } else if (matches(*argv, "egress") == 0) {
79 NEXT_ARG();
80 ok++;
81 continue;
82 } else {
83
84 if (matches(*argv, "index") == 0) {
85 NEXT_ARG();
86 if (get_u32(&p.index, *argv, 10)) {
87 fprintf(stderr, "Illegal \"index\"\n");
88 return -1;
89 }
90 iok++;
91 if (!ok) {
92 argc--;
93 argv++;
94 break;
95 }
96 } else if(!ok) {
97 fprintf(stderr, "was expecting egress (%s)\n", *argv);
98 break;
99
100 } else if (!mirror && matches(*argv, "mirror") == 0) {
101 mirror=1;
102 if (redir) {
103 fprintf(stderr, "Cant have both mirror and redir\n");
104 return -1;
105 }
106 p.eaction = TCA_EGRESS_MIRROR;
107 p.action = TC_ACT_PIPE;
108 ok++;
109 } else if (!redir && matches(*argv, "redirect") == 0) {
110 redir=1;
111 if (mirror) {
112 fprintf(stderr, "Cant have both mirror and redir\n");
113 return -1;
114 }
115 p.eaction = TCA_EGRESS_REDIR;
116 p.action = TC_ACT_STOLEN;
117 ok++;
118 } else if ((redir || mirror) && matches(*argv, "dev") == 0) {
119 NEXT_ARG();
120 if (strlen(d))
121 duparg("dev", *argv);
122
123 strncpy(d, *argv, sizeof(d)-1);
124 argc--;
125 argv++;
126
127 break;
128
129 }
130 }
131
132 NEXT_ARG();
133 }
134
135 if (!ok && !iok) {
136 explain();
137 return -1;
138 }
139
140
141
142 if (d[0]) {
143 int idx;
144 if (rtnl_open(&rth, 0) < 0) {
145 fprintf(stderr, "Cannot open rtnetlink\n");
146 exit(1);
147 }
148 ll_init_map(&rth);
149
150
151 if ((idx = ll_name_to_index(d)) == 0) {
152 fprintf(stderr, "Cannot find device \"%s\"\n", d);
153 rtnl_close(&rth);
154 return -1;
155 }
156
157 p.ifindex = idx;
158 rtnl_close(&rth);
159 }
160
161
162 if (argc && p.eaction == TCA_EGRESS_MIRROR) {
163
164 if (matches(*argv, "reclassify") == 0) {
165 p.action = TC_POLICE_RECLASSIFY;
166 NEXT_ARG();
167 } else if (matches(*argv, "pipe") == 0) {
168 p.action = TC_POLICE_PIPE;
169 NEXT_ARG();
170 } else if (matches(*argv, "drop") == 0 ||
171 matches(*argv, "shot") == 0) {
172 p.action = TC_POLICE_SHOT;
173 NEXT_ARG();
174 } else if (matches(*argv, "continue") == 0) {
175 p.action = TC_POLICE_UNSPEC;
176 NEXT_ARG();
177 } else if (matches(*argv, "pass") == 0) {
178 p.action = TC_POLICE_OK;
179 NEXT_ARG();
180 }
181
182 }
183
184 if (argc) {
185 if (iok && matches(*argv, "index") == 0) {
186 fprintf(stderr, "mirred: Illegal double index\n");
187 return -1;
188 } else {
189 if (matches(*argv, "index") == 0) {
190 NEXT_ARG();
191 if (get_u32(&p.index, *argv, 10)) {
192 fprintf(stderr, "mirred: Illegal \"index\"\n");
193 return -1;
194 }
195 argc--;
196 argv++;
197 }
198 }
199 }
200
201 if (mirred_d)
202 fprintf(stdout, "Action %d device %s ifindex %d\n",p.action, d,p.ifindex);
203
204 tail = (struct rtattr *) (((void *) n) + NLMSG_ALIGN(n->nlmsg_len));
205 addattr_l(n, MAX_MSG, tca_id, NULL, 0);
206 addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof (p));
207 tail->rta_len =
208 (((void *) n) + NLMSG_ALIGN(n->nlmsg_len)) - (void *) tail;
209
210 *argc_p = argc;
211 *argv_p = argv;
212 return 0;
213 }
214
215
216 int
217 parse_mirred(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
218 {
219
220 int argc = *argc_p;
221 char **argv = *argv_p;
222
223 if (argc < 0) {
224 fprintf(stderr,"mirred bad arguement count %d\n", argc);
225 return -1;
226 }
227
228 if (matches(*argv, "mirred") == 0) {
229 NEXT_ARG();
230 } else {
231 fprintf(stderr,"mirred bad arguement %s\n", *argv);
232 return -1;
233 }
234
235
236 if (matches(*argv, "egress") == 0 || matches(*argv, "index") == 0) {
237 int ret = parse_egress(a, &argc, &argv, tca_id, n);
238 if (ret == 0) {
239 *argc_p = argc;
240 *argv_p = argv;
241 return 0;
242 }
243
244 } else if (matches(*argv, "ingress") == 0) {
245 fprintf(stderr,"mirred ingress not supported at the moment\n");
246
247 } else {
248 fprintf(stderr,"mirred not supported %s\n", *argv);
249 }
250
251 return -1;
252
253 }
254
255 int
256 print_mirred(struct action_util *au,FILE * f, struct rtattr *arg)
257 {
258 struct tc_mirred *p;
259 struct rtattr *tb[TCA_MIRRED_MAX + 1];
260 struct rtnl_handle rth;
261 const char *dev;
262 SPRINT_BUF(b1);
263
264 if (arg == NULL)
265 return -1;
266
267 memset(tb, 0, sizeof (tb));
268 parse_rtattr(tb, TCA_MIRRED_MAX, RTA_DATA(arg), RTA_PAYLOAD(arg));
269
270 if (tb[TCA_MIRRED_PARMS] == NULL) {
271 fprintf(f, "[NULL mirred parameters]");
272 return -1;
273 }
274 p = RTA_DATA(tb[TCA_MIRRED_PARMS]);
275
276 if (rtnl_open(&rth, 0) < 0) {
277 fprintf(stderr, "Cannot open rtnetlink\n");
278 return -1;
279 }
280
281 ll_init_map(&rth);
282
283
284 if ((dev = ll_index_to_name(p->ifindex)) == 0) {
285 fprintf(stderr, "Cannot find device %d\n", p->ifindex);
286 rtnl_close(&rth);
287 return -1;
288 }
289
290 fprintf(f, "mirred (%s to device %s) %s", mirred_n2a(p->eaction), dev,action_n2a(p->action, b1, sizeof (b1)));
291
292 fprintf(f, "\n ");
293 fprintf(f, "\tindex %d ref %d bind %d",p->index,p->refcnt,p->bindcnt);
294
295 if (show_stats) {
296 if (tb[TCA_MIRRED_TM]) {
297 struct tcf_t *tm = RTA_DATA(tb[TCA_MIRRED_TM]);
298 print_tm(f,tm);
299 }
300 }
301 fprintf(f, "\n ");
302 rtnl_close(&rth);
303 return 0;
304 }
305
306 struct action_util mirred_util = {
307 .id = "mirred",
308 .parse_aopt = parse_mirred,
309 .print_aopt = print_mirred,
310 };