xref: /illumos-gate/usr/src/lib/libipd/common/libipd.c (revision fe77cc04)
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
xlate_errno(int e)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 *
ipd_strerror(ipd_errno_t e)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
ipd_set_errno(ipd_errno_t e,const char * fmt,...)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
ipd_open(const char * path)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
ipd_close(int fd)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
ipd_status_read(int fd,ipd_stathdl_t * ispp)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
ipd_status_foreach_zone(const ipd_stathdl_t hdl,ipd_status_cb_f f,void * arg)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
ipd_status_get_config(const ipd_stathdl_t hdl,zoneid_t z,ipd_config_t ** icpp)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
ipd_status_free(ipd_stathdl_t hdl)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
ipd_ctl(int fd,zoneid_t z,const ipd_config_t * icp)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