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