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