11cb875aeSCathy Zhou /*
21cb875aeSCathy Zhou  * CDDL HEADER START
31cb875aeSCathy Zhou  *
41cb875aeSCathy Zhou  * The contents of this file are subject to the terms of the
51cb875aeSCathy Zhou  * Common Development and Distribution License (the "License").
61cb875aeSCathy Zhou  * You may not use this file except in compliance with the License.
71cb875aeSCathy Zhou  *
81cb875aeSCathy Zhou  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91cb875aeSCathy Zhou  * or http://www.opensolaris.org/os/licensing.
101cb875aeSCathy Zhou  * See the License for the specific language governing permissions
111cb875aeSCathy Zhou  * and limitations under the License.
121cb875aeSCathy Zhou  *
131cb875aeSCathy Zhou  * When distributing Covered Code, include this CDDL HEADER in each
141cb875aeSCathy Zhou  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151cb875aeSCathy Zhou  * If applicable, add the following below this CDDL HEADER, with the
161cb875aeSCathy Zhou  * fields enclosed by brackets "[]" replaced with your own identifying
171cb875aeSCathy Zhou  * information: Portions Copyright [yyyy] [name of copyright owner]
181cb875aeSCathy Zhou  *
191cb875aeSCathy Zhou  * CDDL HEADER END
201cb875aeSCathy Zhou  */
211cb875aeSCathy Zhou 
221cb875aeSCathy Zhou /*
23c5e0ece0SCathy Zhou  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
241cb875aeSCathy Zhou  * Use is subject to license terms.
251cb875aeSCathy Zhou  */
261cb875aeSCathy Zhou 
27*2954adb0SRob Gulewich /*
28*2954adb0SRob Gulewich  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
29*2954adb0SRob Gulewich  */
30*2954adb0SRob Gulewich 
311cb875aeSCathy Zhou #include <sys/types.h>
321cb875aeSCathy Zhou #include <sys/stat.h>
331cb875aeSCathy Zhou #include <sys/socket.h>
341cb875aeSCathy Zhou #include <sys/mman.h>
351cb875aeSCathy Zhou #include <sys/varargs.h>
361cb875aeSCathy Zhou #include <sys/vlan.h>
371cb875aeSCathy Zhou #include <errno.h>
381cb875aeSCathy Zhou #include <ctype.h>
391cb875aeSCathy Zhou #include <fcntl.h>
401cb875aeSCathy Zhou #include <unistd.h>
411cb875aeSCathy Zhou #include <stdio.h>
421cb875aeSCathy Zhou #include <stdlib.h>
431cb875aeSCathy Zhou #include <string.h>
441cb875aeSCathy Zhou #include <netinet/in.h>
451cb875aeSCathy Zhou #include <arpa/inet.h>
461cb875aeSCathy Zhou #include <net/if.h>	/* LIFNAMSIZ */
471cb875aeSCathy Zhou #include <netinet/vrrp.h>
481cb875aeSCathy Zhou #include <libdladm.h>
491cb875aeSCathy Zhou #include <libdlvnic.h>
501cb875aeSCathy Zhou #include <libdlvlan.h>
511cb875aeSCathy Zhou #include <libdllink.h>
521cb875aeSCathy Zhou #include <libintl.h>
53c5e0ece0SCathy Zhou #include <libscf.h>
541cb875aeSCathy Zhou #include <libvrrpadm.h>
551cb875aeSCathy Zhou 
56c5e0ece0SCathy Zhou #define	VRRP_SERVICE	"network/vrrp:default"
57c5e0ece0SCathy Zhou 
581cb875aeSCathy Zhou typedef vrrp_err_t vrrp_cmd_func_t(int, void *);
591cb875aeSCathy Zhou 
60c5e0ece0SCathy Zhou static boolean_t
vrrp_svc_isonline(char * svc_name)61c5e0ece0SCathy Zhou vrrp_svc_isonline(char *svc_name)
62c5e0ece0SCathy Zhou {
63c5e0ece0SCathy Zhou 	char		*s;
64c5e0ece0SCathy Zhou 	boolean_t	isonline = B_FALSE;
65c5e0ece0SCathy Zhou 
66c5e0ece0SCathy Zhou 	if ((s = smf_get_state(svc_name)) != NULL) {
67c5e0ece0SCathy Zhou 		if (strcmp(s, SCF_STATE_STRING_ONLINE) == 0)
68c5e0ece0SCathy Zhou 			isonline = B_TRUE;
69c5e0ece0SCathy Zhou 		free(s);
70c5e0ece0SCathy Zhou 	}
71c5e0ece0SCathy Zhou 
72c5e0ece0SCathy Zhou 	return (isonline);
73c5e0ece0SCathy Zhou }
74c5e0ece0SCathy Zhou 
75c5e0ece0SCathy Zhou #define	MAX_WAIT_TIME	15
76c5e0ece0SCathy Zhou 
77c5e0ece0SCathy Zhou static vrrp_err_t
vrrp_enable_service()78c5e0ece0SCathy Zhou vrrp_enable_service()
79c5e0ece0SCathy Zhou {
80c5e0ece0SCathy Zhou 	int	i;
81c5e0ece0SCathy Zhou 
82c5e0ece0SCathy Zhou 	if (vrrp_svc_isonline(VRRP_SERVICE))
83c5e0ece0SCathy Zhou 		return (VRRP_SUCCESS);
84c5e0ece0SCathy Zhou 
85c5e0ece0SCathy Zhou 	if (smf_enable_instance(VRRP_SERVICE, 0) == -1) {
86c5e0ece0SCathy Zhou 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
87c5e0ece0SCathy Zhou 			return (VRRP_EPERM);
88c5e0ece0SCathy Zhou 		else
89c5e0ece0SCathy Zhou 			return (VRRP_ENOSVC);
90c5e0ece0SCathy Zhou 	}
91c5e0ece0SCathy Zhou 
92c5e0ece0SCathy Zhou 	/*
93c5e0ece0SCathy Zhou 	 * Wait up to MAX_WAIT_TIME seconds for the VRRP service being brought
94c5e0ece0SCathy Zhou 	 * up online
95c5e0ece0SCathy Zhou 	 */
96c5e0ece0SCathy Zhou 	for (i = 0; i < MAX_WAIT_TIME; i++) {
97c5e0ece0SCathy Zhou 		if (vrrp_svc_isonline(VRRP_SERVICE))
98c5e0ece0SCathy Zhou 			break;
99c5e0ece0SCathy Zhou 		(void) sleep(1);
100c5e0ece0SCathy Zhou 	}
101c5e0ece0SCathy Zhou 	if (i == MAX_WAIT_TIME)
102c5e0ece0SCathy Zhou 		return (VRRP_ENOSVC);
103c5e0ece0SCathy Zhou 
104c5e0ece0SCathy Zhou 	return (VRRP_SUCCESS);
105c5e0ece0SCathy Zhou }
106c5e0ece0SCathy Zhou 
107c5e0ece0SCathy Zhou /*
108c5e0ece0SCathy Zhou  * Disable the VRRP service if there is no VRRP router left.
109c5e0ece0SCathy Zhou  */
110c5e0ece0SCathy Zhou static void
vrrp_disable_service_when_no_router()111c5e0ece0SCathy Zhou vrrp_disable_service_when_no_router()
112c5e0ece0SCathy Zhou {
113c5e0ece0SCathy Zhou 	uint32_t	cnt = 0;
114c5e0ece0SCathy Zhou 
115c5e0ece0SCathy Zhou 	/*
116c5e0ece0SCathy Zhou 	 * Get the number of the existing routers. If there is no routers
117c5e0ece0SCathy Zhou 	 * left, disable the service.
118c5e0ece0SCathy Zhou 	 */
119c5e0ece0SCathy Zhou 	if (vrrp_list(NULL, VRRP_VRID_NONE, NULL, AF_UNSPEC, &cnt,
120c5e0ece0SCathy Zhou 	    NULL) == VRRP_SUCCESS && cnt == 0) {
121c5e0ece0SCathy Zhou 		(void) smf_disable_instance(VRRP_SERVICE, 0);
122c5e0ece0SCathy Zhou 	}
123c5e0ece0SCathy Zhou }
124c5e0ece0SCathy Zhou 
1251cb875aeSCathy Zhou static vrrp_err_t
vrrp_cmd_request(void * cmd,size_t csize,vrrp_cmd_func_t func,void * arg)1261cb875aeSCathy Zhou vrrp_cmd_request(void *cmd, size_t csize, vrrp_cmd_func_t func, void *arg)
1271cb875aeSCathy Zhou {
1281cb875aeSCathy Zhou 	struct sockaddr_un	to;
1291cb875aeSCathy Zhou 	int			sock, flags;
1301cb875aeSCathy Zhou 	size_t			len, cur_size = 0;
1311cb875aeSCathy Zhou 	vrrp_ret_t		ret;
1321cb875aeSCathy Zhou 	vrrp_err_t		err;
1331cb875aeSCathy Zhou 
1341cb875aeSCathy Zhou 	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
135c5e0ece0SCathy Zhou 		return (VRRP_ESYS);
1361cb875aeSCathy Zhou 
1371cb875aeSCathy Zhou 	/*
1381cb875aeSCathy Zhou 	 * Set it to be non-blocking.
1391cb875aeSCathy Zhou 	 */
1401cb875aeSCathy Zhou 	flags = fcntl(sock, F_GETFL, 0);
1411cb875aeSCathy Zhou 	(void) fcntl(sock, F_SETFL, (flags | O_NONBLOCK));
1421cb875aeSCathy Zhou 
1431cb875aeSCathy Zhou 	(void) memset(&to, 0, sizeof (to));
1441cb875aeSCathy Zhou 	to.sun_family = AF_UNIX;
1451cb875aeSCathy Zhou 	(void) strlcpy(to.sun_path, VRRPD_SOCKET, sizeof (to.sun_path));
1461cb875aeSCathy Zhou 
1471cb875aeSCathy Zhou 	/*
1481cb875aeSCathy Zhou 	 * Connect to vrrpd
1491cb875aeSCathy Zhou 	 */
1501cb875aeSCathy Zhou 	if (connect(sock, (const struct sockaddr *)&to, sizeof (to)) < 0) {
1511cb875aeSCathy Zhou 		(void) close(sock);
152c5e0ece0SCathy Zhou 		return (VRRP_ENOSVC);
1531cb875aeSCathy Zhou 	}
1541cb875aeSCathy Zhou 
1551cb875aeSCathy Zhou 	/*
1561cb875aeSCathy Zhou 	 * Send the request
1571cb875aeSCathy Zhou 	 */
1581cb875aeSCathy Zhou 	while (cur_size < csize) {
1591cb875aeSCathy Zhou 		len = write(sock, (char *)cmd + cur_size, csize - cur_size);
1601cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
1611cb875aeSCathy Zhou 			continue;
1621cb875aeSCathy Zhou 		} else if (len > 0) {
1631cb875aeSCathy Zhou 			cur_size += len;
1641cb875aeSCathy Zhou 			continue;
1651cb875aeSCathy Zhou 		}
1661cb875aeSCathy Zhou 		(void) close(sock);
167c5e0ece0SCathy Zhou 		return (VRRP_ENOSVC);
1681cb875aeSCathy Zhou 	}
1691cb875aeSCathy Zhou 
1701cb875aeSCathy Zhou 	/*
1711cb875aeSCathy Zhou 	 * Expect the ack, first get the error code.
1721cb875aeSCathy Zhou 	 */
1731cb875aeSCathy Zhou 	cur_size = 0;
1741cb875aeSCathy Zhou 	while (cur_size < sizeof (vrrp_err_t)) {
1751cb875aeSCathy Zhou 		len = read(sock, (char *)&ret + cur_size,
1761cb875aeSCathy Zhou 		    sizeof (vrrp_err_t) - cur_size);
1771cb875aeSCathy Zhou 
1781cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
1791cb875aeSCathy Zhou 			continue;
1801cb875aeSCathy Zhou 		} else if (len > 0) {
1811cb875aeSCathy Zhou 			cur_size += len;
1821cb875aeSCathy Zhou 			continue;
1831cb875aeSCathy Zhou 		}
1841cb875aeSCathy Zhou 		(void) close(sock);
185c5e0ece0SCathy Zhou 		return (VRRP_ESYS);
1861cb875aeSCathy Zhou 	}
1871cb875aeSCathy Zhou 
1881cb875aeSCathy Zhou 	if ((err = ret.vr_err) != VRRP_SUCCESS)
1891cb875aeSCathy Zhou 		goto done;
1901cb875aeSCathy Zhou 
1911cb875aeSCathy Zhou 	/*
1921cb875aeSCathy Zhou 	 * The specific callback gets the rest of the information.
1931cb875aeSCathy Zhou 	 */
1941cb875aeSCathy Zhou 	if (func != NULL)
1951cb875aeSCathy Zhou 		err = func(sock, arg);
1961cb875aeSCathy Zhou 
1971cb875aeSCathy Zhou done:
1981cb875aeSCathy Zhou 	(void) close(sock);
1991cb875aeSCathy Zhou 	return (err);
2001cb875aeSCathy Zhou }
2011cb875aeSCathy Zhou 
2021cb875aeSCathy Zhou /*
2031cb875aeSCathy Zhou  * public APIs
2041cb875aeSCathy Zhou  */
2051cb875aeSCathy Zhou const char *
vrrp_err2str(vrrp_err_t err)2061cb875aeSCathy Zhou vrrp_err2str(vrrp_err_t err)
2071cb875aeSCathy Zhou {
2081cb875aeSCathy Zhou 	switch (err) {
2091cb875aeSCathy Zhou 	case VRRP_SUCCESS:
2101cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "success"));
2111cb875aeSCathy Zhou 	case VRRP_ENOMEM:
2121cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "not enough memory"));
2131cb875aeSCathy Zhou 	case VRRP_EINVALVRNAME:
2141cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid router name"));
2151cb875aeSCathy Zhou 	case VRRP_ENOPRIM:
2161cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "no primary IP"));
2171cb875aeSCathy Zhou 	case VRRP_EEXIST:
2181cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "already exists"));
2191cb875aeSCathy Zhou 	case VRRP_ENOVIRT:
2201cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "no virtual IPs"));
2211cb875aeSCathy Zhou 	case VRRP_EIPADM:
2221cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "ip configuration failure"));
2231cb875aeSCathy Zhou 	case VRRP_EDLADM:
2241cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "data-link configuration "
2251cb875aeSCathy Zhou 		    "failure"));
2261cb875aeSCathy Zhou 	case VRRP_EDB:
2271cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "configuration update error"));
2281cb875aeSCathy Zhou 	case VRRP_EBADSTATE:
2291cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid state"));
2301cb875aeSCathy Zhou 	case VRRP_EVREXIST:
2311cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "VRRP router already exists"));
2321cb875aeSCathy Zhou 	case VRRP_ETOOSMALL:
2331cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "not enough space"));
2341cb875aeSCathy Zhou 	case VRRP_EINSTEXIST:
2351cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "router name already exists"));
2361cb875aeSCathy Zhou 	case VRRP_ENOTFOUND:
2371cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "VRRP router not found"));
2381cb875aeSCathy Zhou 	case VRRP_EINVALADDR:
2391cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid IP address"));
2401cb875aeSCathy Zhou 	case VRRP_EINVALAF:
2411cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid IP address family"));
2421cb875aeSCathy Zhou 	case VRRP_EINVALLINK:
2431cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid data-link"));
2441cb875aeSCathy Zhou 	case VRRP_EPERM:
2451cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "permission denied"));
2461cb875aeSCathy Zhou 	case VRRP_ESYS:
2471cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "system error"));
2481cb875aeSCathy Zhou 	case VRRP_EAGAIN:
2491cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "try again"));
2501cb875aeSCathy Zhou 	case VRRP_EALREADY:
2511cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "operation already in progress"));
2521cb875aeSCathy Zhou 	case VRRP_ENOVNIC:
2531cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "VRRP VNIC has not been "
2541cb875aeSCathy Zhou 		    "created"));
2551cb875aeSCathy Zhou 	case VRRP_ENOLINK:
2561cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "the data-link does not exist"));
257c5e0ece0SCathy Zhou 	case VRRP_ENOSVC:
258c5e0ece0SCathy Zhou 		return (dgettext(TEXT_DOMAIN, "the VRRP service cannot "
259c5e0ece0SCathy Zhou 		    "be enabled"));
2601cb875aeSCathy Zhou 	case VRRP_EINVAL:
2611cb875aeSCathy Zhou 	default:
2621cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "invalid argument"));
2631cb875aeSCathy Zhou 	}
2641cb875aeSCathy Zhou }
2651cb875aeSCathy Zhou 
2661cb875aeSCathy Zhou const char *
vrrp_state2str(vrrp_state_t state)2671cb875aeSCathy Zhou vrrp_state2str(vrrp_state_t state)
2681cb875aeSCathy Zhou {
2691cb875aeSCathy Zhou 	switch (state) {
2701cb875aeSCathy Zhou 	case VRRP_STATE_NONE:
2711cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "NONE"));
2721cb875aeSCathy Zhou 	case VRRP_STATE_INIT:
2731cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "INIT"));
2741cb875aeSCathy Zhou 	case VRRP_STATE_MASTER:
2751cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "MASTER"));
2761cb875aeSCathy Zhou 	case VRRP_STATE_BACKUP:
2771cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "BACKUP"));
2781cb875aeSCathy Zhou 	default:
2791cb875aeSCathy Zhou 		return (dgettext(TEXT_DOMAIN, "INVALID"));
2801cb875aeSCathy Zhou 	}
2811cb875aeSCathy Zhou }
2821cb875aeSCathy Zhou 
2831cb875aeSCathy Zhou vrrp_err_t
vrrp_open(vrrp_handle_t * vh)2841cb875aeSCathy Zhou vrrp_open(vrrp_handle_t *vh)
2851cb875aeSCathy Zhou {
2861cb875aeSCathy Zhou 	dladm_handle_t	dh;
2871cb875aeSCathy Zhou 
2881cb875aeSCathy Zhou 	if (dladm_open(&dh) != DLADM_STATUS_OK)
2891cb875aeSCathy Zhou 		return (VRRP_EDLADM);
2901cb875aeSCathy Zhou 
2911cb875aeSCathy Zhou 	if ((*vh = malloc(sizeof (struct vrrp_handle))) == NULL) {
2921cb875aeSCathy Zhou 		dladm_close(dh);
2931cb875aeSCathy Zhou 		return (VRRP_ENOMEM);
2941cb875aeSCathy Zhou 	}
2951cb875aeSCathy Zhou 	(*vh)->vh_dh = dh;
2961cb875aeSCathy Zhou 	return (VRRP_SUCCESS);
2971cb875aeSCathy Zhou }
2981cb875aeSCathy Zhou 
2991cb875aeSCathy Zhou void
vrrp_close(vrrp_handle_t vh)3001cb875aeSCathy Zhou vrrp_close(vrrp_handle_t vh)
3011cb875aeSCathy Zhou {
3021cb875aeSCathy Zhou 	if (vh != NULL) {
3031cb875aeSCathy Zhou 		dladm_close(vh->vh_dh);
3041cb875aeSCathy Zhou 		free(vh);
3051cb875aeSCathy Zhou 	}
3061cb875aeSCathy Zhou }
3071cb875aeSCathy Zhou 
3081cb875aeSCathy Zhou boolean_t
vrrp_valid_name(const char * name)3091cb875aeSCathy Zhou vrrp_valid_name(const char *name)
3101cb875aeSCathy Zhou {
3111cb875aeSCathy Zhou 	const char	*c;
3121cb875aeSCathy Zhou 
3131cb875aeSCathy Zhou 	/*
3141cb875aeSCathy Zhou 	 * The legal characters in a valid router name are:
3151cb875aeSCathy Zhou 	 * alphanumeric (a-z,  A-Z,  0-9), underscore ('_'), and '.'.
3161cb875aeSCathy Zhou 	 */
3171cb875aeSCathy Zhou 	for (c = name; *c != '\0'; c++) {
3181cb875aeSCathy Zhou 		if ((isalnum(*c) == 0) && (*c != '_'))
3191cb875aeSCathy Zhou 			return (B_FALSE);
3201cb875aeSCathy Zhou 	}
3211cb875aeSCathy Zhou 
3221cb875aeSCathy Zhou 	return (B_TRUE);
3231cb875aeSCathy Zhou }
3241cb875aeSCathy Zhou 
3251cb875aeSCathy Zhou /*ARGSUSED*/
3261cb875aeSCathy Zhou vrrp_err_t
vrrp_create(vrrp_handle_t vh,vrrp_vr_conf_t * conf)3271cb875aeSCathy Zhou vrrp_create(vrrp_handle_t vh, vrrp_vr_conf_t *conf)
3281cb875aeSCathy Zhou {
3291cb875aeSCathy Zhou 	vrrp_cmd_create_t	cmd;
3301cb875aeSCathy Zhou 	vrrp_err_t		err;
3311cb875aeSCathy Zhou 
332c5e0ece0SCathy Zhou again:
333c5e0ece0SCathy Zhou 	/*
334c5e0ece0SCathy Zhou 	 * Enable the VRRP service if it is not already enabled.
335c5e0ece0SCathy Zhou 	 */
336c5e0ece0SCathy Zhou 	if ((err = vrrp_enable_service()) != VRRP_SUCCESS)
337c5e0ece0SCathy Zhou 		return (err);
338c5e0ece0SCathy Zhou 
3391cb875aeSCathy Zhou 	cmd.vcc_cmd = VRRP_CMD_CREATE;
3401cb875aeSCathy Zhou 	(void) memcpy(&cmd.vcc_conf, conf, sizeof (vrrp_vr_conf_t));
3411cb875aeSCathy Zhou 
3421cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
343c5e0ece0SCathy Zhou 	if (err == VRRP_ENOSVC) {
344c5e0ece0SCathy Zhou 		/*
345c5e0ece0SCathy Zhou 		 * This may be due to another process is deleting the last
346c5e0ece0SCathy Zhou 		 * router and disabled the VRRP service, try again.
347c5e0ece0SCathy Zhou 		 */
348c5e0ece0SCathy Zhou 		goto again;
349c5e0ece0SCathy Zhou 	} else if (err != VRRP_SUCCESS) {
350c5e0ece0SCathy Zhou 		/*
351c5e0ece0SCathy Zhou 		 * If router cannot be created, check if the VRRP service
352c5e0ece0SCathy Zhou 		 * should be disabled, and disable if needed.
353c5e0ece0SCathy Zhou 		 */
354c5e0ece0SCathy Zhou 		vrrp_disable_service_when_no_router();
355c5e0ece0SCathy Zhou 	}
356c5e0ece0SCathy Zhou 
3571cb875aeSCathy Zhou 	return (err);
3581cb875aeSCathy Zhou }
3591cb875aeSCathy Zhou 
3601cb875aeSCathy Zhou /*ARGSUSED*/
3611cb875aeSCathy Zhou vrrp_err_t
vrrp_delete(vrrp_handle_t vh,const char * vn)3621cb875aeSCathy Zhou vrrp_delete(vrrp_handle_t vh, const char *vn)
3631cb875aeSCathy Zhou {
3641cb875aeSCathy Zhou 	vrrp_cmd_delete_t	cmd;
3651cb875aeSCathy Zhou 	vrrp_err_t		err;
3661cb875aeSCathy Zhou 
367c5e0ece0SCathy Zhou 	/*
368c5e0ece0SCathy Zhou 	 * If the VRRP service is not enabled, we assume there is no router
369c5e0ece0SCathy Zhou 	 * configured.
370c5e0ece0SCathy Zhou 	 */
371c5e0ece0SCathy Zhou 	if (!vrrp_svc_isonline(VRRP_SERVICE))
372c5e0ece0SCathy Zhou 		return (VRRP_ENOTFOUND);
373c5e0ece0SCathy Zhou 
3741cb875aeSCathy Zhou 	cmd.vcd_cmd = VRRP_CMD_DELETE;
3751cb875aeSCathy Zhou 	if (strlcpy(cmd.vcd_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
3761cb875aeSCathy Zhou 		return (VRRP_EINVAL);
3771cb875aeSCathy Zhou 
3781cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
379c5e0ece0SCathy Zhou 	if (err == VRRP_SUCCESS)
380c5e0ece0SCathy Zhou 		vrrp_disable_service_when_no_router();
3811cb875aeSCathy Zhou 	return (err);
3821cb875aeSCathy Zhou }
3831cb875aeSCathy Zhou 
3841cb875aeSCathy Zhou /*ARGSUSED*/
3851cb875aeSCathy Zhou vrrp_err_t
vrrp_enable(vrrp_handle_t vh,const char * vn)3861cb875aeSCathy Zhou vrrp_enable(vrrp_handle_t vh, const char *vn)
3871cb875aeSCathy Zhou {
3881cb875aeSCathy Zhou 	vrrp_cmd_enable_t	cmd;
3891cb875aeSCathy Zhou 	vrrp_err_t		err;
3901cb875aeSCathy Zhou 
391c5e0ece0SCathy Zhou 	/*
392c5e0ece0SCathy Zhou 	 * If the VRRP service is not enabled, we assume there is no router
393c5e0ece0SCathy Zhou 	 * configured.
394c5e0ece0SCathy Zhou 	 */
395c5e0ece0SCathy Zhou 	if (!vrrp_svc_isonline(VRRP_SERVICE))
396c5e0ece0SCathy Zhou 		return (VRRP_ENOTFOUND);
397c5e0ece0SCathy Zhou 
3981cb875aeSCathy Zhou 	cmd.vcs_cmd = VRRP_CMD_ENABLE;
3991cb875aeSCathy Zhou 	if (strlcpy(cmd.vcs_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
4001cb875aeSCathy Zhou 		return (VRRP_EINVAL);
4011cb875aeSCathy Zhou 
4021cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
4031cb875aeSCathy Zhou 	return (err);
4041cb875aeSCathy Zhou }
4051cb875aeSCathy Zhou 
4061cb875aeSCathy Zhou /*ARGSUSED*/
4071cb875aeSCathy Zhou vrrp_err_t
vrrp_disable(vrrp_handle_t vh,const char * vn)4081cb875aeSCathy Zhou vrrp_disable(vrrp_handle_t vh, const char *vn)
4091cb875aeSCathy Zhou {
4101cb875aeSCathy Zhou 	vrrp_cmd_disable_t	cmd;
4111cb875aeSCathy Zhou 	vrrp_err_t		err;
4121cb875aeSCathy Zhou 
413c5e0ece0SCathy Zhou 	/*
414c5e0ece0SCathy Zhou 	 * If the VRRP service is not enabled, we assume there is no router
415c5e0ece0SCathy Zhou 	 * configured.
416c5e0ece0SCathy Zhou 	 */
417c5e0ece0SCathy Zhou 	if (!vrrp_svc_isonline(VRRP_SERVICE))
418c5e0ece0SCathy Zhou 		return (VRRP_ENOTFOUND);
419c5e0ece0SCathy Zhou 
4201cb875aeSCathy Zhou 	cmd.vcx_cmd = VRRP_CMD_DISABLE;
4211cb875aeSCathy Zhou 	if (strlcpy(cmd.vcx_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
4221cb875aeSCathy Zhou 		return (VRRP_EINVAL);
4231cb875aeSCathy Zhou 
4241cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
4251cb875aeSCathy Zhou 	return (err);
4261cb875aeSCathy Zhou }
4271cb875aeSCathy Zhou 
4281cb875aeSCathy Zhou /*ARGSUSED*/
4291cb875aeSCathy Zhou vrrp_err_t
vrrp_modify(vrrp_handle_t vh,vrrp_vr_conf_t * conf,uint32_t mask)4301cb875aeSCathy Zhou vrrp_modify(vrrp_handle_t vh, vrrp_vr_conf_t *conf, uint32_t mask)
4311cb875aeSCathy Zhou {
4321cb875aeSCathy Zhou 	vrrp_cmd_modify_t	cmd;
4331cb875aeSCathy Zhou 	vrrp_err_t		err;
4341cb875aeSCathy Zhou 
435c5e0ece0SCathy Zhou 	/*
436c5e0ece0SCathy Zhou 	 * If the VRRP service is not enabled, we assume there is no router
437c5e0ece0SCathy Zhou 	 * configured.
438c5e0ece0SCathy Zhou 	 */
439c5e0ece0SCathy Zhou 	if (!vrrp_svc_isonline(VRRP_SERVICE))
440c5e0ece0SCathy Zhou 		return (VRRP_ENOTFOUND);
441c5e0ece0SCathy Zhou 
4421cb875aeSCathy Zhou 	cmd.vcm_cmd = VRRP_CMD_MODIFY;
4431cb875aeSCathy Zhou 	cmd.vcm_mask = mask;
4441cb875aeSCathy Zhou 	(void) memcpy(&cmd.vcm_conf, conf, sizeof (vrrp_vr_conf_t));
4451cb875aeSCathy Zhou 
4461cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
4471cb875aeSCathy Zhou 	return (err);
4481cb875aeSCathy Zhou }
4491cb875aeSCathy Zhou 
4501cb875aeSCathy Zhou typedef struct vrrp_cmd_list_arg {
4511cb875aeSCathy Zhou 	uint32_t	*vfl_cnt;
4521cb875aeSCathy Zhou 	char		*vfl_names;
4531cb875aeSCathy Zhou } vrrp_cmd_list_arg_t;
4541cb875aeSCathy Zhou 
4551cb875aeSCathy Zhou static vrrp_err_t
vrrp_list_func(int sock,void * arg)4561cb875aeSCathy Zhou vrrp_list_func(int sock, void *arg)
4571cb875aeSCathy Zhou {
4581cb875aeSCathy Zhou 	vrrp_cmd_list_arg_t	*list_arg = arg;
4591cb875aeSCathy Zhou 	uint32_t		in_cnt = *(list_arg->vfl_cnt);
4601cb875aeSCathy Zhou 	uint32_t		out_cnt;
4611cb875aeSCathy Zhou 	vrrp_ret_list_t		ret;
4621cb875aeSCathy Zhou 	size_t			len, cur_size = 0;
4631cb875aeSCathy Zhou 
4641cb875aeSCathy Zhou 	/*
4651cb875aeSCathy Zhou 	 * Get the rest of vrrp_ret_list_t besides the error code.
4661cb875aeSCathy Zhou 	 */
4671cb875aeSCathy Zhou 	cur_size = sizeof (vrrp_err_t);
4681cb875aeSCathy Zhou 	while (cur_size < sizeof (vrrp_ret_list_t)) {
4691cb875aeSCathy Zhou 		len = read(sock, (char *)&ret + cur_size,
4701cb875aeSCathy Zhou 		    sizeof (vrrp_ret_list_t) - cur_size);
4711cb875aeSCathy Zhou 
4721cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
4731cb875aeSCathy Zhou 			continue;
4741cb875aeSCathy Zhou 		} else if (len > 0) {
4751cb875aeSCathy Zhou 			cur_size += len;
4761cb875aeSCathy Zhou 			continue;
4771cb875aeSCathy Zhou 		}
478c5e0ece0SCathy Zhou 		return (VRRP_ESYS);
4791cb875aeSCathy Zhou 	}
4801cb875aeSCathy Zhou 
4811cb875aeSCathy Zhou 	*(list_arg->vfl_cnt) = out_cnt = ret.vrl_cnt;
4821cb875aeSCathy Zhou 	out_cnt = (in_cnt <= out_cnt) ? in_cnt : out_cnt;
4831cb875aeSCathy Zhou 	cur_size = 0;
4841cb875aeSCathy Zhou 
4851cb875aeSCathy Zhou 	while (cur_size < VRRP_NAME_MAX * out_cnt) {
4861cb875aeSCathy Zhou 		len = read(sock, (char *)list_arg->vfl_names + cur_size,
4871cb875aeSCathy Zhou 		    VRRP_NAME_MAX * out_cnt - cur_size);
4881cb875aeSCathy Zhou 
4891cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
4901cb875aeSCathy Zhou 			continue;
4911cb875aeSCathy Zhou 		} else if (len > 0) {
4921cb875aeSCathy Zhou 			cur_size += len;
4931cb875aeSCathy Zhou 			continue;
4941cb875aeSCathy Zhou 		}
495c5e0ece0SCathy Zhou 		return (VRRP_ESYS);
4961cb875aeSCathy Zhou 	}
4971cb875aeSCathy Zhou 	return (VRRP_SUCCESS);
4981cb875aeSCathy Zhou }
4991cb875aeSCathy Zhou 
5001cb875aeSCathy Zhou /*
5011cb875aeSCathy Zhou  * Looks up the vrrp instances that matches the given variable.
5021cb875aeSCathy Zhou  *
5031cb875aeSCathy Zhou  * If the given cnt is 0, names should be set to NULL. In this case, only
5041cb875aeSCathy Zhou  * the count of the matched instances is returned.
5051cb875aeSCathy Zhou  *
5061cb875aeSCathy Zhou  * If the given cnt is non-zero, caller must allocate "names" whose size
5071cb875aeSCathy Zhou  * is (cnt * VRRP_NAME_MAX).
5081cb875aeSCathy Zhou  *
5091cb875aeSCathy Zhou  * Return value: the current count of matched instances, and names will be
5101cb875aeSCathy Zhou  * points to the list of the current vrrp instances names. Note that
5111cb875aeSCathy Zhou  * only MIN(in_cnt, out_cnt) number of names will be returned.
5121cb875aeSCathy Zhou  */
5131cb875aeSCathy Zhou /*ARGSUSED*/
5141cb875aeSCathy Zhou vrrp_err_t
vrrp_list(vrrp_handle_t vh,vrid_t vrid,const char * intf,int af,uint32_t * cnt,char * names)5151cb875aeSCathy Zhou vrrp_list(vrrp_handle_t vh, vrid_t vrid, const char *intf, int af,
5161cb875aeSCathy Zhou     uint32_t *cnt, char *names)
5171cb875aeSCathy Zhou {
5181cb875aeSCathy Zhou 	vrrp_cmd_list_t		cmd;
5191cb875aeSCathy Zhou 	vrrp_err_t		err;
5201cb875aeSCathy Zhou 	vrrp_cmd_list_arg_t	list_arg;
5211cb875aeSCathy Zhou 
5221cb875aeSCathy Zhou 	if ((cnt == NULL) || (*cnt != 0 && names == NULL))
5231cb875aeSCathy Zhou 		return (VRRP_EINVAL);
5241cb875aeSCathy Zhou 
5251cb875aeSCathy Zhou 	cmd.vcl_ifname[0] = '\0';
5261cb875aeSCathy Zhou 	if (intf != NULL && (strlcpy(cmd.vcl_ifname, intf,
5271cb875aeSCathy Zhou 	    LIFNAMSIZ) >= LIFNAMSIZ)) {
5281cb875aeSCathy Zhou 		return (VRRP_EINVAL);
5291cb875aeSCathy Zhou 	}
5301cb875aeSCathy Zhou 
531c5e0ece0SCathy Zhou 	/*
532c5e0ece0SCathy Zhou 	 * If the service is not online, we assume there is no router
533c5e0ece0SCathy Zhou 	 * configured.
534c5e0ece0SCathy Zhou 	 */
535c5e0ece0SCathy Zhou 	if (!vrrp_svc_isonline(VRRP_SERVICE)) {
536c5e0ece0SCathy Zhou 		*cnt = 0;
537c5e0ece0SCathy Zhou 		return (VRRP_SUCCESS);
538c5e0ece0SCathy Zhou 	}
539c5e0ece0SCathy Zhou 
5401cb875aeSCathy Zhou 	cmd.vcl_cmd = VRRP_CMD_LIST;
5411cb875aeSCathy Zhou 	cmd.vcl_vrid = vrid;
5421cb875aeSCathy Zhou 	cmd.vcl_af = af;
5431cb875aeSCathy Zhou 
5441cb875aeSCathy Zhou 	list_arg.vfl_cnt = cnt;
5451cb875aeSCathy Zhou 	list_arg.vfl_names = names;
5461cb875aeSCathy Zhou 
5471cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), vrrp_list_func, &list_arg);
5481cb875aeSCathy Zhou 	return (err);
5491cb875aeSCathy Zhou }
5501cb875aeSCathy Zhou 
5511cb875aeSCathy Zhou static vrrp_err_t
vrrp_query_func(int sock,void * arg)5521cb875aeSCathy Zhou vrrp_query_func(int sock, void *arg)
5531cb875aeSCathy Zhou {
5541cb875aeSCathy Zhou 	vrrp_queryinfo_t	*qinfo = arg;
5551cb875aeSCathy Zhou 	size_t			len, cur_size = 0, total;
5561cb875aeSCathy Zhou 	uint32_t		in_cnt = qinfo->show_va.va_vipcnt;
5571cb875aeSCathy Zhou 	uint32_t		out_cnt;
5581cb875aeSCathy Zhou 
5591cb875aeSCathy Zhou 	/*
5601cb875aeSCathy Zhou 	 * Expect the ack, first get the vrrp_ret_t.
5611cb875aeSCathy Zhou 	 */
5621cb875aeSCathy Zhou 	total = sizeof (vrrp_queryinfo_t);
5631cb875aeSCathy Zhou 	while (cur_size < total) {
5641cb875aeSCathy Zhou 		len = read(sock, (char *)qinfo + cur_size, total - cur_size);
5651cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
5661cb875aeSCathy Zhou 			continue;
5671cb875aeSCathy Zhou 		} else if (len > 0) {
5681cb875aeSCathy Zhou 			cur_size += len;
5691cb875aeSCathy Zhou 			continue;
5701cb875aeSCathy Zhou 		}
571c5e0ece0SCathy Zhou 		return (VRRP_ESYS);
5721cb875aeSCathy Zhou 	}
5731cb875aeSCathy Zhou 
5741cb875aeSCathy Zhou 	out_cnt = qinfo->show_va.va_vipcnt;
5751cb875aeSCathy Zhou 
5761cb875aeSCathy Zhou 	/*
5771cb875aeSCathy Zhou 	 * Even if there is no IP virtual IP address, there is always
5781cb875aeSCathy Zhou 	 * space in the vrrp_queryinfo_t structure for one virtual
5791cb875aeSCathy Zhou 	 * IP address.
5801cb875aeSCathy Zhou 	 */
5811cb875aeSCathy Zhou 	out_cnt = (out_cnt == 0) ? 1 : out_cnt;
5821cb875aeSCathy Zhou 	out_cnt = (in_cnt < out_cnt ? in_cnt : out_cnt) - 1;
5831cb875aeSCathy Zhou 	total += out_cnt * sizeof (vrrp_addr_t);
5841cb875aeSCathy Zhou 
5851cb875aeSCathy Zhou 	while (cur_size < total) {
5861cb875aeSCathy Zhou 		len = read(sock, (char *)qinfo + cur_size, total - cur_size);
5871cb875aeSCathy Zhou 		if (len == (size_t)-1 && errno == EAGAIN) {
5881cb875aeSCathy Zhou 			continue;
5891cb875aeSCathy Zhou 		} else if (len > 0) {
5901cb875aeSCathy Zhou 			cur_size += len;
5911cb875aeSCathy Zhou 			continue;
5921cb875aeSCathy Zhou 		}
593c5e0ece0SCathy Zhou 		return (VRRP_ESYS);
5941cb875aeSCathy Zhou 	}
5951cb875aeSCathy Zhou 	return (VRRP_SUCCESS);
5961cb875aeSCathy Zhou }
5971cb875aeSCathy Zhou 
5981cb875aeSCathy Zhou /*
5991cb875aeSCathy Zhou  * *vqp is allocated inside this function and must be freed by the caller.
6001cb875aeSCathy Zhou  */
6011cb875aeSCathy Zhou /*ARGSUSED*/
6021cb875aeSCathy Zhou vrrp_err_t
vrrp_query(vrrp_handle_t vh,const char * vn,vrrp_queryinfo_t ** vqp)6031cb875aeSCathy Zhou vrrp_query(vrrp_handle_t vh, const char *vn, vrrp_queryinfo_t **vqp)
6041cb875aeSCathy Zhou {
6051cb875aeSCathy Zhou 	vrrp_cmd_query_t	cmd;
6061cb875aeSCathy Zhou 	vrrp_queryinfo_t	*qinfo;
6071cb875aeSCathy Zhou 	vrrp_err_t		err;
6081cb875aeSCathy Zhou 	size_t			size;
6091cb875aeSCathy Zhou 	uint32_t		vipcnt = 1;
6101cb875aeSCathy Zhou 
6111cb875aeSCathy Zhou 	if (strlcpy(cmd.vcq_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
6121cb875aeSCathy Zhou 		return (VRRP_EINVAL);
6131cb875aeSCathy Zhou 
614c5e0ece0SCathy Zhou 	/*
615c5e0ece0SCathy Zhou 	 * If the service is not online, we assume there is no router
616c5e0ece0SCathy Zhou 	 * configured.
617c5e0ece0SCathy Zhou 	 */
618c5e0ece0SCathy Zhou 	if (!vrrp_svc_isonline(VRRP_SERVICE))
619c5e0ece0SCathy Zhou 		return (VRRP_ENOTFOUND);
620c5e0ece0SCathy Zhou 
6211cb875aeSCathy Zhou 	cmd.vcq_cmd = VRRP_CMD_QUERY;
6221cb875aeSCathy Zhou 
6231cb875aeSCathy Zhou 	/*
6241cb875aeSCathy Zhou 	 * Allocate enough room for virtual IPs.
6251cb875aeSCathy Zhou 	 */
6261cb875aeSCathy Zhou again:
6271cb875aeSCathy Zhou 	size = sizeof (vrrp_queryinfo_t);
6281cb875aeSCathy Zhou 	size += (vipcnt == 0) ? 0 : (vipcnt - 1) * sizeof (vrrp_addr_t);
6291cb875aeSCathy Zhou 	if ((qinfo = malloc(size)) == NULL) {
6301cb875aeSCathy Zhou 		err = VRRP_ENOMEM;
6311cb875aeSCathy Zhou 		goto done;
6321cb875aeSCathy Zhou 	}
6331cb875aeSCathy Zhou 
6341cb875aeSCathy Zhou 	qinfo->show_va.va_vipcnt = vipcnt;
6351cb875aeSCathy Zhou 	err = vrrp_cmd_request(&cmd, sizeof (cmd), vrrp_query_func, qinfo);
6361cb875aeSCathy Zhou 	if (err != VRRP_SUCCESS) {
6371cb875aeSCathy Zhou 		free(qinfo);
6381cb875aeSCathy Zhou 		goto done;
6391cb875aeSCathy Zhou 	}
6401cb875aeSCathy Zhou 
6411cb875aeSCathy Zhou 	/*
6421cb875aeSCathy Zhou 	 * If the returned number of virtual IPs is greater than we expected,
6431cb875aeSCathy Zhou 	 * allocate more room and try again.
6441cb875aeSCathy Zhou 	 */
6451cb875aeSCathy Zhou 	if (qinfo->show_va.va_vipcnt > vipcnt) {
6461cb875aeSCathy Zhou 		vipcnt = qinfo->show_va.va_vipcnt;
6471cb875aeSCathy Zhou 		free(qinfo);
6481cb875aeSCathy Zhou 		goto again;
6491cb875aeSCathy Zhou 	}
6501cb875aeSCathy Zhou 
6511cb875aeSCathy Zhou 	*vqp = qinfo;
6521cb875aeSCathy Zhou 
6531cb875aeSCathy Zhou done:
6541cb875aeSCathy Zhou 	return (err);
6551cb875aeSCathy Zhou }
6561cb875aeSCathy Zhou 
6571cb875aeSCathy Zhou struct lookup_vnic_arg {
6581cb875aeSCathy Zhou 	vrid_t		lva_vrid;
6591cb875aeSCathy Zhou 	datalink_id_t	lva_linkid;
6601cb875aeSCathy Zhou 	int		lva_af;
6611cb875aeSCathy Zhou 	uint16_t	lva_vid;
6621cb875aeSCathy Zhou 	vrrp_handle_t	lva_vh;
6631cb875aeSCathy Zhou 	char		lva_vnic[MAXLINKNAMELEN];
6641cb875aeSCathy Zhou };
6651cb875aeSCathy Zhou 
6661cb875aeSCathy Zhou /*
6671cb875aeSCathy Zhou  * Is this a special VNIC interface created for VRRP? If so, return
6681cb875aeSCathy Zhou  * the linkid the VNIC was created on, the VRRP ID and address family.
6691cb875aeSCathy Zhou  */
6701cb875aeSCathy Zhou boolean_t
vrrp_is_vrrp_vnic(vrrp_handle_t vh,datalink_id_t vnicid,datalink_id_t * linkidp,uint16_t * vidp,vrid_t * vridp,int * afp)6711cb875aeSCathy Zhou vrrp_is_vrrp_vnic(vrrp_handle_t vh, datalink_id_t vnicid,
6721cb875aeSCathy Zhou     datalink_id_t *linkidp, uint16_t *vidp, vrid_t *vridp, int *afp)
6731cb875aeSCathy Zhou {
6741cb875aeSCathy Zhou 	dladm_vnic_attr_t	vattr;
6751cb875aeSCathy Zhou 
6761cb875aeSCathy Zhou 	if (dladm_vnic_info(vh->vh_dh, vnicid, &vattr, DLADM_OPT_ACTIVE) !=
6771cb875aeSCathy Zhou 	    DLADM_STATUS_OK) {
6781cb875aeSCathy Zhou 		return (B_FALSE);
6791cb875aeSCathy Zhou 	}
6801cb875aeSCathy Zhou 
6811cb875aeSCathy Zhou 	*vridp = vattr.va_vrid;
6821cb875aeSCathy Zhou 	*vidp = vattr.va_vid;
6831cb875aeSCathy Zhou 	*afp = vattr.va_af;
6841cb875aeSCathy Zhou 	*linkidp = vattr.va_link_id;
6851cb875aeSCathy Zhou 	return (vattr.va_vrid != VRRP_VRID_NONE);
6861cb875aeSCathy Zhou }
6871cb875aeSCathy Zhou 
6881cb875aeSCathy Zhou static int
lookup_vnic(dladm_handle_t dh,datalink_id_t vnicid,void * arg)6891cb875aeSCathy Zhou lookup_vnic(dladm_handle_t dh, datalink_id_t vnicid, void *arg)
6901cb875aeSCathy Zhou {
6911cb875aeSCathy Zhou 	vrid_t			vrid;
6921cb875aeSCathy Zhou 	uint16_t		vid;
6931cb875aeSCathy Zhou 	datalink_id_t		linkid;
6941cb875aeSCathy Zhou 	int			af;
6951cb875aeSCathy Zhou 	struct lookup_vnic_arg	*lva = arg;
6961cb875aeSCathy Zhou 
6971cb875aeSCathy Zhou 	if (vrrp_is_vrrp_vnic(lva->lva_vh, vnicid, &linkid, &vid, &vrid,
6981cb875aeSCathy Zhou 	    &af) && lva->lva_vrid == vrid && lva->lva_linkid == linkid &&
699*2954adb0SRob Gulewich 	    (lva->lva_vid == VLAN_ID_NONE || lva->lva_vid == vid) &&
700*2954adb0SRob Gulewich 	    lva->lva_af == af) {
7011cb875aeSCathy Zhou 		if (dladm_datalink_id2info(dh, vnicid, NULL, NULL, NULL,
7021cb875aeSCathy Zhou 		    lva->lva_vnic, sizeof (lva->lva_vnic)) == DLADM_STATUS_OK) {
7031cb875aeSCathy Zhou 			return (DLADM_WALK_TERMINATE);
7041cb875aeSCathy Zhou 		}
7051cb875aeSCathy Zhou 	}
7061cb875aeSCathy Zhou 	return (DLADM_WALK_CONTINUE);
7071cb875aeSCathy Zhou }
7081cb875aeSCathy Zhou 
7091cb875aeSCathy Zhou /*
7101cb875aeSCathy Zhou  * Given the primary link name, find the assoicated VRRP vnic name, if
7111cb875aeSCathy Zhou  * the vnic does not exist yet, return the linkid, vid of the primary link.
7121cb875aeSCathy Zhou  */
7131cb875aeSCathy Zhou vrrp_err_t
vrrp_get_vnicname(vrrp_handle_t vh,vrid_t vrid,int af,char * link,datalink_id_t * linkidp,uint16_t * vidp,char * vnic,size_t len)7141cb875aeSCathy Zhou vrrp_get_vnicname(vrrp_handle_t vh, vrid_t vrid, int af, char *link,
7151cb875aeSCathy Zhou     datalink_id_t *linkidp, uint16_t *vidp, char *vnic, size_t len)
7161cb875aeSCathy Zhou {
7171cb875aeSCathy Zhou 	datalink_id_t		linkid;
7181cb875aeSCathy Zhou 	uint32_t		flags;
7191cb875aeSCathy Zhou 	uint16_t		vid = VLAN_ID_NONE;
7201cb875aeSCathy Zhou 	datalink_class_t	class;
7211cb875aeSCathy Zhou 	dladm_vlan_attr_t	vlan_attr;
722*2954adb0SRob Gulewich 	dladm_vnic_attr_t	vnic_attr;
7231cb875aeSCathy Zhou 	struct lookup_vnic_arg	lva;
7241cb875aeSCathy Zhou 	uint32_t		media;
7251cb875aeSCathy Zhou 
7261cb875aeSCathy Zhou 	if ((strlen(link) == 0) || dladm_name2info(vh->vh_dh,
7271cb875aeSCathy Zhou 	    link, &linkid, &flags, &class, &media) !=
7281cb875aeSCathy Zhou 	    DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) {
7291cb875aeSCathy Zhou 		return (VRRP_EINVAL);
7301cb875aeSCathy Zhou 	}
7311cb875aeSCathy Zhou 
7321cb875aeSCathy Zhou 	if (class == DATALINK_CLASS_VLAN) {
7331cb875aeSCathy Zhou 		if (dladm_vlan_info(vh->vh_dh, linkid, &vlan_attr,
7341cb875aeSCathy Zhou 		    DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
7351cb875aeSCathy Zhou 			return (VRRP_EINVAL);
7361cb875aeSCathy Zhou 		}
7371cb875aeSCathy Zhou 		linkid = vlan_attr.dv_linkid;
7381cb875aeSCathy Zhou 		vid = vlan_attr.dv_vid;
7391cb875aeSCathy Zhou 		if ((dladm_datalink_id2info(vh->vh_dh, linkid, NULL,
7401cb875aeSCathy Zhou 		    &class, &media, NULL, 0)) != DLADM_STATUS_OK) {
7411cb875aeSCathy Zhou 			return (VRRP_EINVAL);
7421cb875aeSCathy Zhou 		}
7431cb875aeSCathy Zhou 	}
7441cb875aeSCathy Zhou 
745*2954adb0SRob Gulewich 	if (class == DATALINK_CLASS_VNIC) {
746*2954adb0SRob Gulewich 		if (dladm_vnic_info(vh->vh_dh, linkid, &vnic_attr,
747*2954adb0SRob Gulewich 		    DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
748*2954adb0SRob Gulewich 			return (VRRP_EINVAL);
749*2954adb0SRob Gulewich 		}
750*2954adb0SRob Gulewich 		linkid = vnic_attr.va_link_id;
751*2954adb0SRob Gulewich 		vid = vnic_attr.va_vid;
752*2954adb0SRob Gulewich 	}
753*2954adb0SRob Gulewich 
7541cb875aeSCathy Zhou 	/*
755*2954adb0SRob Gulewich 	 * Only VRRP over vnics, aggrs and physical ethernet links is supported
7561cb875aeSCathy Zhou 	 */
757*2954adb0SRob Gulewich 	if ((class != DATALINK_CLASS_PHYS && class != DATALINK_CLASS_AGGR &&
758*2954adb0SRob Gulewich 	    class != DATALINK_CLASS_VNIC) || media != DL_ETHER) {
7591cb875aeSCathy Zhou 		return (VRRP_EINVAL);
7601cb875aeSCathy Zhou 	}
7611cb875aeSCathy Zhou 
7621cb875aeSCathy Zhou 	if (linkidp != NULL)
7631cb875aeSCathy Zhou 		*linkidp = linkid;
7641cb875aeSCathy Zhou 	if (vidp != NULL)
7651cb875aeSCathy Zhou 		*vidp = vid;
7661cb875aeSCathy Zhou 
7671cb875aeSCathy Zhou 	/*
7681cb875aeSCathy Zhou 	 * Find the assoicated vnic with the given vrid/vid/af/linkid
7691cb875aeSCathy Zhou 	 */
7701cb875aeSCathy Zhou 	lva.lva_vrid = vrid;
7711cb875aeSCathy Zhou 	lva.lva_vid = vid;
7721cb875aeSCathy Zhou 	lva.lva_af = af;
7731cb875aeSCathy Zhou 	lva.lva_linkid = linkid;
7741cb875aeSCathy Zhou 	lva.lva_vh = vh;
7751cb875aeSCathy Zhou 	lva.lva_vnic[0] = '\0';
7761cb875aeSCathy Zhou 
7771cb875aeSCathy Zhou 	(void) dladm_walk_datalink_id(lookup_vnic, vh->vh_dh, &lva,
7781cb875aeSCathy Zhou 	    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
7791cb875aeSCathy Zhou 	if (strlen(lva.lva_vnic) != 0) {
7801cb875aeSCathy Zhou 		(void) strlcpy(vnic, lva.lva_vnic, len);
7811cb875aeSCathy Zhou 		return (VRRP_SUCCESS);
7821cb875aeSCathy Zhou 	}
7831cb875aeSCathy Zhou 
7841cb875aeSCathy Zhou 	return (VRRP_ENOVNIC);
7851cb875aeSCathy Zhou }
786