/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright (c) 2012 Joyent, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static char *g_pname; static char g_zonename[ZONENAME_MAX]; static zoneid_t g_zid; #define E_SUCCESS 0 #define E_ERROR 1 #define E_USAGE 2 typedef int (*idc_cmd_func_t)(int, char *[]); typedef struct ipdadm_cmd { const char *idc_name; /* subcommand name */ idc_cmd_func_t idc_func; /* subcommand function */ const char *idc_usage; /* subcommand help */ } ipdadm_cmd_t; static int ipdadm_list(int, char *[]); static int ipdadm_info(int, char *[]); static int ipdadm_corrupt(int, char *[]); static int ipdadm_delay(int, char *[]); static int ipdadm_drop(int, char *[]); static int ipdadm_remove(int, char *[]); #define IPDADM_NCMDS 6 static ipdadm_cmd_t ipdadm_cmds[] = { { "list", ipdadm_list, "list [-v]" }, { "info", ipdadm_info, "info" }, { "corrupt", ipdadm_corrupt, "corrupt " }, { "delay", ipdadm_delay, "delay " }, { "drop", ipdadm_drop, "drop " }, { "remove", ipdadm_remove, "remove [corrupt|delay|drop]" } }; static int usage(FILE *fp) { int ii; ipdadm_cmd_t *cmd; (void) fprintf(fp, "Usage: %s [-z zonename] subcommand " "[subcommand opts]\n\n", g_pname); (void) fprintf(fp, "Subcommands:\n"); for (ii = 0; ii < IPDADM_NCMDS; ii++) { cmd = &ipdadm_cmds[ii]; (void) fprintf(fp, "\t%s\n", cmd->idc_usage); } return (E_USAGE); } static void ipdadm_list_one(zoneid_t z, const ipd_config_t *icp, void *arg) { char zonename[ZONENAME_MAX]; int opt_v = (int)(intptr_t)arg; if (getzonenamebyid(z, zonename, sizeof (zonename)) < 0) (void) printf("%ld", z); else (void) printf("%s", zonename); if (!opt_v) { (void) printf("\n"); return; } (void) printf("\t%u\t%u\t%u\n", icp->ic_corrupt, icp->ic_drop, icp->ic_delay); } static int ipdadm_list(int argc, char *argv[]) { int opt_v = 0; int fd, rval; ipd_stathdl_t hdl; if (argc > 1) return (usage(stderr)); if (argc == 1) { if (strcmp(argv[0], "-v") == 0) ++opt_v; else return (usage(stderr)); } fd = ipd_open(NULL); if (fd < 0) { (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } rval = ipd_status_read(fd, &hdl); (void) ipd_close(fd); if (rval != 0) { (void) fprintf(stderr, "%s: failed to get list info: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } ipd_status_foreach_zone(hdl, ipdadm_list_one, (void *)(intptr_t)opt_v); ipd_status_free(hdl); return (E_SUCCESS); } /*ARGSUSED*/ static int ipdadm_info(int argc, char *argv[]) { int rval, fd; ipd_stathdl_t hdl; ipd_config_t *icp; if (argc != 0) return (usage(stderr)); fd = ipd_open(NULL); if (fd < 0) { (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } rval = ipd_status_read(fd, &hdl); (void) ipd_close(fd); if (rval != 0) { (void) fprintf(stderr, "%s: failed to get info: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } if (ipd_status_get_config(hdl, g_zid, &icp) != 0) { if (ipd_errno == EIPD_ZC_NOENT) { (void) printf("zone %s does not exist or has no " "ipd actions enabled\n", g_zonename); return (E_SUCCESS); } (void) fprintf(stderr, "%s: failed to get info: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } (void) printf("ipd information for zone %s:\n", g_zonename); (void) printf("\tcorrupt:\t%u%% chance of packet corruption\n", icp->ic_corrupt); (void) printf("\tdrop:\t\t%u%% chance of packet drop\n", icp->ic_drop); (void) printf("\tdelay:\t\t%u microsecond delay per packet\n", icp->ic_delay); ipd_status_free(hdl); return (E_SUCCESS); } static long ipdadm_parse_long(const char *str, const char *name, long min, long max) { long val; char *end; errno = 0; val = strtol(str, &end, 10); if (errno != 0) { (void) fprintf(stderr, "%s: invalid value for %s: %s\n", g_pname, name, str); exit(E_ERROR); } /* * We want to make sure that we got the whole string. If not that's an * error. e.g. 23.42 should not be valid. */ if (*end != '\0') { (void) fprintf(stderr, "%s: %s value must be an integer\n", g_pname, name); exit(E_ERROR); } if (val < min || val > max) { (void) fprintf(stderr, "%s: %s value must be between %ld and " "%ld inclusive\n", g_pname, name, min, max); exit(E_ERROR); } return (val); } static int ipdadm_corrupt(int argc, char *argv[]) { int rval, fd; long val; ipd_config_t ic; if (argc != 1) { (void) fprintf(stderr, "%s: corrupt \n", g_pname); return (usage(stderr)); } val = ipdadm_parse_long(argv[0], "corrupt", 0, 100); bzero(&ic, sizeof (ic)); ic.ic_mask = IPDM_CORRUPT; ic.ic_corrupt = val; fd = ipd_open(NULL); if (fd < 0) { (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } rval = ipd_ctl(fd, g_zid, &ic); (void) ipd_close(fd); if (rval != 0) { (void) fprintf(stderr, "%s: failed to change corrupt " "value: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } return (E_SUCCESS); } static int ipdadm_delay(int argc, char *argv[]) { long val; int fd, rval; ipd_config_t ic; if (argc != 1) { (void) fprintf(stderr, "%s: delay \n", g_pname); return (usage(stderr)); } val = ipdadm_parse_long(argv[0], "delay", 0, MAXLONG); bzero(&ic, sizeof (ic)); ic.ic_mask = IPDM_DELAY; ic.ic_delay = val; fd = ipd_open(NULL); if (fd < 0) { (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } rval = ipd_ctl(fd, g_zid, &ic); (void) ipd_close(fd); if (rval != 0) { (void) fprintf(stderr, "%s: failed to change delay value: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } return (E_SUCCESS); } static int ipdadm_drop(int argc, char *argv[]) { long val; int fd, rval; ipd_config_t ic; if (argc != 1) { (void) fprintf(stderr, "%s: drop \n", g_pname); return (usage(stderr)); } val = ipdadm_parse_long(argv[0], "drop", 0, 100); bzero(&ic, sizeof (ic)); ic.ic_mask = IPDM_DROP; ic.ic_drop = val; fd = ipd_open(NULL); if (fd < 0) { (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } rval = ipd_ctl(fd, g_zid, &ic); (void) ipd_close(fd); if (rval != 0) { (void) fprintf(stderr, "%s: failed to change drop value: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } return (E_SUCCESS); } static int ipdadm_remove_valid(const char *str) { if (strcmp(str, "corrupt") == 0) { return (IPDM_CORRUPT); } else if (strcmp(str, "drop") == 0) { return (IPDM_DROP); } else if (strcmp(str, "delay") == 0) { return (IPDM_DELAY); } return (0); } static int ipdadm_remove(int argc, char *argv[]) { ipd_config_t ic; char *cur, *res; int rval, fd; if (argc < 1) { (void) fprintf(stderr, "%s: remove \n", g_pname); return (usage(stderr)); } if (argc > 1) { (void) fprintf(stderr, "%s: remove's arguments must be " "comma seperated\n", g_pname); return (E_ERROR); } bzero(&ic, sizeof (ic)); cur = argv[0]; while ((res = strchr(cur, ',')) != NULL) { *res = '\0'; if ((rval = ipdadm_remove_valid(cur)) == 0) { (void) fprintf(stderr, "%s: unknown remove " "argument: %s\n", g_pname, cur); return (E_ERROR); } ic.ic_mask |= rval; cur = res + 1; } if ((rval = ipdadm_remove_valid(cur)) == 0) { (void) fprintf(stderr, "%s: unknown remove argument: %s\n", g_pname, cur); return (E_ERROR); } ic.ic_mask |= rval; fd = ipd_open(NULL); if (fd < 0) { (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } rval = ipd_ctl(fd, g_zid, &ic); (void) ipd_close(fd); if (rval == -1) { (void) fprintf(stderr, "%s: failed to remove instances: %s\n", g_pname, ipd_errmsg); return (E_ERROR); } return (E_SUCCESS); } int main(int argc, char *argv[]) { int ii; ipdadm_cmd_t *cmd; g_pname = basename(argv[0]); if (argc < 2) return (usage(stderr)); argc--; argv++; g_zid = getzoneid(); if (strcmp("-z", argv[0]) == 0) { argc--; argv++; if (argc < 1) { (void) fprintf(stderr, "%s: -z requires an argument\n", g_pname); return (usage(stderr)); } if (g_zid != GLOBAL_ZONEID) { (void) fprintf(stderr, "%s: -z option only permitted " "in global zone\n", g_pname); return (usage(stderr)); } g_zid = getzoneidbyname(argv[0]); if (g_zid == -1) { (void) fprintf(stderr, "%s: %s: invalid zone\n", g_pname, argv[0]); return (E_ERROR); } argc--; argv++; } if (getzonenamebyid(g_zid, g_zonename, sizeof (g_zonename)) < 0) { (void) fprintf(stderr, "%s: failed to get zonename: %s\n", g_pname, strerror(errno)); return (E_ERROR); } if (argc < 1) return (usage(stderr)); for (ii = 0; ii < IPDADM_NCMDS; ii++) { cmd = &ipdadm_cmds[ii]; if (strcmp(argv[0], cmd->idc_name) == 0) { argv++; argc--; assert(cmd->idc_func != NULL); return (cmd->idc_func(argc, argv)); } } (void) fprintf(stderr, "%s: %s: unknown command\n", g_pname, argv[0]); return (usage(stderr)); }