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