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