Tagging module iproute2 - iproute2-2.6.16-2
[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 "tc_common.h"
27 #include <linux/tc_act/tc_mirred.h>
28
29 int mirred_d = 1;
30
31 static void
32 explain(void)
33 {
34         fprintf(stderr, "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME> \n");
35         fprintf(stderr, "where: \n");
36         fprintf(stderr, "DIRECTION := <ingress | egress>\n");
37         fprintf(stderr, "aCTION := <mirror | redirect>\n");
38         fprintf(stderr, "     : INDEX  is the specific policy instance id\n");
39         fprintf(stderr, "     : DEVICENAME is the devicename \n");
40 }
41
42 #define usage() return(-1)
43
44 char *mirred_n2a(int action)
45 {
46         switch (action) {
47         case TCA_EGRESS_REDIR:
48                 return "Egress Redirect";
49         case TCA_INGRESS_REDIR:
50                 return "Ingress Redirect";
51         case TCA_EGRESS_MIRROR:
52                 return "Egress Mirror";
53         case TCA_INGRESS_MIRROR:
54                 return "Ingress Mirror";
55         default:
56                 return "unknown";
57         }
58 }
59
60 int
61 parse_egress(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
62 {
63
64         int argc = *argc_p;
65         char **argv = *argv_p;
66         int ok = 0, iok = 0, mirror=0,redir=0;
67         struct tc_mirred p;
68         struct rtattr *tail;
69         char d[16];
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                 ll_init_map(&rth);
145
146                 if ((idx = ll_name_to_index(d)) == 0) {
147                         fprintf(stderr, "Cannot find device \"%s\"\n", d);
148                         return -1;
149                 }
150
151                 p.ifindex = idx;
152         }
153
154
155         if (argc && p.eaction == TCA_EGRESS_MIRROR) {
156
157                 if (matches(*argv, "reclassify") == 0) {
158                         p.action = TC_POLICE_RECLASSIFY;
159                         NEXT_ARG();
160                 } else if (matches(*argv, "pipe") == 0) {
161                         p.action = TC_POLICE_PIPE;
162                         NEXT_ARG();
163                 } else if (matches(*argv, "drop") == 0 ||
164                            matches(*argv, "shot") == 0) {
165                         p.action = TC_POLICE_SHOT;
166                         NEXT_ARG();
167                 } else if (matches(*argv, "continue") == 0) {
168                         p.action = TC_POLICE_UNSPEC;
169                         NEXT_ARG();
170                 } else if (matches(*argv, "pass") == 0) {
171                         p.action = TC_POLICE_OK;
172                         NEXT_ARG();
173                 }
174
175         }
176
177         if (argc) {
178                 if (iok && matches(*argv, "index") == 0) {
179                         fprintf(stderr, "mirred: Illegal double index\n");
180                         return -1;
181                 } else {
182                         if (matches(*argv, "index") == 0) {
183                                 NEXT_ARG();
184                                 if (get_u32(&p.index, *argv, 10)) {
185                                         fprintf(stderr, "mirred: Illegal \"index\"\n");
186                                         return -1;
187                                 }
188                                 argc--;
189                                 argv++;
190                         }
191                 }
192         }
193
194         if (mirred_d)
195                 fprintf(stdout, "Action %d device %s ifindex %d\n",p.action, d,p.ifindex);
196
197         tail = NLMSG_TAIL(n);
198         addattr_l(n, MAX_MSG, tca_id, NULL, 0);
199         addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof (p));
200         tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
201
202         *argc_p = argc;
203         *argv_p = argv;
204         return 0;
205 }
206
207
208 int
209 parse_mirred(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
210 {
211
212         int argc = *argc_p;
213         char **argv = *argv_p;
214
215         if (argc < 0) {
216                 fprintf(stderr,"mirred bad arguement count %d\n", argc);
217                 return -1;
218         }
219
220         if (matches(*argv, "mirred") == 0) {
221                 NEXT_ARG();
222         } else {
223                 fprintf(stderr,"mirred bad arguement %s\n", *argv);
224                 return -1;
225         }
226
227
228         if (matches(*argv, "egress") == 0 || matches(*argv, "index") == 0) {
229                 int ret = parse_egress(a, &argc, &argv, tca_id, n);
230                 if (ret == 0) {
231                         *argc_p = argc;
232                         *argv_p = argv;
233                         return 0;
234                 }
235
236         } else if (matches(*argv, "ingress") == 0) {
237                 fprintf(stderr,"mirred ingress not supported at the moment\n");
238
239         } else {
240                 fprintf(stderr,"mirred not supported %s\n", *argv);
241         }
242
243         return -1;
244         
245 }
246
247 int
248 print_mirred(struct action_util *au,FILE * f, struct rtattr *arg)
249 {
250         struct tc_mirred *p;
251         struct rtattr *tb[TCA_MIRRED_MAX + 1];
252         const char *dev;
253         SPRINT_BUF(b1);
254
255         if (arg == NULL)
256                 return -1;
257
258         parse_rtattr_nested(tb, TCA_MIRRED_MAX, arg);
259
260         if (tb[TCA_MIRRED_PARMS] == NULL) {
261                 fprintf(f, "[NULL mirred parameters]");
262                 return -1;
263         }
264         p = RTA_DATA(tb[TCA_MIRRED_PARMS]);
265
266         /*
267         ll_init_map(&rth);
268         */
269
270
271         if ((dev = ll_index_to_name(p->ifindex)) == 0) {
272                 fprintf(stderr, "Cannot find device %d\n", p->ifindex);
273                 return -1;
274         }
275
276         fprintf(f, "mirred (%s to device %s) %s", mirred_n2a(p->eaction), dev,action_n2a(p->action, b1, sizeof (b1)));
277
278         fprintf(f, "\n ");
279         fprintf(f, "\tindex %d ref %d bind %d",p->index,p->refcnt,p->bindcnt);
280
281         if (show_stats) {
282                 if (tb[TCA_MIRRED_TM]) {
283                         struct tcf_t *tm = RTA_DATA(tb[TCA_MIRRED_TM]);
284                         print_tm(f,tm);
285                 }
286         }
287         fprintf(f, "\n ");
288         return 0;
289 }
290
291 struct action_util mirred_action_util = {
292         .id = "mirred",
293         .parse_aopt = parse_mirred,
294         .print_aopt = print_mirred,
295 };