1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 13 /* 14 * Copyright (c) 2012 Joyent, Inc. All rights reserved. 15 * Use is subject to license terms. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 #include <values.h> 21 #include <fcntl.h> 22 #include <errno.h> 23 #include <string.h> 24 #include <strings.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <unistd.h> 28 #include <stropts.h> 29 #include <zone.h> 30 #include <libgen.h> 31 #include <assert.h> 32 33 #include <libipd.h> 34 35 static char *g_pname; 36 static char g_zonename[ZONENAME_MAX]; 37 static zoneid_t g_zid; 38 39 #define E_SUCCESS 0 40 #define E_ERROR 1 41 #define E_USAGE 2 42 43 typedef int (*idc_cmd_func_t)(int, char *[]); 44 typedef struct ipdadm_cmd { 45 const char *idc_name; /* subcommand name */ 46 idc_cmd_func_t idc_func; /* subcommand function */ 47 const char *idc_usage; /* subcommand help */ 48 } ipdadm_cmd_t; 49 50 static int ipdadm_list(int, char *[]); 51 static int ipdadm_info(int, char *[]); 52 static int ipdadm_corrupt(int, char *[]); 53 static int ipdadm_delay(int, char *[]); 54 static int ipdadm_drop(int, char *[]); 55 static int ipdadm_remove(int, char *[]); 56 57 #define IPDADM_NCMDS 6 58 static ipdadm_cmd_t ipdadm_cmds[] = { 59 { "list", ipdadm_list, "list [-v]" }, 60 { "info", ipdadm_info, "info" }, 61 { "corrupt", ipdadm_corrupt, "corrupt <percentage>" }, 62 { "delay", ipdadm_delay, "delay <microseconds>" }, 63 { "drop", ipdadm_drop, "drop <percentage>" }, 64 { "remove", ipdadm_remove, "remove [corrupt|delay|drop]" } 65 }; 66 67 static int 68 usage(FILE *fp) 69 { 70 int ii; 71 ipdadm_cmd_t *cmd; 72 73 (void) fprintf(fp, "Usage: %s [-z zonename] subcommand " 74 "[subcommand opts]\n\n", g_pname); 75 (void) fprintf(fp, "Subcommands:\n"); 76 for (ii = 0; ii < IPDADM_NCMDS; ii++) { 77 cmd = &ipdadm_cmds[ii]; 78 (void) fprintf(fp, "\t%s\n", cmd->idc_usage); 79 } 80 81 return (E_USAGE); 82 } 83 84 static void 85 ipdadm_list_one(zoneid_t z, const ipd_config_t *icp, void *arg) 86 { 87 char zonename[ZONENAME_MAX]; 88 int opt_v = (int)(intptr_t)arg; 89 90 if (getzonenamebyid(z, zonename, sizeof (zonename)) < 0) 91 (void) printf("%ld", z); 92 else 93 (void) printf("%s", zonename); 94 95 if (!opt_v) { 96 (void) printf("\n"); 97 return; 98 } 99 100 (void) printf("\t%u\t%u\t%u\n", icp->ic_corrupt, icp->ic_drop, 101 icp->ic_delay); 102 } 103 104 static int 105 ipdadm_list(int argc, char *argv[]) 106 { 107 int opt_v = 0; 108 int fd, rval; 109 ipd_stathdl_t hdl; 110 111 if (argc > 1) 112 return (usage(stderr)); 113 114 if (argc == 1) { 115 if (strcmp(argv[0], "-v") == 0) 116 ++opt_v; 117 else 118 return (usage(stderr)); 119 } 120 121 fd = ipd_open(NULL); 122 rval = ipd_status_read(fd, &hdl); 123 (void) ipd_close(fd); 124 125 if (rval != 0) { 126 (void) fprintf(stderr, "%s: failed to get list info: %s\n", 127 g_pname, ipd_errmsg); 128 return (E_ERROR); 129 } 130 131 ipd_status_foreach_zone(hdl, ipdadm_list_one, (void *)(intptr_t)opt_v); 132 ipd_status_free(hdl); 133 134 return (E_SUCCESS); 135 } 136 137 /*ARGSUSED*/ 138 static int 139 ipdadm_info(int argc, char *argv[]) 140 { 141 int rval, fd; 142 ipd_stathdl_t hdl; 143 ipd_config_t *icp; 144 145 if (argc != 0) 146 return (usage(stderr)); 147 148 fd = ipd_open(NULL); 149 rval = ipd_status_read(fd, &hdl); 150 (void) ipd_close(fd); 151 if (rval != 0) { 152 (void) fprintf(stderr, "%s: failed to get info: %s\n", 153 g_pname, ipd_errmsg); 154 return (E_ERROR); 155 } 156 157 if (ipd_status_get_config(hdl, g_zid, &icp) != 0) { 158 if (ipd_errno == EIPD_ZC_NOENT) { 159 (void) printf("zone %s does not exist or has no " 160 "ipd actions enabled\n", g_zonename); 161 return (E_SUCCESS); 162 } 163 (void) fprintf(stderr, "%s: failed to get info: %s\n", 164 g_pname, ipd_errmsg); 165 return (E_ERROR); 166 } 167 168 (void) printf("ipd information for zone %s:\n", 169 g_zonename); 170 (void) printf("\tcorrupt:\t%u%% chance of packet corruption\n", 171 icp->ic_corrupt); 172 (void) printf("\tdrop:\t\t%u%% chance of packet drop\n", 173 icp->ic_drop); 174 (void) printf("\tdelay:\t\t%u microsecond delay per packet\n", 175 icp->ic_delay); 176 177 ipd_status_free(hdl); 178 179 return (E_SUCCESS); 180 } 181 182 static long 183 ipdadm_parse_long(const char *str, const char *name, long min, long max) 184 { 185 long val; 186 char *end; 187 188 errno = 0; 189 val = strtol(str, &end, 10); 190 if (errno != 0) { 191 (void) fprintf(stderr, "%s: invalid value for %s: %s\n", 192 g_pname, name, str); 193 exit(E_ERROR); 194 } 195 196 /* 197 * We want to make sure that we got the whole string. If not that's an 198 * error. e.g. 23.42 should not be valid. 199 */ 200 if (*end != '\0') { 201 (void) fprintf(stderr, "%s: %s value must be an integer\n", 202 g_pname, name); 203 exit(E_ERROR); 204 } 205 206 if (val < min || val > max) { 207 (void) fprintf(stderr, "%s: %s value must be between %ld and " 208 "%ld inclusive\n", g_pname, name, min, max); 209 exit(E_ERROR); 210 } 211 212 return (val); 213 } 214 215 static int 216 ipdadm_corrupt(int argc, char *argv[]) 217 { 218 int rval, fd; 219 long val; 220 ipd_config_t ic; 221 222 if (argc != 1) { 223 (void) fprintf(stderr, "%s: corrupt <percentage>\n", 224 g_pname); 225 return (usage(stderr)); 226 } 227 228 val = ipdadm_parse_long(argv[0], "corrupt", 0, 100); 229 bzero(&ic, sizeof (ic)); 230 ic.ic_mask = IPDM_CORRUPT; 231 ic.ic_corrupt = val; 232 233 fd = ipd_open(NULL); 234 rval = ipd_ctl(fd, g_zid, &ic); 235 (void) ipd_close(fd); 236 237 if (rval != 0) { 238 (void) fprintf(stderr, "%s: failed to change corrupt " 239 "value: %s\n", g_pname, ipd_errmsg); 240 return (E_ERROR); 241 } 242 243 return (E_SUCCESS); 244 } 245 246 static int 247 ipdadm_delay(int argc, char *argv[]) 248 { 249 long val; 250 int fd, rval; 251 ipd_config_t ic; 252 253 if (argc != 1) { 254 (void) fprintf(stderr, "%s: delay <microseconds>\n", 255 g_pname); 256 return (usage(stderr)); 257 } 258 259 val = ipdadm_parse_long(argv[0], "delay", 0, MAXLONG); 260 bzero(&ic, sizeof (ic)); 261 ic.ic_mask = IPDM_DELAY; 262 ic.ic_delay = val; 263 264 fd = ipd_open(NULL); 265 rval = ipd_ctl(fd, g_zid, &ic); 266 (void) ipd_close(fd); 267 268 if (rval != 0) { 269 (void) fprintf(stderr, "%s: failed to change delay value: %s\n", 270 g_pname, ipd_errmsg); 271 return (E_ERROR); 272 } 273 274 return (E_SUCCESS); 275 } 276 277 static int 278 ipdadm_drop(int argc, char *argv[]) 279 { 280 long val; 281 int fd, rval; 282 ipd_config_t ic; 283 284 if (argc != 1) { 285 (void) fprintf(stderr, "%s: drop <percentage>\n", 286 g_pname); 287 return (usage(stderr)); 288 } 289 290 val = ipdadm_parse_long(argv[0], "drop", 0, 100); 291 bzero(&ic, sizeof (ic)); 292 ic.ic_mask = IPDM_DROP; 293 ic.ic_drop = val; 294 295 fd = ipd_open(NULL); 296 rval = ipd_ctl(fd, g_zid, &ic); 297 (void) ipd_close(fd); 298 299 if (rval != 0) { 300 (void) fprintf(stderr, "%s: failed to change drop value: %s\n", 301 g_pname, ipd_errmsg); 302 return (E_ERROR); 303 } 304 305 return (E_SUCCESS); 306 } 307 308 static int 309 ipdadm_remove_valid(const char *str) 310 { 311 if (strcmp(str, "corrupt") == 0) { 312 return (IPDM_CORRUPT); 313 } else if (strcmp(str, "drop") == 0) { 314 return (IPDM_DROP); 315 } else if (strcmp(str, "delay") == 0) { 316 return (IPDM_DELAY); 317 } 318 319 return (0); 320 } 321 322 static int 323 ipdadm_remove(int argc, char *argv[]) 324 { 325 ipd_config_t ic; 326 char *cur, *res; 327 int rval, fd; 328 329 if (argc < 1) { 330 (void) fprintf(stderr, "%s: remove <arguments>\n", 331 g_pname); 332 return (usage(stderr)); 333 } 334 335 if (argc > 1) { 336 (void) fprintf(stderr, "%s: remove's arguments must be " 337 "comma seperated\n", g_pname); 338 return (E_ERROR); 339 } 340 341 bzero(&ic, sizeof (ic)); 342 343 cur = argv[0]; 344 while ((res = strchr(cur, ',')) != NULL) { 345 *res = '\0'; 346 if ((rval = ipdadm_remove_valid(cur)) == 0) { 347 (void) fprintf(stderr, "%s: unknown remove " 348 "argument: %s\n", g_pname, cur); 349 return (E_ERROR); 350 } 351 ic.ic_mask |= rval; 352 cur = res + 1; 353 } 354 355 if ((rval = ipdadm_remove_valid(cur)) == 0) { 356 (void) fprintf(stderr, "%s: unknown remove argument: %s\n", 357 g_pname, cur); 358 return (E_ERROR); 359 } 360 ic.ic_mask |= rval; 361 362 fd = ipd_open(NULL); 363 rval = ipd_ctl(fd, g_zid, &ic); 364 (void) ipd_close(fd); 365 if (rval == -1) { 366 (void) fprintf(stderr, "%s: failed to remove instances: %s\n", 367 g_pname, ipd_errmsg); 368 return (E_ERROR); 369 } 370 371 return (E_SUCCESS); 372 } 373 374 375 int 376 main(int argc, char *argv[]) 377 { 378 int ii; 379 ipdadm_cmd_t *cmd; 380 381 g_pname = basename(argv[0]); 382 383 if (argc < 2) 384 return (usage(stderr)); 385 argc--; 386 argv++; 387 388 g_zid = getzoneid(); 389 if (strcmp("-z", argv[0]) == 0) { 390 argc--; 391 argv++; 392 if (argc < 1) { 393 (void) fprintf(stderr, "%s: -z requires an argument\n", 394 g_pname); 395 return (usage(stderr)); 396 } 397 398 if (g_zid != GLOBAL_ZONEID) { 399 (void) fprintf(stderr, "%s: -z option only permitted " 400 "in global zone\n", g_pname); 401 return (usage(stderr)); 402 } 403 404 g_zid = getzoneidbyname(argv[0]); 405 if (g_zid == -1) { 406 (void) fprintf(stderr, "%s: %s: invalid zone\n", 407 g_pname, argv[0]); 408 return (E_ERROR); 409 } 410 argc--; 411 argv++; 412 } 413 414 if (getzonenamebyid(g_zid, g_zonename, sizeof (g_zonename)) < 0) { 415 (void) fprintf(stderr, "%s: failed to get zonename: %s\n", 416 g_pname, strerror(errno)); 417 return (E_ERROR); 418 } 419 420 if (argc < 1) 421 return (usage(stderr)); 422 423 for (ii = 0; ii < IPDADM_NCMDS; ii++) { 424 cmd = &ipdadm_cmds[ii]; 425 if (strcmp(argv[0], cmd->idc_name) == 0) { 426 argv++; 427 argc--; 428 assert(cmd->idc_func != NULL); 429 return (cmd->idc_func(argc, argv)); 430 } 431 } 432 433 (void) fprintf(stderr, "%s: %s: unknown command\n", g_pname, argv[0]); 434 return (usage(stderr)); 435 } 436