1*fe77cc04SRobert Mustacchi /* 2*fe77cc04SRobert Mustacchi * This file and its contents are supplied under the terms of the 3*fe77cc04SRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0. 4*fe77cc04SRobert Mustacchi * You may only use this file in accordance with the terms of version 5*fe77cc04SRobert Mustacchi * 1.0 of the CDDL. 6*fe77cc04SRobert Mustacchi * 7*fe77cc04SRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this 8*fe77cc04SRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at 9*fe77cc04SRobert Mustacchi * http://www.illumos.org/license/CDDL. 10*fe77cc04SRobert Mustacchi */ 11*fe77cc04SRobert Mustacchi 12*fe77cc04SRobert Mustacchi /* 13*fe77cc04SRobert Mustacchi * Copyright (c) 2012 Joyent, Inc. All rights reserved. 14*fe77cc04SRobert Mustacchi * Use is subject to license terms. 15*fe77cc04SRobert Mustacchi */ 16*fe77cc04SRobert Mustacchi 17*fe77cc04SRobert Mustacchi #include <sys/types.h> 18*fe77cc04SRobert Mustacchi #include <stdio.h> 19*fe77cc04SRobert Mustacchi #include <fcntl.h> 20*fe77cc04SRobert Mustacchi #include <errno.h> 21*fe77cc04SRobert Mustacchi #include <string.h> 22*fe77cc04SRobert Mustacchi #include <strings.h> 23*fe77cc04SRobert Mustacchi #include <stdlib.h> 24*fe77cc04SRobert Mustacchi #include <unistd.h> 25*fe77cc04SRobert Mustacchi #include <stdarg.h> 26*fe77cc04SRobert Mustacchi 27*fe77cc04SRobert Mustacchi #include <libipd.h> 28*fe77cc04SRobert Mustacchi #include <sys/ipd.h> 29*fe77cc04SRobert Mustacchi 30*fe77cc04SRobert Mustacchi __thread ipd_errno_t ipd_errno = 0; 31*fe77cc04SRobert Mustacchi __thread char ipd_errmsg[512]; 32*fe77cc04SRobert Mustacchi 33*fe77cc04SRobert Mustacchi struct ipd_stat { 34*fe77cc04SRobert Mustacchi uint_t is_nzones; 35*fe77cc04SRobert Mustacchi zoneid_t *is_zoneids; 36*fe77cc04SRobert Mustacchi struct ipd_config *is_configs; 37*fe77cc04SRobert Mustacchi }; 38*fe77cc04SRobert Mustacchi 39*fe77cc04SRobert Mustacchi static ipd_errno_t 40*fe77cc04SRobert Mustacchi xlate_errno(int e) 41*fe77cc04SRobert Mustacchi { 42*fe77cc04SRobert Mustacchi switch (e) { 43*fe77cc04SRobert Mustacchi case 0: 44*fe77cc04SRobert Mustacchi return (EIPD_NOERROR); 45*fe77cc04SRobert Mustacchi case ENOMEM: 46*fe77cc04SRobert Mustacchi case EAGAIN: 47*fe77cc04SRobert Mustacchi return (EIPD_NOMEM); 48*fe77cc04SRobert Mustacchi case ERANGE: 49*fe77cc04SRobert Mustacchi return (EIPD_RANGE); 50*fe77cc04SRobert Mustacchi case EPERM: 51*fe77cc04SRobert Mustacchi return (EIPD_PERM); 52*fe77cc04SRobert Mustacchi case EFAULT: 53*fe77cc04SRobert Mustacchi return (EIPD_FAULT); 54*fe77cc04SRobert Mustacchi case ENOTTY: 55*fe77cc04SRobert Mustacchi return (EIPD_INTERNAL); 56*fe77cc04SRobert Mustacchi default: 57*fe77cc04SRobert Mustacchi return (EIPD_UNKNOWN); 58*fe77cc04SRobert Mustacchi } 59*fe77cc04SRobert Mustacchi } 60*fe77cc04SRobert Mustacchi 61*fe77cc04SRobert Mustacchi const char * 62*fe77cc04SRobert Mustacchi ipd_strerror(ipd_errno_t e) 63*fe77cc04SRobert Mustacchi { 64*fe77cc04SRobert Mustacchi switch (e) { 65*fe77cc04SRobert Mustacchi case EIPD_NOERROR: 66*fe77cc04SRobert Mustacchi return ("no error"); 67*fe77cc04SRobert Mustacchi case EIPD_NOMEM: 68*fe77cc04SRobert Mustacchi return ("out of memory"); 69*fe77cc04SRobert Mustacchi case EIPD_ZC_NOENT: 70*fe77cc04SRobert Mustacchi return ("zone does not exist or is not using ipd"); 71*fe77cc04SRobert Mustacchi case EIPD_RANGE: 72*fe77cc04SRobert Mustacchi return ("argument out of range"); 73*fe77cc04SRobert Mustacchi case EIPD_PERM: 74*fe77cc04SRobert Mustacchi return ("permission denied"); 75*fe77cc04SRobert Mustacchi case EIPD_FAULT: 76*fe77cc04SRobert Mustacchi return ("bad pointer"); 77*fe77cc04SRobert Mustacchi case EIPD_INTERNAL: 78*fe77cc04SRobert Mustacchi return ("internal library error"); 79*fe77cc04SRobert Mustacchi case EIPD_UNKNOWN: 80*fe77cc04SRobert Mustacchi default: 81*fe77cc04SRobert Mustacchi return ("unknown error"); 82*fe77cc04SRobert Mustacchi } 83*fe77cc04SRobert Mustacchi } 84*fe77cc04SRobert Mustacchi 85*fe77cc04SRobert Mustacchi static int 86*fe77cc04SRobert Mustacchi ipd_set_errno(ipd_errno_t e, const char *fmt, ...) 87*fe77cc04SRobert Mustacchi { 88*fe77cc04SRobert Mustacchi va_list ap; 89*fe77cc04SRobert Mustacchi 90*fe77cc04SRobert Mustacchi ipd_errno = e; 91*fe77cc04SRobert Mustacchi if (fmt != NULL) { 92*fe77cc04SRobert Mustacchi va_start(ap, fmt); 93*fe77cc04SRobert Mustacchi (void) vsnprintf(ipd_errmsg, sizeof (ipd_errmsg), fmt, ap); 94*fe77cc04SRobert Mustacchi va_end(ap); 95*fe77cc04SRobert Mustacchi } else { 96*fe77cc04SRobert Mustacchi (void) strlcpy(ipd_errmsg, 97*fe77cc04SRobert Mustacchi ipd_strerror(e), sizeof (ipd_errmsg)); 98*fe77cc04SRobert Mustacchi } 99*fe77cc04SRobert Mustacchi 100*fe77cc04SRobert Mustacchi return (-1); 101*fe77cc04SRobert Mustacchi } 102*fe77cc04SRobert Mustacchi 103*fe77cc04SRobert Mustacchi int 104*fe77cc04SRobert Mustacchi ipd_open(const char *path) 105*fe77cc04SRobert Mustacchi { 106*fe77cc04SRobert Mustacchi int fd; 107*fe77cc04SRobert Mustacchi 108*fe77cc04SRobert Mustacchi if (path == NULL) 109*fe77cc04SRobert Mustacchi path = IPD_DEV_PATH; 110*fe77cc04SRobert Mustacchi 111*fe77cc04SRobert Mustacchi fd = open(path, O_RDWR); 112*fe77cc04SRobert Mustacchi if (fd < 0) { 113*fe77cc04SRobert Mustacchi return (ipd_set_errno(xlate_errno(errno), 114*fe77cc04SRobert Mustacchi "unable to open %s: %s", path, strerror(errno))); 115*fe77cc04SRobert Mustacchi } 116*fe77cc04SRobert Mustacchi 117*fe77cc04SRobert Mustacchi return (fd); 118*fe77cc04SRobert Mustacchi } 119*fe77cc04SRobert Mustacchi 120*fe77cc04SRobert Mustacchi int 121*fe77cc04SRobert Mustacchi ipd_close(int fd) 122*fe77cc04SRobert Mustacchi { 123*fe77cc04SRobert Mustacchi (void) close(fd); 124*fe77cc04SRobert Mustacchi return (0); 125*fe77cc04SRobert Mustacchi } 126*fe77cc04SRobert Mustacchi 127*fe77cc04SRobert Mustacchi int 128*fe77cc04SRobert Mustacchi ipd_status_read(int fd, ipd_stathdl_t *ispp) 129*fe77cc04SRobert Mustacchi { 130*fe77cc04SRobert Mustacchi struct ipd_stat *isp = NULL; 131*fe77cc04SRobert Mustacchi ipd_ioc_list_t ipil; 132*fe77cc04SRobert Mustacchi uint_t rzones; 133*fe77cc04SRobert Mustacchi uint_t i; 134*fe77cc04SRobert Mustacchi 135*fe77cc04SRobert Mustacchi bzero(&ipil, sizeof (ipil)); 136*fe77cc04SRobert Mustacchi if (ioctl(fd, IPDIOC_LIST, &ipil) != 0) { 137*fe77cc04SRobert Mustacchi return (ipd_set_errno(xlate_errno(errno), 138*fe77cc04SRobert Mustacchi "unable to retrieve ipd zone list: %s", strerror(errno))); 139*fe77cc04SRobert Mustacchi } 140*fe77cc04SRobert Mustacchi 141*fe77cc04SRobert Mustacchi for (;;) { 142*fe77cc04SRobert Mustacchi if ((rzones = ipil.ipil_nzones) == 0) 143*fe77cc04SRobert Mustacchi break; 144*fe77cc04SRobert Mustacchi 145*fe77cc04SRobert Mustacchi ipil.ipil_info = 146*fe77cc04SRobert Mustacchi malloc(sizeof (ipd_ioc_info_t) * ipil.ipil_nzones); 147*fe77cc04SRobert Mustacchi if (ipil.ipil_info == NULL) 148*fe77cc04SRobert Mustacchi return (ipd_set_errno(EIPD_NOMEM, NULL)); 149*fe77cc04SRobert Mustacchi 150*fe77cc04SRobert Mustacchi if (ioctl(fd, IPDIOC_LIST, &ipil) != 0) { 151*fe77cc04SRobert Mustacchi free(ipil.ipil_info); 152*fe77cc04SRobert Mustacchi return (ipd_set_errno(xlate_errno(errno), 153*fe77cc04SRobert Mustacchi "unable to retrieve ipd zone list: %s", 154*fe77cc04SRobert Mustacchi strerror(errno))); 155*fe77cc04SRobert Mustacchi } 156*fe77cc04SRobert Mustacchi 157*fe77cc04SRobert Mustacchi if (ipil.ipil_nzones <= rzones) 158*fe77cc04SRobert Mustacchi break; 159*fe77cc04SRobert Mustacchi 160*fe77cc04SRobert Mustacchi free(ipil.ipil_info); 161*fe77cc04SRobert Mustacchi } 162*fe77cc04SRobert Mustacchi 163*fe77cc04SRobert Mustacchi if ((isp = malloc(sizeof (struct ipd_stat))) == NULL) { 164*fe77cc04SRobert Mustacchi free(ipil.ipil_info); 165*fe77cc04SRobert Mustacchi return (ipd_set_errno(EIPD_NOMEM, NULL)); 166*fe77cc04SRobert Mustacchi } 167*fe77cc04SRobert Mustacchi 168*fe77cc04SRobert Mustacchi isp->is_nzones = ipil.ipil_nzones; 169*fe77cc04SRobert Mustacchi 170*fe77cc04SRobert Mustacchi if (isp->is_nzones == 0) { 171*fe77cc04SRobert Mustacchi isp->is_zoneids = NULL; 172*fe77cc04SRobert Mustacchi isp->is_configs = NULL; 173*fe77cc04SRobert Mustacchi *ispp = isp; 174*fe77cc04SRobert Mustacchi return (0); 175*fe77cc04SRobert Mustacchi } 176*fe77cc04SRobert Mustacchi 177*fe77cc04SRobert Mustacchi isp->is_zoneids = malloc(sizeof (zoneid_t) * ipil.ipil_nzones); 178*fe77cc04SRobert Mustacchi if (isp->is_zoneids == NULL) { 179*fe77cc04SRobert Mustacchi free(ipil.ipil_info); 180*fe77cc04SRobert Mustacchi free(isp); 181*fe77cc04SRobert Mustacchi return (ipd_set_errno(EIPD_NOMEM, NULL)); 182*fe77cc04SRobert Mustacchi } 183*fe77cc04SRobert Mustacchi isp->is_configs = malloc(sizeof (struct ipd_config) * ipil.ipil_nzones); 184*fe77cc04SRobert Mustacchi if (isp->is_configs == NULL) { 185*fe77cc04SRobert Mustacchi free(ipil.ipil_info); 186*fe77cc04SRobert Mustacchi free(isp->is_zoneids); 187*fe77cc04SRobert Mustacchi free(isp); 188*fe77cc04SRobert Mustacchi return (ipd_set_errno(EIPD_NOMEM, NULL)); 189*fe77cc04SRobert Mustacchi } 190*fe77cc04SRobert Mustacchi 191*fe77cc04SRobert Mustacchi for (i = 0; i < isp->is_nzones; i++) { 192*fe77cc04SRobert Mustacchi isp->is_zoneids[i] = ipil.ipil_info[i].ipii_zoneid; 193*fe77cc04SRobert Mustacchi 194*fe77cc04SRobert Mustacchi isp->is_configs[i].ic_corrupt = ipil.ipil_info[i].ipii_corrupt; 195*fe77cc04SRobert Mustacchi isp->is_configs[i].ic_drop = ipil.ipil_info[i].ipii_drop; 196*fe77cc04SRobert Mustacchi isp->is_configs[i].ic_delay = ipil.ipil_info[i].ipii_delay; 197*fe77cc04SRobert Mustacchi 198*fe77cc04SRobert Mustacchi isp->is_configs[i].ic_mask = 199*fe77cc04SRobert Mustacchi ((!!isp->is_configs[i].ic_corrupt) * IPDM_CORRUPT) | 200*fe77cc04SRobert Mustacchi ((!!isp->is_configs[i].ic_drop) * IPDM_DROP) | 201*fe77cc04SRobert Mustacchi ((!!isp->is_configs[i].ic_delay) * IPDM_DELAY); 202*fe77cc04SRobert Mustacchi } 203*fe77cc04SRobert Mustacchi 204*fe77cc04SRobert Mustacchi *ispp = isp; 205*fe77cc04SRobert Mustacchi return (0); 206*fe77cc04SRobert Mustacchi } 207*fe77cc04SRobert Mustacchi 208*fe77cc04SRobert Mustacchi void 209*fe77cc04SRobert Mustacchi ipd_status_foreach_zone(const ipd_stathdl_t hdl, ipd_status_cb_f f, void *arg) 210*fe77cc04SRobert Mustacchi { 211*fe77cc04SRobert Mustacchi const struct ipd_stat *isp = hdl; 212*fe77cc04SRobert Mustacchi uint_t i; 213*fe77cc04SRobert Mustacchi 214*fe77cc04SRobert Mustacchi for (i = 0; i < isp->is_nzones; i++) 215*fe77cc04SRobert Mustacchi f(isp->is_zoneids[i], &isp->is_configs[i], arg); 216*fe77cc04SRobert Mustacchi } 217*fe77cc04SRobert Mustacchi 218*fe77cc04SRobert Mustacchi int 219*fe77cc04SRobert Mustacchi ipd_status_get_config(const ipd_stathdl_t hdl, zoneid_t z, ipd_config_t **icpp) 220*fe77cc04SRobert Mustacchi { 221*fe77cc04SRobert Mustacchi const struct ipd_stat *isp = hdl; 222*fe77cc04SRobert Mustacchi uint_t i; 223*fe77cc04SRobert Mustacchi 224*fe77cc04SRobert Mustacchi for (i = 0; i < isp->is_nzones; i++) { 225*fe77cc04SRobert Mustacchi if (isp->is_zoneids[i] == z) { 226*fe77cc04SRobert Mustacchi *icpp = &isp->is_configs[i]; 227*fe77cc04SRobert Mustacchi return (0); 228*fe77cc04SRobert Mustacchi } 229*fe77cc04SRobert Mustacchi } 230*fe77cc04SRobert Mustacchi 231*fe77cc04SRobert Mustacchi return (ipd_set_errno(EIPD_ZC_NOENT, 232*fe77cc04SRobert Mustacchi "zone %d does not exist or has no ipd configuration", z)); 233*fe77cc04SRobert Mustacchi } 234*fe77cc04SRobert Mustacchi 235*fe77cc04SRobert Mustacchi void 236*fe77cc04SRobert Mustacchi ipd_status_free(ipd_stathdl_t hdl) 237*fe77cc04SRobert Mustacchi { 238*fe77cc04SRobert Mustacchi struct ipd_stat *isp = hdl; 239*fe77cc04SRobert Mustacchi 240*fe77cc04SRobert Mustacchi if (isp != NULL) { 241*fe77cc04SRobert Mustacchi free(isp->is_zoneids); 242*fe77cc04SRobert Mustacchi free(isp->is_configs); 243*fe77cc04SRobert Mustacchi } 244*fe77cc04SRobert Mustacchi free(isp); 245*fe77cc04SRobert Mustacchi } 246*fe77cc04SRobert Mustacchi 247*fe77cc04SRobert Mustacchi int 248*fe77cc04SRobert Mustacchi ipd_ctl(int fd, zoneid_t z, const ipd_config_t *icp) 249*fe77cc04SRobert Mustacchi { 250*fe77cc04SRobert Mustacchi ipd_ioc_perturb_t ipip; 251*fe77cc04SRobert Mustacchi 252*fe77cc04SRobert Mustacchi bzero(&ipip, sizeof (ipd_ioc_perturb_t)); 253*fe77cc04SRobert Mustacchi ipip.ipip_zoneid = z; 254*fe77cc04SRobert Mustacchi 255*fe77cc04SRobert Mustacchi if (icp->ic_mask & IPDM_CORRUPT) { 256*fe77cc04SRobert Mustacchi if (icp->ic_corrupt == 0) 257*fe77cc04SRobert Mustacchi ipip.ipip_arg |= IPD_CORRUPT; 258*fe77cc04SRobert Mustacchi } 259*fe77cc04SRobert Mustacchi if (icp->ic_mask & IPDM_DELAY) { 260*fe77cc04SRobert Mustacchi if (icp->ic_delay == 0) 261*fe77cc04SRobert Mustacchi ipip.ipip_arg |= IPD_DELAY; 262*fe77cc04SRobert Mustacchi } 263*fe77cc04SRobert Mustacchi if (icp->ic_mask & IPDM_DROP) { 264*fe77cc04SRobert Mustacchi if (icp->ic_drop == 0) 265*fe77cc04SRobert Mustacchi ipip.ipip_arg |= IPD_DROP; 266*fe77cc04SRobert Mustacchi } 267*fe77cc04SRobert Mustacchi 268*fe77cc04SRobert Mustacchi if (ipip.ipip_arg != 0 && ioctl(fd, IPDIOC_REMOVE, &ipip) != 0) { 269*fe77cc04SRobert Mustacchi return (ipd_set_errno(xlate_errno(errno), 270*fe77cc04SRobert Mustacchi "unable to remove cleared ipd settings: %s", 271*fe77cc04SRobert Mustacchi strerror(errno))); 272*fe77cc04SRobert Mustacchi } 273*fe77cc04SRobert Mustacchi 274*fe77cc04SRobert Mustacchi if ((icp->ic_mask & IPDM_CORRUPT) && icp->ic_corrupt != 0) { 275*fe77cc04SRobert Mustacchi ipip.ipip_zoneid = z; 276*fe77cc04SRobert Mustacchi ipip.ipip_arg = icp->ic_corrupt; 277*fe77cc04SRobert Mustacchi if (ioctl(fd, IPDIOC_CORRUPT, &ipip) != 0) { 278*fe77cc04SRobert Mustacchi return (ipd_set_errno(xlate_errno(errno), 279*fe77cc04SRobert Mustacchi "unable to set corruption rate to %d: %s", 280*fe77cc04SRobert Mustacchi ipip.ipip_arg, strerror(errno))); 281*fe77cc04SRobert Mustacchi } 282*fe77cc04SRobert Mustacchi } 283*fe77cc04SRobert Mustacchi if ((icp->ic_mask & IPDM_DELAY) && icp->ic_delay != 0) { 284*fe77cc04SRobert Mustacchi ipip.ipip_zoneid = z; 285*fe77cc04SRobert Mustacchi ipip.ipip_arg = icp->ic_delay; 286*fe77cc04SRobert Mustacchi if (ioctl(fd, IPDIOC_DELAY, &ipip) != 0) { 287*fe77cc04SRobert Mustacchi return (ipd_set_errno(xlate_errno(errno), 288*fe77cc04SRobert Mustacchi "unable to set delay time to %d: %s", 289*fe77cc04SRobert Mustacchi ipip.ipip_arg, strerror(errno))); 290*fe77cc04SRobert Mustacchi } 291*fe77cc04SRobert Mustacchi } 292*fe77cc04SRobert Mustacchi if ((icp->ic_mask & IPDM_DROP) && icp->ic_drop != 0) { 293*fe77cc04SRobert Mustacchi ipip.ipip_zoneid = z; 294*fe77cc04SRobert Mustacchi ipip.ipip_arg = icp->ic_drop; 295*fe77cc04SRobert Mustacchi if (ioctl(fd, IPDIOC_DROP, &ipip) != 0) { 296*fe77cc04SRobert Mustacchi return (ipd_set_errno(xlate_errno(errno), 297*fe77cc04SRobert Mustacchi "unable to set drop probability to %d: %s", 298*fe77cc04SRobert Mustacchi ipip.ipip_arg, strerror(errno))); 299*fe77cc04SRobert Mustacchi } 300*fe77cc04SRobert Mustacchi } 301*fe77cc04SRobert Mustacchi 302*fe77cc04SRobert Mustacchi return (0); 303*fe77cc04SRobert Mustacchi } 304