xref: /illumos-gate/usr/src/lib/libvrrpadm/common/libvrrpadm.c (revision 1cb875ae88fb9463b368e725c2444776595895cb)
1*1cb875aeSCathy Zhou /*
2*1cb875aeSCathy Zhou  * CDDL HEADER START
3*1cb875aeSCathy Zhou  *
4*1cb875aeSCathy Zhou  * The contents of this file are subject to the terms of the
5*1cb875aeSCathy Zhou  * Common Development and Distribution License (the "License").
6*1cb875aeSCathy Zhou  * You may not use this file except in compliance with the License.
7*1cb875aeSCathy Zhou  *
8*1cb875aeSCathy Zhou  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1cb875aeSCathy Zhou  * or http://www.opensolaris.org/os/licensing.
10*1cb875aeSCathy Zhou  * See the License for the specific language governing permissions
11*1cb875aeSCathy Zhou  * and limitations under the License.
12*1cb875aeSCathy Zhou  *
13*1cb875aeSCathy Zhou  * When distributing Covered Code, include this CDDL HEADER in each
14*1cb875aeSCathy Zhou  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1cb875aeSCathy Zhou  * If applicable, add the following below this CDDL HEADER, with the
16*1cb875aeSCathy Zhou  * fields enclosed by brackets "[]" replaced with your own identifying
17*1cb875aeSCathy Zhou  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1cb875aeSCathy Zhou  *
19*1cb875aeSCathy Zhou  * CDDL HEADER END
20*1cb875aeSCathy Zhou  */
21*1cb875aeSCathy Zhou 
22*1cb875aeSCathy Zhou /*
23*1cb875aeSCathy Zhou  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*1cb875aeSCathy Zhou  * Use is subject to license terms.
25*1cb875aeSCathy Zhou  */
26*1cb875aeSCathy Zhou 
27*1cb875aeSCathy Zhou #include <sys/types.h>
28*1cb875aeSCathy Zhou #include <sys/stat.h>
29*1cb875aeSCathy Zhou #include <sys/socket.h>
30*1cb875aeSCathy Zhou #include <sys/mman.h>
31*1cb875aeSCathy Zhou #include <sys/varargs.h>
32*1cb875aeSCathy Zhou #include <sys/vlan.h>
33*1cb875aeSCathy Zhou #include <errno.h>
34*1cb875aeSCathy Zhou #include <ctype.h>
35*1cb875aeSCathy Zhou #include <fcntl.h>
36*1cb875aeSCathy Zhou #include <unistd.h>
37*1cb875aeSCathy Zhou #include <stdio.h>
38*1cb875aeSCathy Zhou #include <stdlib.h>
39*1cb875aeSCathy Zhou #include <string.h>
40*1cb875aeSCathy Zhou #include <netinet/in.h>
41*1cb875aeSCathy Zhou #include <arpa/inet.h>
42*1cb875aeSCathy Zhou #include <net/if.h>	/* LIFNAMSIZ */
43*1cb875aeSCathy Zhou #include <netinet/vrrp.h>
44*1cb875aeSCathy Zhou #include <libdladm.h>
45*1cb875aeSCathy Zhou #include <libdlvnic.h>
46*1cb875aeSCathy Zhou #include <libdlvlan.h>
47*1cb875aeSCathy Zhou #include <libdllink.h>
48*1cb875aeSCathy Zhou #include <libintl.h>
49*1cb875aeSCathy Zhou #include <libvrrpadm.h>
50*1cb875aeSCathy Zhou 
51*1cb875aeSCathy Zhou typedef vrrp_err_t vrrp_cmd_func_t(int, void *);
52*1cb875aeSCathy Zhou 
53*1cb875aeSCathy Zhou static vrrp_err_t
54*1cb875aeSCathy Zhou vrrp_cmd_request(void *cmd, size_t csize, vrrp_cmd_func_t func, void *arg)
55*1cb875aeSCathy Zhou {
56*1cb875aeSCathy Zhou 	struct sockaddr_un	to;
57*1cb875aeSCathy Zhou 	int			sock, flags;
58*1cb875aeSCathy Zhou 	size_t			len, cur_size = 0;
59*1cb875aeSCathy Zhou 	vrrp_ret_t		ret;
60*1cb875aeSCathy Zhou 	vrrp_err_t		err;
61*1cb875aeSCathy Zhou 
62*1cb875aeSCathy Zhou 	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
63*1cb875aeSCathy Zhou 		return (VRRP_ECMD);
64*1cb875aeSCathy Zhou 
65*1cb875aeSCathy Zhou 	/*
66*1cb875aeSCathy Zhou 	 * Set it to be non-blocking.
67*1cb875aeSCathy Zhou 	 */
68*1cb875aeSCathy Zhou 	flags = fcntl(sock, F_GETFL, 0);
69*1cb875aeSCathy Zhou 	(void) fcntl(sock, F_SETFL, (flags | O_NONBLOCK));
70*1cb875aeSCathy Zhou 
71*1cb875aeSCathy Zhou 	(void) memset(&to, 0, sizeof (to));
72*1cb875aeSCathy Zhou 	to.sun_family = AF_UNIX;
73*1cb875aeSCathy Zhou 	(void) strlcpy(to.sun_path, VRRPD_SOCKET, sizeof (to.sun_path));
74*1cb875aeSCathy Zhou 
75*1cb875aeSCathy Zhou 	/*
76*1cb875aeSCathy Zhou 	 * Connect to vrrpd
77*1cb875aeSCathy Zhou 	 */
78*1cb875aeSCathy Zhou 	if (connect(sock, (const struct sockaddr *)&to, sizeof (to)) < 0) {
79*1cb875aeSCathy Zhou 		(void) close(sock);
80*1cb875aeSCathy Zhou 		return (VRRP_ECMD);
81*1cb875aeSCathy Zhou 	}
82*1cb875aeSCathy Zhou 
83*1cb875aeSCathy Zhou 	/*
84*1cb875aeSCathy Zhou 	 * Send the request
85*1cb875aeSCathy Zhou 	 */
86*1cb875aeSCathy Zhou 	while (cur_size < csize) {
87*1cb875aeSCathy Zhou 		len = write(sock, (char *)cmd + cur_size, csize - cur_size);
88*1cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
89*1cb875aeSCathy Zhou 			continue;
90*1cb875aeSCathy Zhou 		} else if (len > 0) {
91*1cb875aeSCathy Zhou 			cur_size += len;
92*1cb875aeSCathy Zhou 			continue;
93*1cb875aeSCathy Zhou 		}
94*1cb875aeSCathy Zhou 		(void) close(sock);
95*1cb875aeSCathy Zhou 		return (VRRP_ECMD);
96*1cb875aeSCathy Zhou 	}
97*1cb875aeSCathy Zhou 
98*1cb875aeSCathy Zhou 	/*
99*1cb875aeSCathy Zhou 	 * Expect the ack, first get the error code.
100*1cb875aeSCathy Zhou 	 */
101*1cb875aeSCathy Zhou 	cur_size = 0;
102*1cb875aeSCathy Zhou 	while (cur_size < sizeof (vrrp_err_t)) {
103*1cb875aeSCathy Zhou 		len = read(sock, (char *)&ret + cur_size,
104*1cb875aeSCathy Zhou 		    sizeof (vrrp_err_t) - cur_size);
105*1cb875aeSCathy Zhou 
106*1cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
107*1cb875aeSCathy Zhou 			continue;
108*1cb875aeSCathy Zhou 		} else if (len > 0) {
109*1cb875aeSCathy Zhou 			cur_size += len;
110*1cb875aeSCathy Zhou 			continue;
111*1cb875aeSCathy Zhou 		}
112*1cb875aeSCathy Zhou 		(void) close(sock);
113*1cb875aeSCathy Zhou 		return (VRRP_ECMD);
114*1cb875aeSCathy Zhou 	}
115*1cb875aeSCathy Zhou 
116*1cb875aeSCathy Zhou 	if ((err = ret.vr_err) != VRRP_SUCCESS)
117*1cb875aeSCathy Zhou 		goto done;
118*1cb875aeSCathy Zhou 
119*1cb875aeSCathy Zhou 	/*
120*1cb875aeSCathy Zhou 	 * The specific callback gets the rest of the information.
121*1cb875aeSCathy Zhou 	 */
122*1cb875aeSCathy Zhou 	if (func != NULL)
123*1cb875aeSCathy Zhou 		err = func(sock, arg);
124*1cb875aeSCathy Zhou 
125*1cb875aeSCathy Zhou done:
126*1cb875aeSCathy Zhou 	(void) close(sock);
127*1cb875aeSCathy Zhou 	return (err);
128*1cb875aeSCathy Zhou }
129*1cb875aeSCathy Zhou 
130*1cb875aeSCathy Zhou /*
131*1cb875aeSCathy Zhou  * public APIs
132*1cb875aeSCathy Zhou  */
133*1cb875aeSCathy Zhou const char *
134*1cb875aeSCathy Zhou vrrp_err2str(vrrp_err_t err)
135*1cb875aeSCathy Zhou {
136*1cb875aeSCathy Zhou 	switch (err) {
137*1cb875aeSCathy Zhou 	case VRRP_SUCCESS:
138*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "success"));
139*1cb875aeSCathy Zhou 	case VRRP_ENOMEM:
140*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "not enough memory"));
141*1cb875aeSCathy Zhou 	case VRRP_EINVALVRNAME:
142*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid router name"));
143*1cb875aeSCathy Zhou 	case VRRP_ENOPRIM:
144*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "no primary IP"));
145*1cb875aeSCathy Zhou 	case VRRP_EEXIST:
146*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "already exists"));
147*1cb875aeSCathy Zhou 	case VRRP_ENOVIRT:
148*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "no virtual IPs"));
149*1cb875aeSCathy Zhou 	case VRRP_EIPADM:
150*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "ip configuration failure"));
151*1cb875aeSCathy Zhou 	case VRRP_EDLADM:
152*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "data-link configuration "
153*1cb875aeSCathy Zhou 		    "failure"));
154*1cb875aeSCathy Zhou 	case VRRP_EDB:
155*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "configuration update error"));
156*1cb875aeSCathy Zhou 	case VRRP_EBADSTATE:
157*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid state"));
158*1cb875aeSCathy Zhou 	case VRRP_EVREXIST:
159*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "VRRP router already exists"));
160*1cb875aeSCathy Zhou 	case VRRP_ETOOSMALL:
161*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "not enough space"));
162*1cb875aeSCathy Zhou 	case VRRP_EINSTEXIST:
163*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "router name already exists"));
164*1cb875aeSCathy Zhou 	case VRRP_ENOTFOUND:
165*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "VRRP router not found"));
166*1cb875aeSCathy Zhou 	case VRRP_ECMD:
167*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "failed to communicate to "
168*1cb875aeSCathy Zhou 		    "vrrpd"));
169*1cb875aeSCathy Zhou 	case VRRP_EINVALADDR:
170*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid IP address"));
171*1cb875aeSCathy Zhou 	case VRRP_EINVALAF:
172*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid IP address family"));
173*1cb875aeSCathy Zhou 	case VRRP_EINVALLINK:
174*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid data-link"));
175*1cb875aeSCathy Zhou 	case VRRP_EPERM:
176*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "permission denied"));
177*1cb875aeSCathy Zhou 	case VRRP_ESYS:
178*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "system error"));
179*1cb875aeSCathy Zhou 	case VRRP_EAGAIN:
180*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "try again"));
181*1cb875aeSCathy Zhou 	case VRRP_EALREADY:
182*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "operation already in progress"));
183*1cb875aeSCathy Zhou 	case VRRP_ENOVNIC:
184*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "VRRP VNIC has not been "
185*1cb875aeSCathy Zhou 		    "created"));
186*1cb875aeSCathy Zhou 	case VRRP_ENOLINK:
187*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "the data-link does not exist"));
188*1cb875aeSCathy Zhou 	case VRRP_EINVAL:
189*1cb875aeSCathy Zhou 	default:
190*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid argument"));
191*1cb875aeSCathy Zhou 	}
192*1cb875aeSCathy Zhou }
193*1cb875aeSCathy Zhou 
194*1cb875aeSCathy Zhou const char *
195*1cb875aeSCathy Zhou vrrp_state2str(vrrp_state_t state)
196*1cb875aeSCathy Zhou {
197*1cb875aeSCathy Zhou 	switch (state) {
198*1cb875aeSCathy Zhou 	case VRRP_STATE_NONE:
199*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "NONE"));
200*1cb875aeSCathy Zhou 	case VRRP_STATE_INIT:
201*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "INIT"));
202*1cb875aeSCathy Zhou 	case VRRP_STATE_MASTER:
203*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "MASTER"));
204*1cb875aeSCathy Zhou 	case VRRP_STATE_BACKUP:
205*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "BACKUP"));
206*1cb875aeSCathy Zhou 	default:
207*1cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "INVALID"));
208*1cb875aeSCathy Zhou 	}
209*1cb875aeSCathy Zhou }
210*1cb875aeSCathy Zhou 
211*1cb875aeSCathy Zhou vrrp_err_t
212*1cb875aeSCathy Zhou vrrp_open(vrrp_handle_t *vh)
213*1cb875aeSCathy Zhou {
214*1cb875aeSCathy Zhou 	dladm_handle_t	dh;
215*1cb875aeSCathy Zhou 
216*1cb875aeSCathy Zhou 	if (dladm_open(&dh) != DLADM_STATUS_OK)
217*1cb875aeSCathy Zhou 		return (VRRP_EDLADM);
218*1cb875aeSCathy Zhou 
219*1cb875aeSCathy Zhou 	if ((*vh = malloc(sizeof (struct vrrp_handle))) == NULL) {
220*1cb875aeSCathy Zhou 		dladm_close(dh);
221*1cb875aeSCathy Zhou 		return (VRRP_ENOMEM);
222*1cb875aeSCathy Zhou 	}
223*1cb875aeSCathy Zhou 	(*vh)->vh_dh = dh;
224*1cb875aeSCathy Zhou 	return (VRRP_SUCCESS);
225*1cb875aeSCathy Zhou }
226*1cb875aeSCathy Zhou 
227*1cb875aeSCathy Zhou void
228*1cb875aeSCathy Zhou vrrp_close(vrrp_handle_t vh)
229*1cb875aeSCathy Zhou {
230*1cb875aeSCathy Zhou 	if (vh != NULL) {
231*1cb875aeSCathy Zhou 		dladm_close(vh->vh_dh);
232*1cb875aeSCathy Zhou 		free(vh);
233*1cb875aeSCathy Zhou 	}
234*1cb875aeSCathy Zhou }
235*1cb875aeSCathy Zhou 
236*1cb875aeSCathy Zhou boolean_t
237*1cb875aeSCathy Zhou vrrp_valid_name(const char *name)
238*1cb875aeSCathy Zhou {
239*1cb875aeSCathy Zhou 	const char	*c;
240*1cb875aeSCathy Zhou 
241*1cb875aeSCathy Zhou 	/*
242*1cb875aeSCathy Zhou 	 * The legal characters in a valid router name are:
243*1cb875aeSCathy Zhou 	 * alphanumeric (a-z,  A-Z,  0-9), underscore ('_'), and '.'.
244*1cb875aeSCathy Zhou 	 */
245*1cb875aeSCathy Zhou 	for (c = name; *c != '\0'; c++) {
246*1cb875aeSCathy Zhou 		if ((isalnum(*c) == 0) && (*c != '_'))
247*1cb875aeSCathy Zhou 			return (B_FALSE);
248*1cb875aeSCathy Zhou 	}
249*1cb875aeSCathy Zhou 
250*1cb875aeSCathy Zhou 	return (B_TRUE);
251*1cb875aeSCathy Zhou }
252*1cb875aeSCathy Zhou 
253*1cb875aeSCathy Zhou /*ARGSUSED*/
254*1cb875aeSCathy Zhou vrrp_err_t
255*1cb875aeSCathy Zhou vrrp_create(vrrp_handle_t vh, vrrp_vr_conf_t *conf)
256*1cb875aeSCathy Zhou {
257*1cb875aeSCathy Zhou 	vrrp_cmd_create_t	cmd;
258*1cb875aeSCathy Zhou 	vrrp_err_t		err;
259*1cb875aeSCathy Zhou 
260*1cb875aeSCathy Zhou 	cmd.vcc_cmd = VRRP_CMD_CREATE;
261*1cb875aeSCathy Zhou 	(void) memcpy(&cmd.vcc_conf, conf, sizeof (vrrp_vr_conf_t));
262*1cb875aeSCathy Zhou 
263*1cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
264*1cb875aeSCathy Zhou 	return (err);
265*1cb875aeSCathy Zhou }
266*1cb875aeSCathy Zhou 
267*1cb875aeSCathy Zhou /*ARGSUSED*/
268*1cb875aeSCathy Zhou vrrp_err_t
269*1cb875aeSCathy Zhou vrrp_delete(vrrp_handle_t vh, const char *vn)
270*1cb875aeSCathy Zhou {
271*1cb875aeSCathy Zhou 	vrrp_cmd_delete_t	cmd;
272*1cb875aeSCathy Zhou 	vrrp_err_t		err;
273*1cb875aeSCathy Zhou 
274*1cb875aeSCathy Zhou 	cmd.vcd_cmd = VRRP_CMD_DELETE;
275*1cb875aeSCathy Zhou 	if (strlcpy(cmd.vcd_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
276*1cb875aeSCathy Zhou 		return (VRRP_EINVAL);
277*1cb875aeSCathy Zhou 
278*1cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
279*1cb875aeSCathy Zhou 	return (err);
280*1cb875aeSCathy Zhou }
281*1cb875aeSCathy Zhou 
282*1cb875aeSCathy Zhou /*ARGSUSED*/
283*1cb875aeSCathy Zhou vrrp_err_t
284*1cb875aeSCathy Zhou vrrp_enable(vrrp_handle_t vh, const char *vn)
285*1cb875aeSCathy Zhou {
286*1cb875aeSCathy Zhou 	vrrp_cmd_enable_t	cmd;
287*1cb875aeSCathy Zhou 	vrrp_err_t		err;
288*1cb875aeSCathy Zhou 
289*1cb875aeSCathy Zhou 	cmd.vcs_cmd = VRRP_CMD_ENABLE;
290*1cb875aeSCathy Zhou 	if (strlcpy(cmd.vcs_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
291*1cb875aeSCathy Zhou 		return (VRRP_EINVAL);
292*1cb875aeSCathy Zhou 
293*1cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
294*1cb875aeSCathy Zhou 	return (err);
295*1cb875aeSCathy Zhou }
296*1cb875aeSCathy Zhou 
297*1cb875aeSCathy Zhou /*ARGSUSED*/
298*1cb875aeSCathy Zhou vrrp_err_t
299*1cb875aeSCathy Zhou vrrp_disable(vrrp_handle_t vh, const char *vn)
300*1cb875aeSCathy Zhou {
301*1cb875aeSCathy Zhou 	vrrp_cmd_disable_t	cmd;
302*1cb875aeSCathy Zhou 	vrrp_err_t		err;
303*1cb875aeSCathy Zhou 
304*1cb875aeSCathy Zhou 	cmd.vcx_cmd = VRRP_CMD_DISABLE;
305*1cb875aeSCathy Zhou 	if (strlcpy(cmd.vcx_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
306*1cb875aeSCathy Zhou 		return (VRRP_EINVAL);
307*1cb875aeSCathy Zhou 
308*1cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
309*1cb875aeSCathy Zhou 	return (err);
310*1cb875aeSCathy Zhou }
311*1cb875aeSCathy Zhou 
312*1cb875aeSCathy Zhou /*ARGSUSED*/
313*1cb875aeSCathy Zhou vrrp_err_t
314*1cb875aeSCathy Zhou vrrp_modify(vrrp_handle_t vh, vrrp_vr_conf_t *conf, uint32_t mask)
315*1cb875aeSCathy Zhou {
316*1cb875aeSCathy Zhou 	vrrp_cmd_modify_t	cmd;
317*1cb875aeSCathy Zhou 	vrrp_err_t		err;
318*1cb875aeSCathy Zhou 
319*1cb875aeSCathy Zhou 	cmd.vcm_cmd = VRRP_CMD_MODIFY;
320*1cb875aeSCathy Zhou 	cmd.vcm_mask = mask;
321*1cb875aeSCathy Zhou 	(void) memcpy(&cmd.vcm_conf, conf, sizeof (vrrp_vr_conf_t));
322*1cb875aeSCathy Zhou 
323*1cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
324*1cb875aeSCathy Zhou 	return (err);
325*1cb875aeSCathy Zhou }
326*1cb875aeSCathy Zhou 
327*1cb875aeSCathy Zhou typedef struct vrrp_cmd_list_arg {
328*1cb875aeSCathy Zhou 	uint32_t	*vfl_cnt;
329*1cb875aeSCathy Zhou 	char		*vfl_names;
330*1cb875aeSCathy Zhou } vrrp_cmd_list_arg_t;
331*1cb875aeSCathy Zhou 
332*1cb875aeSCathy Zhou static vrrp_err_t
333*1cb875aeSCathy Zhou vrrp_list_func(int sock, void *arg)
334*1cb875aeSCathy Zhou {
335*1cb875aeSCathy Zhou 	vrrp_cmd_list_arg_t	*list_arg = arg;
336*1cb875aeSCathy Zhou 	uint32_t		in_cnt = *(list_arg->vfl_cnt);
337*1cb875aeSCathy Zhou 	uint32_t		out_cnt;
338*1cb875aeSCathy Zhou 	vrrp_ret_list_t		ret;
339*1cb875aeSCathy Zhou 	size_t			len, cur_size = 0;
340*1cb875aeSCathy Zhou 
341*1cb875aeSCathy Zhou 	/*
342*1cb875aeSCathy Zhou 	 * Get the rest of vrrp_ret_list_t besides the error code.
343*1cb875aeSCathy Zhou 	 */
344*1cb875aeSCathy Zhou 	cur_size = sizeof (vrrp_err_t);
345*1cb875aeSCathy Zhou 	while (cur_size < sizeof (vrrp_ret_list_t)) {
346*1cb875aeSCathy Zhou 		len = read(sock, (char *)&ret + cur_size,
347*1cb875aeSCathy Zhou 		    sizeof (vrrp_ret_list_t) - cur_size);
348*1cb875aeSCathy Zhou 
349*1cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
350*1cb875aeSCathy Zhou 			continue;
351*1cb875aeSCathy Zhou 		} else if (len > 0) {
352*1cb875aeSCathy Zhou 			cur_size += len;
353*1cb875aeSCathy Zhou 			continue;
354*1cb875aeSCathy Zhou 		}
355*1cb875aeSCathy Zhou 		return (VRRP_ECMD);
356*1cb875aeSCathy Zhou 	}
357*1cb875aeSCathy Zhou 
358*1cb875aeSCathy Zhou 	*(list_arg->vfl_cnt) = out_cnt = ret.vrl_cnt;
359*1cb875aeSCathy Zhou 	out_cnt = (in_cnt <= out_cnt) ? in_cnt : out_cnt;
360*1cb875aeSCathy Zhou 	cur_size = 0;
361*1cb875aeSCathy Zhou 
362*1cb875aeSCathy Zhou 	while (cur_size < VRRP_NAME_MAX * out_cnt) {
363*1cb875aeSCathy Zhou 		len = read(sock, (char *)list_arg->vfl_names + cur_size,
364*1cb875aeSCathy Zhou 		    VRRP_NAME_MAX * out_cnt - cur_size);
365*1cb875aeSCathy Zhou 
366*1cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
367*1cb875aeSCathy Zhou 			continue;
368*1cb875aeSCathy Zhou 		} else if (len > 0) {
369*1cb875aeSCathy Zhou 			cur_size += len;
370*1cb875aeSCathy Zhou 			continue;
371*1cb875aeSCathy Zhou 		}
372*1cb875aeSCathy Zhou 		return (VRRP_ECMD);
373*1cb875aeSCathy Zhou 	}
374*1cb875aeSCathy Zhou 	return (VRRP_SUCCESS);
375*1cb875aeSCathy Zhou }
376*1cb875aeSCathy Zhou 
377*1cb875aeSCathy Zhou /*
378*1cb875aeSCathy Zhou  * Looks up the vrrp instances that matches the given variable.
379*1cb875aeSCathy Zhou  *
380*1cb875aeSCathy Zhou  * If the given cnt is 0, names should be set to NULL. In this case, only
381*1cb875aeSCathy Zhou  * the count of the matched instances is returned.
382*1cb875aeSCathy Zhou  *
383*1cb875aeSCathy Zhou  * If the given cnt is non-zero, caller must allocate "names" whose size
384*1cb875aeSCathy Zhou  * is (cnt * VRRP_NAME_MAX).
385*1cb875aeSCathy Zhou  *
386*1cb875aeSCathy Zhou  * Return value: the current count of matched instances, and names will be
387*1cb875aeSCathy Zhou  * points to the list of the current vrrp instances names. Note that
388*1cb875aeSCathy Zhou  * only MIN(in_cnt, out_cnt) number of names will be returned.
389*1cb875aeSCathy Zhou  */
390*1cb875aeSCathy Zhou /*ARGSUSED*/
391*1cb875aeSCathy Zhou vrrp_err_t
392*1cb875aeSCathy Zhou vrrp_list(vrrp_handle_t vh, vrid_t vrid, const char *intf, int af,
393*1cb875aeSCathy Zhou     uint32_t *cnt, char *names)
394*1cb875aeSCathy Zhou {
395*1cb875aeSCathy Zhou 	vrrp_cmd_list_t		cmd;
396*1cb875aeSCathy Zhou 	vrrp_err_t		err;
397*1cb875aeSCathy Zhou 	vrrp_cmd_list_arg_t	list_arg;
398*1cb875aeSCathy Zhou 
399*1cb875aeSCathy Zhou 	if ((cnt == NULL) || (*cnt != 0 && names == NULL))
400*1cb875aeSCathy Zhou 		return (VRRP_EINVAL);
401*1cb875aeSCathy Zhou 
402*1cb875aeSCathy Zhou 	cmd.vcl_ifname[0] = '\0';
403*1cb875aeSCathy Zhou 	if (intf != NULL && (strlcpy(cmd.vcl_ifname, intf,
404*1cb875aeSCathy Zhou 	    LIFNAMSIZ) >= LIFNAMSIZ)) {
405*1cb875aeSCathy Zhou 		return (VRRP_EINVAL);
406*1cb875aeSCathy Zhou 	}
407*1cb875aeSCathy Zhou 
408*1cb875aeSCathy Zhou 	cmd.vcl_cmd = VRRP_CMD_LIST;
409*1cb875aeSCathy Zhou 	cmd.vcl_vrid = vrid;
410*1cb875aeSCathy Zhou 	cmd.vcl_af = af;
411*1cb875aeSCathy Zhou 
412*1cb875aeSCathy Zhou 	list_arg.vfl_cnt = cnt;
413*1cb875aeSCathy Zhou 	list_arg.vfl_names = names;
414*1cb875aeSCathy Zhou 
415*1cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), vrrp_list_func, &list_arg);
416*1cb875aeSCathy Zhou 	return (err);
417*1cb875aeSCathy Zhou }
418*1cb875aeSCathy Zhou 
419*1cb875aeSCathy Zhou static vrrp_err_t
420*1cb875aeSCathy Zhou vrrp_query_func(int sock, void *arg)
421*1cb875aeSCathy Zhou {
422*1cb875aeSCathy Zhou 	vrrp_queryinfo_t	*qinfo = arg;
423*1cb875aeSCathy Zhou 	size_t			len, cur_size = 0, total;
424*1cb875aeSCathy Zhou 	uint32_t		in_cnt = qinfo->show_va.va_vipcnt;
425*1cb875aeSCathy Zhou 	uint32_t		out_cnt;
426*1cb875aeSCathy Zhou 
427*1cb875aeSCathy Zhou 	/*
428*1cb875aeSCathy Zhou 	 * Expect the ack, first get the vrrp_ret_t.
429*1cb875aeSCathy Zhou 	 */
430*1cb875aeSCathy Zhou 	total = sizeof (vrrp_queryinfo_t);
431*1cb875aeSCathy Zhou 	while (cur_size < total) {
432*1cb875aeSCathy Zhou 		len = read(sock, (char *)qinfo + cur_size, total - cur_size);
433*1cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
434*1cb875aeSCathy Zhou 			continue;
435*1cb875aeSCathy Zhou 		} else if (len > 0) {
436*1cb875aeSCathy Zhou 			cur_size += len;
437*1cb875aeSCathy Zhou 			continue;
438*1cb875aeSCathy Zhou 		}
439*1cb875aeSCathy Zhou 		return (VRRP_ECMD);
440*1cb875aeSCathy Zhou 	}
441*1cb875aeSCathy Zhou 
442*1cb875aeSCathy Zhou 	out_cnt = qinfo->show_va.va_vipcnt;
443*1cb875aeSCathy Zhou 
444*1cb875aeSCathy Zhou 	/*
445*1cb875aeSCathy Zhou 	 * Even if there is no IP virtual IP address, there is always
446*1cb875aeSCathy Zhou 	 * space in the vrrp_queryinfo_t structure for one virtual
447*1cb875aeSCathy Zhou 	 * IP address.
448*1cb875aeSCathy Zhou 	 */
449*1cb875aeSCathy Zhou 	out_cnt = (out_cnt == 0) ? 1 : out_cnt;
450*1cb875aeSCathy Zhou 	out_cnt = (in_cnt < out_cnt ? in_cnt : out_cnt) - 1;
451*1cb875aeSCathy Zhou 	total += out_cnt * sizeof (vrrp_addr_t);
452*1cb875aeSCathy Zhou 
453*1cb875aeSCathy Zhou 	while (cur_size < total) {
454*1cb875aeSCathy Zhou 		len = read(sock, (char *)qinfo + cur_size, total - cur_size);
455*1cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
456*1cb875aeSCathy Zhou 			continue;
457*1cb875aeSCathy Zhou 		} else if (len > 0) {
458*1cb875aeSCathy Zhou 			cur_size += len;
459*1cb875aeSCathy Zhou 			continue;
460*1cb875aeSCathy Zhou 		}
461*1cb875aeSCathy Zhou 		return (VRRP_ECMD);
462*1cb875aeSCathy Zhou 	}
463*1cb875aeSCathy Zhou 	return (VRRP_SUCCESS);
464*1cb875aeSCathy Zhou }
465*1cb875aeSCathy Zhou 
466*1cb875aeSCathy Zhou /*
467*1cb875aeSCathy Zhou  * *vqp is allocated inside this function and must be freed by the caller.
468*1cb875aeSCathy Zhou  */
469*1cb875aeSCathy Zhou /*ARGSUSED*/
470*1cb875aeSCathy Zhou vrrp_err_t
471*1cb875aeSCathy Zhou vrrp_query(vrrp_handle_t vh, const char *vn, vrrp_queryinfo_t **vqp)
472*1cb875aeSCathy Zhou {
473*1cb875aeSCathy Zhou 	vrrp_cmd_query_t	cmd;
474*1cb875aeSCathy Zhou 	vrrp_queryinfo_t	*qinfo;
475*1cb875aeSCathy Zhou 	vrrp_err_t		err;
476*1cb875aeSCathy Zhou 	size_t			size;
477*1cb875aeSCathy Zhou 	uint32_t		vipcnt = 1;
478*1cb875aeSCathy Zhou 
479*1cb875aeSCathy Zhou 	if (strlcpy(cmd.vcq_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
480*1cb875aeSCathy Zhou 		return (VRRP_EINVAL);
481*1cb875aeSCathy Zhou 
482*1cb875aeSCathy Zhou 	cmd.vcq_cmd = VRRP_CMD_QUERY;
483*1cb875aeSCathy Zhou 
484*1cb875aeSCathy Zhou 	/*
485*1cb875aeSCathy Zhou 	 * Allocate enough room for virtual IPs.
486*1cb875aeSCathy Zhou 	 */
487*1cb875aeSCathy Zhou again:
488*1cb875aeSCathy Zhou 	size = sizeof (vrrp_queryinfo_t);
489*1cb875aeSCathy Zhou 	size += (vipcnt == 0) ? 0 : (vipcnt - 1) * sizeof (vrrp_addr_t);
490*1cb875aeSCathy Zhou 	if ((qinfo = malloc(size)) == NULL) {
491*1cb875aeSCathy Zhou 		err = VRRP_ENOMEM;
492*1cb875aeSCathy Zhou 		goto done;
493*1cb875aeSCathy Zhou 	}
494*1cb875aeSCathy Zhou 
495*1cb875aeSCathy Zhou 	qinfo->show_va.va_vipcnt = vipcnt;
496*1cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), vrrp_query_func, qinfo);
497*1cb875aeSCathy Zhou 	if (err != VRRP_SUCCESS) {
498*1cb875aeSCathy Zhou 		free(qinfo);
499*1cb875aeSCathy Zhou 		goto done;
500*1cb875aeSCathy Zhou 	}
501*1cb875aeSCathy Zhou 
502*1cb875aeSCathy Zhou 	/*
503*1cb875aeSCathy Zhou 	 * If the returned number of virtual IPs is greater than we expected,
504*1cb875aeSCathy Zhou 	 * allocate more room and try again.
505*1cb875aeSCathy Zhou 	 */
506*1cb875aeSCathy Zhou 	if (qinfo->show_va.va_vipcnt > vipcnt) {
507*1cb875aeSCathy Zhou 		vipcnt = qinfo->show_va.va_vipcnt;
508*1cb875aeSCathy Zhou 		free(qinfo);
509*1cb875aeSCathy Zhou 		goto again;
510*1cb875aeSCathy Zhou 	}
511*1cb875aeSCathy Zhou 
512*1cb875aeSCathy Zhou 	*vqp = qinfo;
513*1cb875aeSCathy Zhou 
514*1cb875aeSCathy Zhou done:
515*1cb875aeSCathy Zhou 	return (err);
516*1cb875aeSCathy Zhou }
517*1cb875aeSCathy Zhou 
518*1cb875aeSCathy Zhou struct lookup_vnic_arg {
519*1cb875aeSCathy Zhou 	vrid_t		lva_vrid;
520*1cb875aeSCathy Zhou 	datalink_id_t	lva_linkid;
521*1cb875aeSCathy Zhou 	int		lva_af;
522*1cb875aeSCathy Zhou 	uint16_t	lva_vid;
523*1cb875aeSCathy Zhou 	vrrp_handle_t	lva_vh;
524*1cb875aeSCathy Zhou 	char		lva_vnic[MAXLINKNAMELEN];
525*1cb875aeSCathy Zhou };
526*1cb875aeSCathy Zhou 
527*1cb875aeSCathy Zhou /*
528*1cb875aeSCathy Zhou  * Is this a special VNIC interface created for VRRP? If so, return
529*1cb875aeSCathy Zhou  * the linkid the VNIC was created on, the VRRP ID and address family.
530*1cb875aeSCathy Zhou  */
531*1cb875aeSCathy Zhou boolean_t
532*1cb875aeSCathy Zhou vrrp_is_vrrp_vnic(vrrp_handle_t vh, datalink_id_t vnicid,
533*1cb875aeSCathy Zhou     datalink_id_t *linkidp, uint16_t *vidp, vrid_t *vridp, int *afp)
534*1cb875aeSCathy Zhou {
535*1cb875aeSCathy Zhou 	dladm_vnic_attr_t	vattr;
536*1cb875aeSCathy Zhou 
537*1cb875aeSCathy Zhou 	if (dladm_vnic_info(vh->vh_dh, vnicid, &vattr, DLADM_OPT_ACTIVE) !=
538*1cb875aeSCathy Zhou 	    DLADM_STATUS_OK) {
539*1cb875aeSCathy Zhou 		return (B_FALSE);
540*1cb875aeSCathy Zhou 	}
541*1cb875aeSCathy Zhou 
542*1cb875aeSCathy Zhou 	*vridp = vattr.va_vrid;
543*1cb875aeSCathy Zhou 	*vidp = vattr.va_vid;
544*1cb875aeSCathy Zhou 	*afp = vattr.va_af;
545*1cb875aeSCathy Zhou 	*linkidp = vattr.va_link_id;
546*1cb875aeSCathy Zhou 	return (vattr.va_vrid != VRRP_VRID_NONE);
547*1cb875aeSCathy Zhou }
548*1cb875aeSCathy Zhou 
549*1cb875aeSCathy Zhou static int
550*1cb875aeSCathy Zhou lookup_vnic(dladm_handle_t dh, datalink_id_t vnicid, void *arg)
551*1cb875aeSCathy Zhou {
552*1cb875aeSCathy Zhou 	vrid_t			vrid;
553*1cb875aeSCathy Zhou 	uint16_t		vid;
554*1cb875aeSCathy Zhou 	datalink_id_t		linkid;
555*1cb875aeSCathy Zhou 	int			af;
556*1cb875aeSCathy Zhou 	struct lookup_vnic_arg	*lva = arg;
557*1cb875aeSCathy Zhou 
558*1cb875aeSCathy Zhou 	if (vrrp_is_vrrp_vnic(lva->lva_vh, vnicid, &linkid, &vid, &vrid,
559*1cb875aeSCathy Zhou 	    &af) && lva->lva_vrid == vrid && lva->lva_linkid == linkid &&
560*1cb875aeSCathy Zhou 	    lva->lva_vid == vid && lva->lva_af == af) {
561*1cb875aeSCathy Zhou 		if (dladm_datalink_id2info(dh, vnicid, NULL, NULL, NULL,
562*1cb875aeSCathy Zhou 		    lva->lva_vnic, sizeof (lva->lva_vnic)) == DLADM_STATUS_OK) {
563*1cb875aeSCathy Zhou 			return (DLADM_WALK_TERMINATE);
564*1cb875aeSCathy Zhou 		}
565*1cb875aeSCathy Zhou 	}
566*1cb875aeSCathy Zhou 	return (DLADM_WALK_CONTINUE);
567*1cb875aeSCathy Zhou }
568*1cb875aeSCathy Zhou 
569*1cb875aeSCathy Zhou /*
570*1cb875aeSCathy Zhou  * Given the primary link name, find the assoicated VRRP vnic name, if
571*1cb875aeSCathy Zhou  * the vnic does not exist yet, return the linkid, vid of the primary link.
572*1cb875aeSCathy Zhou  */
573*1cb875aeSCathy Zhou vrrp_err_t
574*1cb875aeSCathy Zhou vrrp_get_vnicname(vrrp_handle_t vh, vrid_t vrid, int af, char *link,
575*1cb875aeSCathy Zhou     datalink_id_t *linkidp, uint16_t *vidp, char *vnic, size_t len)
576*1cb875aeSCathy Zhou {
577*1cb875aeSCathy Zhou 	datalink_id_t		linkid;
578*1cb875aeSCathy Zhou 	uint32_t		flags;
579*1cb875aeSCathy Zhou 	uint16_t		vid = VLAN_ID_NONE;
580*1cb875aeSCathy Zhou 	datalink_class_t	class;
581*1cb875aeSCathy Zhou 	dladm_vlan_attr_t	vlan_attr;
582*1cb875aeSCathy Zhou 	struct lookup_vnic_arg	lva;
583*1cb875aeSCathy Zhou 	uint32_t		media;
584*1cb875aeSCathy Zhou 
585*1cb875aeSCathy Zhou 	if ((strlen(link) == 0) || dladm_name2info(vh->vh_dh,
586*1cb875aeSCathy Zhou 	    link, &linkid, &flags, &class, &media) !=
587*1cb875aeSCathy Zhou 	    DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) {
588*1cb875aeSCathy Zhou 		return (VRRP_EINVAL);
589*1cb875aeSCathy Zhou 	}
590*1cb875aeSCathy Zhou 
591*1cb875aeSCathy Zhou 	if (class == DATALINK_CLASS_VLAN) {
592*1cb875aeSCathy Zhou 		if (dladm_vlan_info(vh->vh_dh, linkid, &vlan_attr,
593*1cb875aeSCathy Zhou 		    DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
594*1cb875aeSCathy Zhou 			return (VRRP_EINVAL);
595*1cb875aeSCathy Zhou 		}
596*1cb875aeSCathy Zhou 		linkid = vlan_attr.dv_linkid;
597*1cb875aeSCathy Zhou 		vid = vlan_attr.dv_vid;
598*1cb875aeSCathy Zhou 		if ((dladm_datalink_id2info(vh->vh_dh, linkid, NULL,
599*1cb875aeSCathy Zhou 		    &class, &media, NULL, 0)) != DLADM_STATUS_OK) {
600*1cb875aeSCathy Zhou 			return (VRRP_EINVAL);
601*1cb875aeSCathy Zhou 		}
602*1cb875aeSCathy Zhou 	}
603*1cb875aeSCathy Zhou 
604*1cb875aeSCathy Zhou 	/*
605*1cb875aeSCathy Zhou 	 * For now, Only VRRP over aggr and physical ethernet links is supported
606*1cb875aeSCathy Zhou 	 */
607*1cb875aeSCathy Zhou 	if ((class != DATALINK_CLASS_PHYS && class != DATALINK_CLASS_AGGR) ||
608*1cb875aeSCathy Zhou 	    media != DL_ETHER) {
609*1cb875aeSCathy Zhou 		return (VRRP_EINVAL);
610*1cb875aeSCathy Zhou 	}
611*1cb875aeSCathy Zhou 
612*1cb875aeSCathy Zhou 	if (linkidp != NULL)
613*1cb875aeSCathy Zhou 		*linkidp = linkid;
614*1cb875aeSCathy Zhou 	if (vidp != NULL)
615*1cb875aeSCathy Zhou 		*vidp = vid;
616*1cb875aeSCathy Zhou 
617*1cb875aeSCathy Zhou 	/*
618*1cb875aeSCathy Zhou 	 * Find the assoicated vnic with the given vrid/vid/af/linkid
619*1cb875aeSCathy Zhou 	 */
620*1cb875aeSCathy Zhou 	lva.lva_vrid = vrid;
621*1cb875aeSCathy Zhou 	lva.lva_vid = vid;
622*1cb875aeSCathy Zhou 	lva.lva_af = af;
623*1cb875aeSCathy Zhou 	lva.lva_linkid = linkid;
624*1cb875aeSCathy Zhou 	lva.lva_vh = vh;
625*1cb875aeSCathy Zhou 	lva.lva_vnic[0] = '\0';
626*1cb875aeSCathy Zhou 
627*1cb875aeSCathy Zhou 	(void) dladm_walk_datalink_id(lookup_vnic, vh->vh_dh, &lva,
628*1cb875aeSCathy Zhou 	    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
629*1cb875aeSCathy Zhou 	if (strlen(lva.lva_vnic) != 0) {
630*1cb875aeSCathy Zhou 		(void) strlcpy(vnic, lva.lva_vnic, len);
631*1cb875aeSCathy Zhou 		return (VRRP_SUCCESS);
632*1cb875aeSCathy Zhou 	}
633*1cb875aeSCathy Zhou 
634*1cb875aeSCathy Zhou 	return (VRRP_ENOVNIC);
635*1cb875aeSCathy Zhou }
636