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