xref: /onnv-gate/usr/src/lib/libvrrpadm/common/libvrrpadm.c (revision 11451:84318b5fda90)
111076SCathy.Zhou@Sun.COM /*
211076SCathy.Zhou@Sun.COM  * CDDL HEADER START
311076SCathy.Zhou@Sun.COM  *
411076SCathy.Zhou@Sun.COM  * The contents of this file are subject to the terms of the
511076SCathy.Zhou@Sun.COM  * Common Development and Distribution License (the "License").
611076SCathy.Zhou@Sun.COM  * You may not use this file except in compliance with the License.
711076SCathy.Zhou@Sun.COM  *
811076SCathy.Zhou@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911076SCathy.Zhou@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011076SCathy.Zhou@Sun.COM  * See the License for the specific language governing permissions
1111076SCathy.Zhou@Sun.COM  * and limitations under the License.
1211076SCathy.Zhou@Sun.COM  *
1311076SCathy.Zhou@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411076SCathy.Zhou@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511076SCathy.Zhou@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611076SCathy.Zhou@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711076SCathy.Zhou@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811076SCathy.Zhou@Sun.COM  *
1911076SCathy.Zhou@Sun.COM  * CDDL HEADER END
2011076SCathy.Zhou@Sun.COM  */
2111076SCathy.Zhou@Sun.COM 
2211076SCathy.Zhou@Sun.COM /*
23*11451SCathy.Zhou@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2411076SCathy.Zhou@Sun.COM  * Use is subject to license terms.
2511076SCathy.Zhou@Sun.COM  */
2611076SCathy.Zhou@Sun.COM 
2711076SCathy.Zhou@Sun.COM #include <sys/types.h>
2811076SCathy.Zhou@Sun.COM #include <sys/stat.h>
2911076SCathy.Zhou@Sun.COM #include <sys/socket.h>
3011076SCathy.Zhou@Sun.COM #include <sys/mman.h>
3111076SCathy.Zhou@Sun.COM #include <sys/varargs.h>
3211076SCathy.Zhou@Sun.COM #include <sys/vlan.h>
3311076SCathy.Zhou@Sun.COM #include <errno.h>
3411076SCathy.Zhou@Sun.COM #include <ctype.h>
3511076SCathy.Zhou@Sun.COM #include <fcntl.h>
3611076SCathy.Zhou@Sun.COM #include <unistd.h>
3711076SCathy.Zhou@Sun.COM #include <stdio.h>
3811076SCathy.Zhou@Sun.COM #include <stdlib.h>
3911076SCathy.Zhou@Sun.COM #include <string.h>
4011076SCathy.Zhou@Sun.COM #include <netinet/in.h>
4111076SCathy.Zhou@Sun.COM #include <arpa/inet.h>
4211076SCathy.Zhou@Sun.COM #include <net/if.h>	/* LIFNAMSIZ */
4311076SCathy.Zhou@Sun.COM #include <netinet/vrrp.h>
4411076SCathy.Zhou@Sun.COM #include <libdladm.h>
4511076SCathy.Zhou@Sun.COM #include <libdlvnic.h>
4611076SCathy.Zhou@Sun.COM #include <libdlvlan.h>
4711076SCathy.Zhou@Sun.COM #include <libdllink.h>
4811076SCathy.Zhou@Sun.COM #include <libintl.h>
49*11451SCathy.Zhou@Sun.COM #include <libscf.h>
5011076SCathy.Zhou@Sun.COM #include <libvrrpadm.h>
5111076SCathy.Zhou@Sun.COM 
52*11451SCathy.Zhou@Sun.COM #define	VRRP_SERVICE	"network/vrrp:default"
53*11451SCathy.Zhou@Sun.COM 
5411076SCathy.Zhou@Sun.COM typedef vrrp_err_t vrrp_cmd_func_t(int, void *);
5511076SCathy.Zhou@Sun.COM 
56*11451SCathy.Zhou@Sun.COM static boolean_t
vrrp_svc_isonline(char * svc_name)57*11451SCathy.Zhou@Sun.COM vrrp_svc_isonline(char *svc_name)
58*11451SCathy.Zhou@Sun.COM {
59*11451SCathy.Zhou@Sun.COM 	char		*s;
60*11451SCathy.Zhou@Sun.COM 	boolean_t	isonline = B_FALSE;
61*11451SCathy.Zhou@Sun.COM 
62*11451SCathy.Zhou@Sun.COM 	if ((s = smf_get_state(svc_name)) != NULL) {
63*11451SCathy.Zhou@Sun.COM 		if (strcmp(s, SCF_STATE_STRING_ONLINE) == 0)
64*11451SCathy.Zhou@Sun.COM 			isonline = B_TRUE;
65*11451SCathy.Zhou@Sun.COM 		free(s);
66*11451SCathy.Zhou@Sun.COM 	}
67*11451SCathy.Zhou@Sun.COM 
68*11451SCathy.Zhou@Sun.COM 	return (isonline);
69*11451SCathy.Zhou@Sun.COM }
70*11451SCathy.Zhou@Sun.COM 
71*11451SCathy.Zhou@Sun.COM #define	MAX_WAIT_TIME	15
72*11451SCathy.Zhou@Sun.COM 
73*11451SCathy.Zhou@Sun.COM static vrrp_err_t
vrrp_enable_service()74*11451SCathy.Zhou@Sun.COM vrrp_enable_service()
75*11451SCathy.Zhou@Sun.COM {
76*11451SCathy.Zhou@Sun.COM 	int	i;
77*11451SCathy.Zhou@Sun.COM 
78*11451SCathy.Zhou@Sun.COM 	if (vrrp_svc_isonline(VRRP_SERVICE))
79*11451SCathy.Zhou@Sun.COM 		return (VRRP_SUCCESS);
80*11451SCathy.Zhou@Sun.COM 
81*11451SCathy.Zhou@Sun.COM 	if (smf_enable_instance(VRRP_SERVICE, 0) == -1) {
82*11451SCathy.Zhou@Sun.COM 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
83*11451SCathy.Zhou@Sun.COM 			return (VRRP_EPERM);
84*11451SCathy.Zhou@Sun.COM 		else
85*11451SCathy.Zhou@Sun.COM 			return (VRRP_ENOSVC);
86*11451SCathy.Zhou@Sun.COM 	}
87*11451SCathy.Zhou@Sun.COM 
88*11451SCathy.Zhou@Sun.COM 	/*
89*11451SCathy.Zhou@Sun.COM 	 * Wait up to MAX_WAIT_TIME seconds for the VRRP service being brought
90*11451SCathy.Zhou@Sun.COM 	 * up online
91*11451SCathy.Zhou@Sun.COM 	 */
92*11451SCathy.Zhou@Sun.COM 	for (i = 0; i < MAX_WAIT_TIME; i++) {
93*11451SCathy.Zhou@Sun.COM 		if (vrrp_svc_isonline(VRRP_SERVICE))
94*11451SCathy.Zhou@Sun.COM 			break;
95*11451SCathy.Zhou@Sun.COM 		(void) sleep(1);
96*11451SCathy.Zhou@Sun.COM 	}
97*11451SCathy.Zhou@Sun.COM 	if (i == MAX_WAIT_TIME)
98*11451SCathy.Zhou@Sun.COM 		return (VRRP_ENOSVC);
99*11451SCathy.Zhou@Sun.COM 
100*11451SCathy.Zhou@Sun.COM 	return (VRRP_SUCCESS);
101*11451SCathy.Zhou@Sun.COM }
102*11451SCathy.Zhou@Sun.COM 
103*11451SCathy.Zhou@Sun.COM /*
104*11451SCathy.Zhou@Sun.COM  * Disable the VRRP service if there is no VRRP router left.
105*11451SCathy.Zhou@Sun.COM  */
106*11451SCathy.Zhou@Sun.COM static void
vrrp_disable_service_when_no_router()107*11451SCathy.Zhou@Sun.COM vrrp_disable_service_when_no_router()
108*11451SCathy.Zhou@Sun.COM {
109*11451SCathy.Zhou@Sun.COM 	uint32_t	cnt = 0;
110*11451SCathy.Zhou@Sun.COM 
111*11451SCathy.Zhou@Sun.COM 	/*
112*11451SCathy.Zhou@Sun.COM 	 * Get the number of the existing routers. If there is no routers
113*11451SCathy.Zhou@Sun.COM 	 * left, disable the service.
114*11451SCathy.Zhou@Sun.COM 	 */
115*11451SCathy.Zhou@Sun.COM 	if (vrrp_list(NULL, VRRP_VRID_NONE, NULL, AF_UNSPEC, &cnt,
116*11451SCathy.Zhou@Sun.COM 	    NULL) == VRRP_SUCCESS && cnt == 0) {
117*11451SCathy.Zhou@Sun.COM 		(void) smf_disable_instance(VRRP_SERVICE, 0);
118*11451SCathy.Zhou@Sun.COM 	}
119*11451SCathy.Zhou@Sun.COM }
120*11451SCathy.Zhou@Sun.COM 
12111076SCathy.Zhou@Sun.COM static vrrp_err_t
vrrp_cmd_request(void * cmd,size_t csize,vrrp_cmd_func_t func,void * arg)12211076SCathy.Zhou@Sun.COM vrrp_cmd_request(void *cmd, size_t csize, vrrp_cmd_func_t func, void *arg)
12311076SCathy.Zhou@Sun.COM {
12411076SCathy.Zhou@Sun.COM 	struct sockaddr_un	to;
12511076SCathy.Zhou@Sun.COM 	int			sock, flags;
12611076SCathy.Zhou@Sun.COM 	size_t			len, cur_size = 0;
12711076SCathy.Zhou@Sun.COM 	vrrp_ret_t		ret;
12811076SCathy.Zhou@Sun.COM 	vrrp_err_t		err;
12911076SCathy.Zhou@Sun.COM 
13011076SCathy.Zhou@Sun.COM 	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
131*11451SCathy.Zhou@Sun.COM 		return (VRRP_ESYS);
13211076SCathy.Zhou@Sun.COM 
13311076SCathy.Zhou@Sun.COM 	/*
13411076SCathy.Zhou@Sun.COM 	 * Set it to be non-blocking.
13511076SCathy.Zhou@Sun.COM 	 */
13611076SCathy.Zhou@Sun.COM 	flags = fcntl(sock, F_GETFL, 0);
13711076SCathy.Zhou@Sun.COM 	(void) fcntl(sock, F_SETFL, (flags | O_NONBLOCK));
13811076SCathy.Zhou@Sun.COM 
13911076SCathy.Zhou@Sun.COM 	(void) memset(&to, 0, sizeof (to));
14011076SCathy.Zhou@Sun.COM 	to.sun_family = AF_UNIX;
14111076SCathy.Zhou@Sun.COM 	(void) strlcpy(to.sun_path, VRRPD_SOCKET, sizeof (to.sun_path));
14211076SCathy.Zhou@Sun.COM 
14311076SCathy.Zhou@Sun.COM 	/*
14411076SCathy.Zhou@Sun.COM 	 * Connect to vrrpd
14511076SCathy.Zhou@Sun.COM 	 */
14611076SCathy.Zhou@Sun.COM 	if (connect(sock, (const struct sockaddr *)&to, sizeof (to)) < 0) {
14711076SCathy.Zhou@Sun.COM 		(void) close(sock);
148*11451SCathy.Zhou@Sun.COM 		return (VRRP_ENOSVC);
14911076SCathy.Zhou@Sun.COM 	}
15011076SCathy.Zhou@Sun.COM 
15111076SCathy.Zhou@Sun.COM 	/*
15211076SCathy.Zhou@Sun.COM 	 * Send the request
15311076SCathy.Zhou@Sun.COM 	 */
15411076SCathy.Zhou@Sun.COM 	while (cur_size < csize) {
15511076SCathy.Zhou@Sun.COM 		len = write(sock, (char *)cmd + cur_size, csize - cur_size);
15611076SCathy.Zhou@Sun.COM 		if (len == (size_t)-1 && errno == EAGAIN) {
15711076SCathy.Zhou@Sun.COM 			continue;
15811076SCathy.Zhou@Sun.COM 		} else if (len > 0) {
15911076SCathy.Zhou@Sun.COM 			cur_size += len;
16011076SCathy.Zhou@Sun.COM 			continue;
16111076SCathy.Zhou@Sun.COM 		}
16211076SCathy.Zhou@Sun.COM 		(void) close(sock);
163*11451SCathy.Zhou@Sun.COM 		return (VRRP_ENOSVC);
16411076SCathy.Zhou@Sun.COM 	}
16511076SCathy.Zhou@Sun.COM 
16611076SCathy.Zhou@Sun.COM 	/*
16711076SCathy.Zhou@Sun.COM 	 * Expect the ack, first get the error code.
16811076SCathy.Zhou@Sun.COM 	 */
16911076SCathy.Zhou@Sun.COM 	cur_size = 0;
17011076SCathy.Zhou@Sun.COM 	while (cur_size < sizeof (vrrp_err_t)) {
17111076SCathy.Zhou@Sun.COM 		len = read(sock, (char *)&ret + cur_size,
17211076SCathy.Zhou@Sun.COM 		    sizeof (vrrp_err_t) - cur_size);
17311076SCathy.Zhou@Sun.COM 
17411076SCathy.Zhou@Sun.COM 		if (len == (size_t)-1 && errno == EAGAIN) {
17511076SCathy.Zhou@Sun.COM 			continue;
17611076SCathy.Zhou@Sun.COM 		} else if (len > 0) {
17711076SCathy.Zhou@Sun.COM 			cur_size += len;
17811076SCathy.Zhou@Sun.COM 			continue;
17911076SCathy.Zhou@Sun.COM 		}
18011076SCathy.Zhou@Sun.COM 		(void) close(sock);
181*11451SCathy.Zhou@Sun.COM 		return (VRRP_ESYS);
18211076SCathy.Zhou@Sun.COM 	}
18311076SCathy.Zhou@Sun.COM 
18411076SCathy.Zhou@Sun.COM 	if ((err = ret.vr_err) != VRRP_SUCCESS)
18511076SCathy.Zhou@Sun.COM 		goto done;
18611076SCathy.Zhou@Sun.COM 
18711076SCathy.Zhou@Sun.COM 	/*
18811076SCathy.Zhou@Sun.COM 	 * The specific callback gets the rest of the information.
18911076SCathy.Zhou@Sun.COM 	 */
19011076SCathy.Zhou@Sun.COM 	if (func != NULL)
19111076SCathy.Zhou@Sun.COM 		err = func(sock, arg);
19211076SCathy.Zhou@Sun.COM 
19311076SCathy.Zhou@Sun.COM done:
19411076SCathy.Zhou@Sun.COM 	(void) close(sock);
19511076SCathy.Zhou@Sun.COM 	return (err);
19611076SCathy.Zhou@Sun.COM }
19711076SCathy.Zhou@Sun.COM 
19811076SCathy.Zhou@Sun.COM /*
19911076SCathy.Zhou@Sun.COM  * public APIs
20011076SCathy.Zhou@Sun.COM  */
20111076SCathy.Zhou@Sun.COM const char *
vrrp_err2str(vrrp_err_t err)20211076SCathy.Zhou@Sun.COM vrrp_err2str(vrrp_err_t err)
20311076SCathy.Zhou@Sun.COM {
20411076SCathy.Zhou@Sun.COM 	switch (err) {
20511076SCathy.Zhou@Sun.COM 	case VRRP_SUCCESS:
20611076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "success"));
20711076SCathy.Zhou@Sun.COM 	case VRRP_ENOMEM:
20811076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "not enough memory"));
20911076SCathy.Zhou@Sun.COM 	case VRRP_EINVALVRNAME:
21011076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "invalid router name"));
21111076SCathy.Zhou@Sun.COM 	case VRRP_ENOPRIM:
21211076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "no primary IP"));
21311076SCathy.Zhou@Sun.COM 	case VRRP_EEXIST:
21411076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "already exists"));
21511076SCathy.Zhou@Sun.COM 	case VRRP_ENOVIRT:
21611076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "no virtual IPs"));
21711076SCathy.Zhou@Sun.COM 	case VRRP_EIPADM:
21811076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "ip configuration failure"));
21911076SCathy.Zhou@Sun.COM 	case VRRP_EDLADM:
22011076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "data-link configuration "
22111076SCathy.Zhou@Sun.COM 		    "failure"));
22211076SCathy.Zhou@Sun.COM 	case VRRP_EDB:
22311076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "configuration update error"));
22411076SCathy.Zhou@Sun.COM 	case VRRP_EBADSTATE:
22511076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "invalid state"));
22611076SCathy.Zhou@Sun.COM 	case VRRP_EVREXIST:
22711076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "VRRP router already exists"));
22811076SCathy.Zhou@Sun.COM 	case VRRP_ETOOSMALL:
22911076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "not enough space"));
23011076SCathy.Zhou@Sun.COM 	case VRRP_EINSTEXIST:
23111076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "router name already exists"));
23211076SCathy.Zhou@Sun.COM 	case VRRP_ENOTFOUND:
23311076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "VRRP router not found"));
23411076SCathy.Zhou@Sun.COM 	case VRRP_EINVALADDR:
23511076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "invalid IP address"));
23611076SCathy.Zhou@Sun.COM 	case VRRP_EINVALAF:
23711076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "invalid IP address family"));
23811076SCathy.Zhou@Sun.COM 	case VRRP_EINVALLINK:
23911076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "invalid data-link"));
24011076SCathy.Zhou@Sun.COM 	case VRRP_EPERM:
24111076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "permission denied"));
24211076SCathy.Zhou@Sun.COM 	case VRRP_ESYS:
24311076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "system error"));
24411076SCathy.Zhou@Sun.COM 	case VRRP_EAGAIN:
24511076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "try again"));
24611076SCathy.Zhou@Sun.COM 	case VRRP_EALREADY:
24711076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "operation already in progress"));
24811076SCathy.Zhou@Sun.COM 	case VRRP_ENOVNIC:
24911076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "VRRP VNIC has not been "
25011076SCathy.Zhou@Sun.COM 		    "created"));
25111076SCathy.Zhou@Sun.COM 	case VRRP_ENOLINK:
25211076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "the data-link does not exist"));
253*11451SCathy.Zhou@Sun.COM 	case VRRP_ENOSVC:
254*11451SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "the VRRP service cannot "
255*11451SCathy.Zhou@Sun.COM 		    "be enabled"));
25611076SCathy.Zhou@Sun.COM 	case VRRP_EINVAL:
25711076SCathy.Zhou@Sun.COM 	default:
25811076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "invalid argument"));
25911076SCathy.Zhou@Sun.COM 	}
26011076SCathy.Zhou@Sun.COM }
26111076SCathy.Zhou@Sun.COM 
26211076SCathy.Zhou@Sun.COM const char *
vrrp_state2str(vrrp_state_t state)26311076SCathy.Zhou@Sun.COM vrrp_state2str(vrrp_state_t state)
26411076SCathy.Zhou@Sun.COM {
26511076SCathy.Zhou@Sun.COM 	switch (state) {
26611076SCathy.Zhou@Sun.COM 	case VRRP_STATE_NONE:
26711076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "NONE"));
26811076SCathy.Zhou@Sun.COM 	case VRRP_STATE_INIT:
26911076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "INIT"));
27011076SCathy.Zhou@Sun.COM 	case VRRP_STATE_MASTER:
27111076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "MASTER"));
27211076SCathy.Zhou@Sun.COM 	case VRRP_STATE_BACKUP:
27311076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "BACKUP"));
27411076SCathy.Zhou@Sun.COM 	default:
27511076SCathy.Zhou@Sun.COM 		return (dgettext(TEXT_DOMAIN, "INVALID"));
27611076SCathy.Zhou@Sun.COM 	}
27711076SCathy.Zhou@Sun.COM }
27811076SCathy.Zhou@Sun.COM 
27911076SCathy.Zhou@Sun.COM vrrp_err_t
vrrp_open(vrrp_handle_t * vh)28011076SCathy.Zhou@Sun.COM vrrp_open(vrrp_handle_t *vh)
28111076SCathy.Zhou@Sun.COM {
28211076SCathy.Zhou@Sun.COM 	dladm_handle_t	dh;
28311076SCathy.Zhou@Sun.COM 
28411076SCathy.Zhou@Sun.COM 	if (dladm_open(&dh) != DLADM_STATUS_OK)
28511076SCathy.Zhou@Sun.COM 		return (VRRP_EDLADM);
28611076SCathy.Zhou@Sun.COM 
28711076SCathy.Zhou@Sun.COM 	if ((*vh = malloc(sizeof (struct vrrp_handle))) == NULL) {
28811076SCathy.Zhou@Sun.COM 		dladm_close(dh);
28911076SCathy.Zhou@Sun.COM 		return (VRRP_ENOMEM);
29011076SCathy.Zhou@Sun.COM 	}
29111076SCathy.Zhou@Sun.COM 	(*vh)->vh_dh = dh;
29211076SCathy.Zhou@Sun.COM 	return (VRRP_SUCCESS);
29311076SCathy.Zhou@Sun.COM }
29411076SCathy.Zhou@Sun.COM 
29511076SCathy.Zhou@Sun.COM void
vrrp_close(vrrp_handle_t vh)29611076SCathy.Zhou@Sun.COM vrrp_close(vrrp_handle_t vh)
29711076SCathy.Zhou@Sun.COM {
29811076SCathy.Zhou@Sun.COM 	if (vh != NULL) {
29911076SCathy.Zhou@Sun.COM 		dladm_close(vh->vh_dh);
30011076SCathy.Zhou@Sun.COM 		free(vh);
30111076SCathy.Zhou@Sun.COM 	}
30211076SCathy.Zhou@Sun.COM }
30311076SCathy.Zhou@Sun.COM 
30411076SCathy.Zhou@Sun.COM boolean_t
vrrp_valid_name(const char * name)30511076SCathy.Zhou@Sun.COM vrrp_valid_name(const char *name)
30611076SCathy.Zhou@Sun.COM {
30711076SCathy.Zhou@Sun.COM 	const char	*c;
30811076SCathy.Zhou@Sun.COM 
30911076SCathy.Zhou@Sun.COM 	/*
31011076SCathy.Zhou@Sun.COM 	 * The legal characters in a valid router name are:
31111076SCathy.Zhou@Sun.COM 	 * alphanumeric (a-z,  A-Z,  0-9), underscore ('_'), and '.'.
31211076SCathy.Zhou@Sun.COM 	 */
31311076SCathy.Zhou@Sun.COM 	for (c = name; *c != '\0'; c++) {
31411076SCathy.Zhou@Sun.COM 		if ((isalnum(*c) == 0) && (*c != '_'))
31511076SCathy.Zhou@Sun.COM 			return (B_FALSE);
31611076SCathy.Zhou@Sun.COM 	}
31711076SCathy.Zhou@Sun.COM 
31811076SCathy.Zhou@Sun.COM 	return (B_TRUE);
31911076SCathy.Zhou@Sun.COM }
32011076SCathy.Zhou@Sun.COM 
32111076SCathy.Zhou@Sun.COM /*ARGSUSED*/
32211076SCathy.Zhou@Sun.COM vrrp_err_t
vrrp_create(vrrp_handle_t vh,vrrp_vr_conf_t * conf)32311076SCathy.Zhou@Sun.COM vrrp_create(vrrp_handle_t vh, vrrp_vr_conf_t *conf)
32411076SCathy.Zhou@Sun.COM {
32511076SCathy.Zhou@Sun.COM 	vrrp_cmd_create_t	cmd;
32611076SCathy.Zhou@Sun.COM 	vrrp_err_t		err;
32711076SCathy.Zhou@Sun.COM 
328*11451SCathy.Zhou@Sun.COM again:
329*11451SCathy.Zhou@Sun.COM 	/*
330*11451SCathy.Zhou@Sun.COM 	 * Enable the VRRP service if it is not already enabled.
331*11451SCathy.Zhou@Sun.COM 	 */
332*11451SCathy.Zhou@Sun.COM 	if ((err = vrrp_enable_service()) != VRRP_SUCCESS)
333*11451SCathy.Zhou@Sun.COM 		return (err);
334*11451SCathy.Zhou@Sun.COM 
33511076SCathy.Zhou@Sun.COM 	cmd.vcc_cmd = VRRP_CMD_CREATE;
33611076SCathy.Zhou@Sun.COM 	(void) memcpy(&cmd.vcc_conf, conf, sizeof (vrrp_vr_conf_t));
33711076SCathy.Zhou@Sun.COM 
33811076SCathy.Zhou@Sun.COM 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
339*11451SCathy.Zhou@Sun.COM 	if (err == VRRP_ENOSVC) {
340*11451SCathy.Zhou@Sun.COM 		/*
341*11451SCathy.Zhou@Sun.COM 		 * This may be due to another process is deleting the last
342*11451SCathy.Zhou@Sun.COM 		 * router and disabled the VRRP service, try again.
343*11451SCathy.Zhou@Sun.COM 		 */
344*11451SCathy.Zhou@Sun.COM 		goto again;
345*11451SCathy.Zhou@Sun.COM 	} else if (err != VRRP_SUCCESS) {
346*11451SCathy.Zhou@Sun.COM 		/*
347*11451SCathy.Zhou@Sun.COM 		 * If router cannot be created, check if the VRRP service
348*11451SCathy.Zhou@Sun.COM 		 * should be disabled, and disable if needed.
349*11451SCathy.Zhou@Sun.COM 		 */
350*11451SCathy.Zhou@Sun.COM 		vrrp_disable_service_when_no_router();
351*11451SCathy.Zhou@Sun.COM 	}
352*11451SCathy.Zhou@Sun.COM 
35311076SCathy.Zhou@Sun.COM 	return (err);
35411076SCathy.Zhou@Sun.COM }
35511076SCathy.Zhou@Sun.COM 
35611076SCathy.Zhou@Sun.COM /*ARGSUSED*/
35711076SCathy.Zhou@Sun.COM vrrp_err_t
vrrp_delete(vrrp_handle_t vh,const char * vn)35811076SCathy.Zhou@Sun.COM vrrp_delete(vrrp_handle_t vh, const char *vn)
35911076SCathy.Zhou@Sun.COM {
36011076SCathy.Zhou@Sun.COM 	vrrp_cmd_delete_t	cmd;
36111076SCathy.Zhou@Sun.COM 	vrrp_err_t		err;
36211076SCathy.Zhou@Sun.COM 
363*11451SCathy.Zhou@Sun.COM 	/*
364*11451SCathy.Zhou@Sun.COM 	 * If the VRRP service is not enabled, we assume there is no router
365*11451SCathy.Zhou@Sun.COM 	 * configured.
366*11451SCathy.Zhou@Sun.COM 	 */
367*11451SCathy.Zhou@Sun.COM 	if (!vrrp_svc_isonline(VRRP_SERVICE))
368*11451SCathy.Zhou@Sun.COM 		return (VRRP_ENOTFOUND);
369*11451SCathy.Zhou@Sun.COM 
37011076SCathy.Zhou@Sun.COM 	cmd.vcd_cmd = VRRP_CMD_DELETE;
37111076SCathy.Zhou@Sun.COM 	if (strlcpy(cmd.vcd_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
37211076SCathy.Zhou@Sun.COM 		return (VRRP_EINVAL);
37311076SCathy.Zhou@Sun.COM 
37411076SCathy.Zhou@Sun.COM 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
375*11451SCathy.Zhou@Sun.COM 	if (err == VRRP_SUCCESS)
376*11451SCathy.Zhou@Sun.COM 		vrrp_disable_service_when_no_router();
37711076SCathy.Zhou@Sun.COM 	return (err);
37811076SCathy.Zhou@Sun.COM }
37911076SCathy.Zhou@Sun.COM 
38011076SCathy.Zhou@Sun.COM /*ARGSUSED*/
38111076SCathy.Zhou@Sun.COM vrrp_err_t
vrrp_enable(vrrp_handle_t vh,const char * vn)38211076SCathy.Zhou@Sun.COM vrrp_enable(vrrp_handle_t vh, const char *vn)
38311076SCathy.Zhou@Sun.COM {
38411076SCathy.Zhou@Sun.COM 	vrrp_cmd_enable_t	cmd;
38511076SCathy.Zhou@Sun.COM 	vrrp_err_t		err;
38611076SCathy.Zhou@Sun.COM 
387*11451SCathy.Zhou@Sun.COM 	/*
388*11451SCathy.Zhou@Sun.COM 	 * If the VRRP service is not enabled, we assume there is no router
389*11451SCathy.Zhou@Sun.COM 	 * configured.
390*11451SCathy.Zhou@Sun.COM 	 */
391*11451SCathy.Zhou@Sun.COM 	if (!vrrp_svc_isonline(VRRP_SERVICE))
392*11451SCathy.Zhou@Sun.COM 		return (VRRP_ENOTFOUND);
393*11451SCathy.Zhou@Sun.COM 
39411076SCathy.Zhou@Sun.COM 	cmd.vcs_cmd = VRRP_CMD_ENABLE;
39511076SCathy.Zhou@Sun.COM 	if (strlcpy(cmd.vcs_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
39611076SCathy.Zhou@Sun.COM 		return (VRRP_EINVAL);
39711076SCathy.Zhou@Sun.COM 
39811076SCathy.Zhou@Sun.COM 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
39911076SCathy.Zhou@Sun.COM 	return (err);
40011076SCathy.Zhou@Sun.COM }
40111076SCathy.Zhou@Sun.COM 
40211076SCathy.Zhou@Sun.COM /*ARGSUSED*/
40311076SCathy.Zhou@Sun.COM vrrp_err_t
vrrp_disable(vrrp_handle_t vh,const char * vn)40411076SCathy.Zhou@Sun.COM vrrp_disable(vrrp_handle_t vh, const char *vn)
40511076SCathy.Zhou@Sun.COM {
40611076SCathy.Zhou@Sun.COM 	vrrp_cmd_disable_t	cmd;
40711076SCathy.Zhou@Sun.COM 	vrrp_err_t		err;
40811076SCathy.Zhou@Sun.COM 
409*11451SCathy.Zhou@Sun.COM 	/*
410*11451SCathy.Zhou@Sun.COM 	 * If the VRRP service is not enabled, we assume there is no router
411*11451SCathy.Zhou@Sun.COM 	 * configured.
412*11451SCathy.Zhou@Sun.COM 	 */
413*11451SCathy.Zhou@Sun.COM 	if (!vrrp_svc_isonline(VRRP_SERVICE))
414*11451SCathy.Zhou@Sun.COM 		return (VRRP_ENOTFOUND);
415*11451SCathy.Zhou@Sun.COM 
41611076SCathy.Zhou@Sun.COM 	cmd.vcx_cmd = VRRP_CMD_DISABLE;
41711076SCathy.Zhou@Sun.COM 	if (strlcpy(cmd.vcx_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
41811076SCathy.Zhou@Sun.COM 		return (VRRP_EINVAL);
41911076SCathy.Zhou@Sun.COM 
42011076SCathy.Zhou@Sun.COM 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
42111076SCathy.Zhou@Sun.COM 	return (err);
42211076SCathy.Zhou@Sun.COM }
42311076SCathy.Zhou@Sun.COM 
42411076SCathy.Zhou@Sun.COM /*ARGSUSED*/
42511076SCathy.Zhou@Sun.COM vrrp_err_t
vrrp_modify(vrrp_handle_t vh,vrrp_vr_conf_t * conf,uint32_t mask)42611076SCathy.Zhou@Sun.COM vrrp_modify(vrrp_handle_t vh, vrrp_vr_conf_t *conf, uint32_t mask)
42711076SCathy.Zhou@Sun.COM {
42811076SCathy.Zhou@Sun.COM 	vrrp_cmd_modify_t	cmd;
42911076SCathy.Zhou@Sun.COM 	vrrp_err_t		err;
43011076SCathy.Zhou@Sun.COM 
431*11451SCathy.Zhou@Sun.COM 	/*
432*11451SCathy.Zhou@Sun.COM 	 * If the VRRP service is not enabled, we assume there is no router
433*11451SCathy.Zhou@Sun.COM 	 * configured.
434*11451SCathy.Zhou@Sun.COM 	 */
435*11451SCathy.Zhou@Sun.COM 	if (!vrrp_svc_isonline(VRRP_SERVICE))
436*11451SCathy.Zhou@Sun.COM 		return (VRRP_ENOTFOUND);
437*11451SCathy.Zhou@Sun.COM 
43811076SCathy.Zhou@Sun.COM 	cmd.vcm_cmd = VRRP_CMD_MODIFY;
43911076SCathy.Zhou@Sun.COM 	cmd.vcm_mask = mask;
44011076SCathy.Zhou@Sun.COM 	(void) memcpy(&cmd.vcm_conf, conf, sizeof (vrrp_vr_conf_t));
44111076SCathy.Zhou@Sun.COM 
44211076SCathy.Zhou@Sun.COM 	err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL);
44311076SCathy.Zhou@Sun.COM 	return (err);
44411076SCathy.Zhou@Sun.COM }
44511076SCathy.Zhou@Sun.COM 
44611076SCathy.Zhou@Sun.COM typedef struct vrrp_cmd_list_arg {
44711076SCathy.Zhou@Sun.COM 	uint32_t	*vfl_cnt;
44811076SCathy.Zhou@Sun.COM 	char		*vfl_names;
44911076SCathy.Zhou@Sun.COM } vrrp_cmd_list_arg_t;
45011076SCathy.Zhou@Sun.COM 
45111076SCathy.Zhou@Sun.COM static vrrp_err_t
vrrp_list_func(int sock,void * arg)45211076SCathy.Zhou@Sun.COM vrrp_list_func(int sock, void *arg)
45311076SCathy.Zhou@Sun.COM {
45411076SCathy.Zhou@Sun.COM 	vrrp_cmd_list_arg_t	*list_arg = arg;
45511076SCathy.Zhou@Sun.COM 	uint32_t		in_cnt = *(list_arg->vfl_cnt);
45611076SCathy.Zhou@Sun.COM 	uint32_t		out_cnt;
45711076SCathy.Zhou@Sun.COM 	vrrp_ret_list_t		ret;
45811076SCathy.Zhou@Sun.COM 	size_t			len, cur_size = 0;
45911076SCathy.Zhou@Sun.COM 
46011076SCathy.Zhou@Sun.COM 	/*
46111076SCathy.Zhou@Sun.COM 	 * Get the rest of vrrp_ret_list_t besides the error code.
46211076SCathy.Zhou@Sun.COM 	 */
46311076SCathy.Zhou@Sun.COM 	cur_size = sizeof (vrrp_err_t);
46411076SCathy.Zhou@Sun.COM 	while (cur_size < sizeof (vrrp_ret_list_t)) {
46511076SCathy.Zhou@Sun.COM 		len = read(sock, (char *)&ret + cur_size,
46611076SCathy.Zhou@Sun.COM 		    sizeof (vrrp_ret_list_t) - cur_size);
46711076SCathy.Zhou@Sun.COM 
46811076SCathy.Zhou@Sun.COM 		if (len == (size_t)-1 && errno == EAGAIN) {
46911076SCathy.Zhou@Sun.COM 			continue;
47011076SCathy.Zhou@Sun.COM 		} else if (len > 0) {
47111076SCathy.Zhou@Sun.COM 			cur_size += len;
47211076SCathy.Zhou@Sun.COM 			continue;
47311076SCathy.Zhou@Sun.COM 		}
474*11451SCathy.Zhou@Sun.COM 		return (VRRP_ESYS);
47511076SCathy.Zhou@Sun.COM 	}
47611076SCathy.Zhou@Sun.COM 
47711076SCathy.Zhou@Sun.COM 	*(list_arg->vfl_cnt) = out_cnt = ret.vrl_cnt;
47811076SCathy.Zhou@Sun.COM 	out_cnt = (in_cnt <= out_cnt) ? in_cnt : out_cnt;
47911076SCathy.Zhou@Sun.COM 	cur_size = 0;
48011076SCathy.Zhou@Sun.COM 
48111076SCathy.Zhou@Sun.COM 	while (cur_size < VRRP_NAME_MAX * out_cnt) {
48211076SCathy.Zhou@Sun.COM 		len = read(sock, (char *)list_arg->vfl_names + cur_size,
48311076SCathy.Zhou@Sun.COM 		    VRRP_NAME_MAX * out_cnt - cur_size);
48411076SCathy.Zhou@Sun.COM 
48511076SCathy.Zhou@Sun.COM 		if (len == (size_t)-1 && errno == EAGAIN) {
48611076SCathy.Zhou@Sun.COM 			continue;
48711076SCathy.Zhou@Sun.COM 		} else if (len > 0) {
48811076SCathy.Zhou@Sun.COM 			cur_size += len;
48911076SCathy.Zhou@Sun.COM 			continue;
49011076SCathy.Zhou@Sun.COM 		}
491*11451SCathy.Zhou@Sun.COM 		return (VRRP_ESYS);
49211076SCathy.Zhou@Sun.COM 	}
49311076SCathy.Zhou@Sun.COM 	return (VRRP_SUCCESS);
49411076SCathy.Zhou@Sun.COM }
49511076SCathy.Zhou@Sun.COM 
49611076SCathy.Zhou@Sun.COM /*
49711076SCathy.Zhou@Sun.COM  * Looks up the vrrp instances that matches the given variable.
49811076SCathy.Zhou@Sun.COM  *
49911076SCathy.Zhou@Sun.COM  * If the given cnt is 0, names should be set to NULL. In this case, only
50011076SCathy.Zhou@Sun.COM  * the count of the matched instances is returned.
50111076SCathy.Zhou@Sun.COM  *
50211076SCathy.Zhou@Sun.COM  * If the given cnt is non-zero, caller must allocate "names" whose size
50311076SCathy.Zhou@Sun.COM  * is (cnt * VRRP_NAME_MAX).
50411076SCathy.Zhou@Sun.COM  *
50511076SCathy.Zhou@Sun.COM  * Return value: the current count of matched instances, and names will be
50611076SCathy.Zhou@Sun.COM  * points to the list of the current vrrp instances names. Note that
50711076SCathy.Zhou@Sun.COM  * only MIN(in_cnt, out_cnt) number of names will be returned.
50811076SCathy.Zhou@Sun.COM  */
50911076SCathy.Zhou@Sun.COM /*ARGSUSED*/
51011076SCathy.Zhou@Sun.COM vrrp_err_t
vrrp_list(vrrp_handle_t vh,vrid_t vrid,const char * intf,int af,uint32_t * cnt,char * names)51111076SCathy.Zhou@Sun.COM vrrp_list(vrrp_handle_t vh, vrid_t vrid, const char *intf, int af,
51211076SCathy.Zhou@Sun.COM     uint32_t *cnt, char *names)
51311076SCathy.Zhou@Sun.COM {
51411076SCathy.Zhou@Sun.COM 	vrrp_cmd_list_t		cmd;
51511076SCathy.Zhou@Sun.COM 	vrrp_err_t		err;
51611076SCathy.Zhou@Sun.COM 	vrrp_cmd_list_arg_t	list_arg;
51711076SCathy.Zhou@Sun.COM 
51811076SCathy.Zhou@Sun.COM 	if ((cnt == NULL) || (*cnt != 0 && names == NULL))
51911076SCathy.Zhou@Sun.COM 		return (VRRP_EINVAL);
52011076SCathy.Zhou@Sun.COM 
52111076SCathy.Zhou@Sun.COM 	cmd.vcl_ifname[0] = '\0';
52211076SCathy.Zhou@Sun.COM 	if (intf != NULL && (strlcpy(cmd.vcl_ifname, intf,
52311076SCathy.Zhou@Sun.COM 	    LIFNAMSIZ) >= LIFNAMSIZ)) {
52411076SCathy.Zhou@Sun.COM 		return (VRRP_EINVAL);
52511076SCathy.Zhou@Sun.COM 	}
52611076SCathy.Zhou@Sun.COM 
527*11451SCathy.Zhou@Sun.COM 	/*
528*11451SCathy.Zhou@Sun.COM 	 * If the service is not online, we assume there is no router
529*11451SCathy.Zhou@Sun.COM 	 * configured.
530*11451SCathy.Zhou@Sun.COM 	 */
531*11451SCathy.Zhou@Sun.COM 	if (!vrrp_svc_isonline(VRRP_SERVICE)) {
532*11451SCathy.Zhou@Sun.COM 		*cnt = 0;
533*11451SCathy.Zhou@Sun.COM 		return (VRRP_SUCCESS);
534*11451SCathy.Zhou@Sun.COM 	}
535*11451SCathy.Zhou@Sun.COM 
53611076SCathy.Zhou@Sun.COM 	cmd.vcl_cmd = VRRP_CMD_LIST;
53711076SCathy.Zhou@Sun.COM 	cmd.vcl_vrid = vrid;
53811076SCathy.Zhou@Sun.COM 	cmd.vcl_af = af;
53911076SCathy.Zhou@Sun.COM 
54011076SCathy.Zhou@Sun.COM 	list_arg.vfl_cnt = cnt;
54111076SCathy.Zhou@Sun.COM 	list_arg.vfl_names = names;
54211076SCathy.Zhou@Sun.COM 
54311076SCathy.Zhou@Sun.COM 	err = vrrp_cmd_request(&cmd, sizeof (cmd), vrrp_list_func, &list_arg);
54411076SCathy.Zhou@Sun.COM 	return (err);
54511076SCathy.Zhou@Sun.COM }
54611076SCathy.Zhou@Sun.COM 
54711076SCathy.Zhou@Sun.COM static vrrp_err_t
vrrp_query_func(int sock,void * arg)54811076SCathy.Zhou@Sun.COM vrrp_query_func(int sock, void *arg)
54911076SCathy.Zhou@Sun.COM {
55011076SCathy.Zhou@Sun.COM 	vrrp_queryinfo_t	*qinfo = arg;
55111076SCathy.Zhou@Sun.COM 	size_t			len, cur_size = 0, total;
55211076SCathy.Zhou@Sun.COM 	uint32_t		in_cnt = qinfo->show_va.va_vipcnt;
55311076SCathy.Zhou@Sun.COM 	uint32_t		out_cnt;
55411076SCathy.Zhou@Sun.COM 
55511076SCathy.Zhou@Sun.COM 	/*
55611076SCathy.Zhou@Sun.COM 	 * Expect the ack, first get the vrrp_ret_t.
55711076SCathy.Zhou@Sun.COM 	 */
55811076SCathy.Zhou@Sun.COM 	total = sizeof (vrrp_queryinfo_t);
55911076SCathy.Zhou@Sun.COM 	while (cur_size < total) {
56011076SCathy.Zhou@Sun.COM 		len = read(sock, (char *)qinfo + cur_size, total - cur_size);
56111076SCathy.Zhou@Sun.COM 		if (len == (size_t)-1 && errno == EAGAIN) {
56211076SCathy.Zhou@Sun.COM 			continue;
56311076SCathy.Zhou@Sun.COM 		} else if (len > 0) {
56411076SCathy.Zhou@Sun.COM 			cur_size += len;
56511076SCathy.Zhou@Sun.COM 			continue;
56611076SCathy.Zhou@Sun.COM 		}
567*11451SCathy.Zhou@Sun.COM 		return (VRRP_ESYS);
56811076SCathy.Zhou@Sun.COM 	}
56911076SCathy.Zhou@Sun.COM 
57011076SCathy.Zhou@Sun.COM 	out_cnt = qinfo->show_va.va_vipcnt;
57111076SCathy.Zhou@Sun.COM 
57211076SCathy.Zhou@Sun.COM 	/*
57311076SCathy.Zhou@Sun.COM 	 * Even if there is no IP virtual IP address, there is always
57411076SCathy.Zhou@Sun.COM 	 * space in the vrrp_queryinfo_t structure for one virtual
57511076SCathy.Zhou@Sun.COM 	 * IP address.
57611076SCathy.Zhou@Sun.COM 	 */
57711076SCathy.Zhou@Sun.COM 	out_cnt = (out_cnt == 0) ? 1 : out_cnt;
57811076SCathy.Zhou@Sun.COM 	out_cnt = (in_cnt < out_cnt ? in_cnt : out_cnt) - 1;
57911076SCathy.Zhou@Sun.COM 	total += out_cnt * sizeof (vrrp_addr_t);
58011076SCathy.Zhou@Sun.COM 
58111076SCathy.Zhou@Sun.COM 	while (cur_size < total) {
58211076SCathy.Zhou@Sun.COM 		len = read(sock, (char *)qinfo + cur_size, total - cur_size);
58311076SCathy.Zhou@Sun.COM 		if (len == (size_t)-1 && errno == EAGAIN) {
58411076SCathy.Zhou@Sun.COM 			continue;
58511076SCathy.Zhou@Sun.COM 		} else if (len > 0) {
58611076SCathy.Zhou@Sun.COM 			cur_size += len;
58711076SCathy.Zhou@Sun.COM 			continue;
58811076SCathy.Zhou@Sun.COM 		}
589*11451SCathy.Zhou@Sun.COM 		return (VRRP_ESYS);
59011076SCathy.Zhou@Sun.COM 	}
59111076SCathy.Zhou@Sun.COM 	return (VRRP_SUCCESS);
59211076SCathy.Zhou@Sun.COM }
59311076SCathy.Zhou@Sun.COM 
59411076SCathy.Zhou@Sun.COM /*
59511076SCathy.Zhou@Sun.COM  * *vqp is allocated inside this function and must be freed by the caller.
59611076SCathy.Zhou@Sun.COM  */
59711076SCathy.Zhou@Sun.COM /*ARGSUSED*/
59811076SCathy.Zhou@Sun.COM vrrp_err_t
vrrp_query(vrrp_handle_t vh,const char * vn,vrrp_queryinfo_t ** vqp)59911076SCathy.Zhou@Sun.COM vrrp_query(vrrp_handle_t vh, const char *vn, vrrp_queryinfo_t **vqp)
60011076SCathy.Zhou@Sun.COM {
60111076SCathy.Zhou@Sun.COM 	vrrp_cmd_query_t	cmd;
60211076SCathy.Zhou@Sun.COM 	vrrp_queryinfo_t	*qinfo;
60311076SCathy.Zhou@Sun.COM 	vrrp_err_t		err;
60411076SCathy.Zhou@Sun.COM 	size_t			size;
60511076SCathy.Zhou@Sun.COM 	uint32_t		vipcnt = 1;
60611076SCathy.Zhou@Sun.COM 
60711076SCathy.Zhou@Sun.COM 	if (strlcpy(cmd.vcq_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX)
60811076SCathy.Zhou@Sun.COM 		return (VRRP_EINVAL);
60911076SCathy.Zhou@Sun.COM 
610*11451SCathy.Zhou@Sun.COM 	/*
611*11451SCathy.Zhou@Sun.COM 	 * If the service is not online, we assume there is no router
612*11451SCathy.Zhou@Sun.COM 	 * configured.
613*11451SCathy.Zhou@Sun.COM 	 */
614*11451SCathy.Zhou@Sun.COM 	if (!vrrp_svc_isonline(VRRP_SERVICE))
615*11451SCathy.Zhou@Sun.COM 		return (VRRP_ENOTFOUND);
616*11451SCathy.Zhou@Sun.COM 
61711076SCathy.Zhou@Sun.COM 	cmd.vcq_cmd = VRRP_CMD_QUERY;
61811076SCathy.Zhou@Sun.COM 
61911076SCathy.Zhou@Sun.COM 	/*
62011076SCathy.Zhou@Sun.COM 	 * Allocate enough room for virtual IPs.
62111076SCathy.Zhou@Sun.COM 	 */
62211076SCathy.Zhou@Sun.COM again:
62311076SCathy.Zhou@Sun.COM 	size = sizeof (vrrp_queryinfo_t);
62411076SCathy.Zhou@Sun.COM 	size += (vipcnt == 0) ? 0 : (vipcnt - 1) * sizeof (vrrp_addr_t);
62511076SCathy.Zhou@Sun.COM 	if ((qinfo = malloc(size)) == NULL) {
62611076SCathy.Zhou@Sun.COM 		err = VRRP_ENOMEM;
62711076SCathy.Zhou@Sun.COM 		goto done;
62811076SCathy.Zhou@Sun.COM 	}
62911076SCathy.Zhou@Sun.COM 
63011076SCathy.Zhou@Sun.COM 	qinfo->show_va.va_vipcnt = vipcnt;
63111076SCathy.Zhou@Sun.COM 	err = vrrp_cmd_request(&cmd, sizeof (cmd), vrrp_query_func, qinfo);
63211076SCathy.Zhou@Sun.COM 	if (err != VRRP_SUCCESS) {
63311076SCathy.Zhou@Sun.COM 		free(qinfo);
63411076SCathy.Zhou@Sun.COM 		goto done;
63511076SCathy.Zhou@Sun.COM 	}
63611076SCathy.Zhou@Sun.COM 
63711076SCathy.Zhou@Sun.COM 	/*
63811076SCathy.Zhou@Sun.COM 	 * If the returned number of virtual IPs is greater than we expected,
63911076SCathy.Zhou@Sun.COM 	 * allocate more room and try again.
64011076SCathy.Zhou@Sun.COM 	 */
64111076SCathy.Zhou@Sun.COM 	if (qinfo->show_va.va_vipcnt > vipcnt) {
64211076SCathy.Zhou@Sun.COM 		vipcnt = qinfo->show_va.va_vipcnt;
64311076SCathy.Zhou@Sun.COM 		free(qinfo);
64411076SCathy.Zhou@Sun.COM 		goto again;
64511076SCathy.Zhou@Sun.COM 	}
64611076SCathy.Zhou@Sun.COM 
64711076SCathy.Zhou@Sun.COM 	*vqp = qinfo;
64811076SCathy.Zhou@Sun.COM 
64911076SCathy.Zhou@Sun.COM done:
65011076SCathy.Zhou@Sun.COM 	return (err);
65111076SCathy.Zhou@Sun.COM }
65211076SCathy.Zhou@Sun.COM 
65311076SCathy.Zhou@Sun.COM struct lookup_vnic_arg {
65411076SCathy.Zhou@Sun.COM 	vrid_t		lva_vrid;
65511076SCathy.Zhou@Sun.COM 	datalink_id_t	lva_linkid;
65611076SCathy.Zhou@Sun.COM 	int		lva_af;
65711076SCathy.Zhou@Sun.COM 	uint16_t	lva_vid;
65811076SCathy.Zhou@Sun.COM 	vrrp_handle_t	lva_vh;
65911076SCathy.Zhou@Sun.COM 	char		lva_vnic[MAXLINKNAMELEN];
66011076SCathy.Zhou@Sun.COM };
66111076SCathy.Zhou@Sun.COM 
66211076SCathy.Zhou@Sun.COM /*
66311076SCathy.Zhou@Sun.COM  * Is this a special VNIC interface created for VRRP? If so, return
66411076SCathy.Zhou@Sun.COM  * the linkid the VNIC was created on, the VRRP ID and address family.
66511076SCathy.Zhou@Sun.COM  */
66611076SCathy.Zhou@Sun.COM 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)66711076SCathy.Zhou@Sun.COM vrrp_is_vrrp_vnic(vrrp_handle_t vh, datalink_id_t vnicid,
66811076SCathy.Zhou@Sun.COM     datalink_id_t *linkidp, uint16_t *vidp, vrid_t *vridp, int *afp)
66911076SCathy.Zhou@Sun.COM {
67011076SCathy.Zhou@Sun.COM 	dladm_vnic_attr_t	vattr;
67111076SCathy.Zhou@Sun.COM 
67211076SCathy.Zhou@Sun.COM 	if (dladm_vnic_info(vh->vh_dh, vnicid, &vattr, DLADM_OPT_ACTIVE) !=
67311076SCathy.Zhou@Sun.COM 	    DLADM_STATUS_OK) {
67411076SCathy.Zhou@Sun.COM 		return (B_FALSE);
67511076SCathy.Zhou@Sun.COM 	}
67611076SCathy.Zhou@Sun.COM 
67711076SCathy.Zhou@Sun.COM 	*vridp = vattr.va_vrid;
67811076SCathy.Zhou@Sun.COM 	*vidp = vattr.va_vid;
67911076SCathy.Zhou@Sun.COM 	*afp = vattr.va_af;
68011076SCathy.Zhou@Sun.COM 	*linkidp = vattr.va_link_id;
68111076SCathy.Zhou@Sun.COM 	return (vattr.va_vrid != VRRP_VRID_NONE);
68211076SCathy.Zhou@Sun.COM }
68311076SCathy.Zhou@Sun.COM 
68411076SCathy.Zhou@Sun.COM static int
lookup_vnic(dladm_handle_t dh,datalink_id_t vnicid,void * arg)68511076SCathy.Zhou@Sun.COM lookup_vnic(dladm_handle_t dh, datalink_id_t vnicid, void *arg)
68611076SCathy.Zhou@Sun.COM {
68711076SCathy.Zhou@Sun.COM 	vrid_t			vrid;
68811076SCathy.Zhou@Sun.COM 	uint16_t		vid;
68911076SCathy.Zhou@Sun.COM 	datalink_id_t		linkid;
69011076SCathy.Zhou@Sun.COM 	int			af;
69111076SCathy.Zhou@Sun.COM 	struct lookup_vnic_arg	*lva = arg;
69211076SCathy.Zhou@Sun.COM 
69311076SCathy.Zhou@Sun.COM 	if (vrrp_is_vrrp_vnic(lva->lva_vh, vnicid, &linkid, &vid, &vrid,
69411076SCathy.Zhou@Sun.COM 	    &af) && lva->lva_vrid == vrid && lva->lva_linkid == linkid &&
69511076SCathy.Zhou@Sun.COM 	    lva->lva_vid == vid && lva->lva_af == af) {
69611076SCathy.Zhou@Sun.COM 		if (dladm_datalink_id2info(dh, vnicid, NULL, NULL, NULL,
69711076SCathy.Zhou@Sun.COM 		    lva->lva_vnic, sizeof (lva->lva_vnic)) == DLADM_STATUS_OK) {
69811076SCathy.Zhou@Sun.COM 			return (DLADM_WALK_TERMINATE);
69911076SCathy.Zhou@Sun.COM 		}
70011076SCathy.Zhou@Sun.COM 	}
70111076SCathy.Zhou@Sun.COM 	return (DLADM_WALK_CONTINUE);
70211076SCathy.Zhou@Sun.COM }
70311076SCathy.Zhou@Sun.COM 
70411076SCathy.Zhou@Sun.COM /*
70511076SCathy.Zhou@Sun.COM  * Given the primary link name, find the assoicated VRRP vnic name, if
70611076SCathy.Zhou@Sun.COM  * the vnic does not exist yet, return the linkid, vid of the primary link.
70711076SCathy.Zhou@Sun.COM  */
70811076SCathy.Zhou@Sun.COM 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)70911076SCathy.Zhou@Sun.COM vrrp_get_vnicname(vrrp_handle_t vh, vrid_t vrid, int af, char *link,
71011076SCathy.Zhou@Sun.COM     datalink_id_t *linkidp, uint16_t *vidp, char *vnic, size_t len)
71111076SCathy.Zhou@Sun.COM {
71211076SCathy.Zhou@Sun.COM 	datalink_id_t		linkid;
71311076SCathy.Zhou@Sun.COM 	uint32_t		flags;
71411076SCathy.Zhou@Sun.COM 	uint16_t		vid = VLAN_ID_NONE;
71511076SCathy.Zhou@Sun.COM 	datalink_class_t	class;
71611076SCathy.Zhou@Sun.COM 	dladm_vlan_attr_t	vlan_attr;
71711076SCathy.Zhou@Sun.COM 	struct lookup_vnic_arg	lva;
71811076SCathy.Zhou@Sun.COM 	uint32_t		media;
71911076SCathy.Zhou@Sun.COM 
72011076SCathy.Zhou@Sun.COM 	if ((strlen(link) == 0) || dladm_name2info(vh->vh_dh,
72111076SCathy.Zhou@Sun.COM 	    link, &linkid, &flags, &class, &media) !=
72211076SCathy.Zhou@Sun.COM 	    DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) {
72311076SCathy.Zhou@Sun.COM 		return (VRRP_EINVAL);
72411076SCathy.Zhou@Sun.COM 	}
72511076SCathy.Zhou@Sun.COM 
72611076SCathy.Zhou@Sun.COM 	if (class == DATALINK_CLASS_VLAN) {
72711076SCathy.Zhou@Sun.COM 		if (dladm_vlan_info(vh->vh_dh, linkid, &vlan_attr,
72811076SCathy.Zhou@Sun.COM 		    DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
72911076SCathy.Zhou@Sun.COM 			return (VRRP_EINVAL);
73011076SCathy.Zhou@Sun.COM 		}
73111076SCathy.Zhou@Sun.COM 		linkid = vlan_attr.dv_linkid;
73211076SCathy.Zhou@Sun.COM 		vid = vlan_attr.dv_vid;
73311076SCathy.Zhou@Sun.COM 		if ((dladm_datalink_id2info(vh->vh_dh, linkid, NULL,
73411076SCathy.Zhou@Sun.COM 		    &class, &media, NULL, 0)) != DLADM_STATUS_OK) {
73511076SCathy.Zhou@Sun.COM 			return (VRRP_EINVAL);
73611076SCathy.Zhou@Sun.COM 		}
73711076SCathy.Zhou@Sun.COM 	}
73811076SCathy.Zhou@Sun.COM 
73911076SCathy.Zhou@Sun.COM 	/*
74011076SCathy.Zhou@Sun.COM 	 * For now, Only VRRP over aggr and physical ethernet links is supported
74111076SCathy.Zhou@Sun.COM 	 */
74211076SCathy.Zhou@Sun.COM 	if ((class != DATALINK_CLASS_PHYS && class != DATALINK_CLASS_AGGR) ||
74311076SCathy.Zhou@Sun.COM 	    media != DL_ETHER) {
74411076SCathy.Zhou@Sun.COM 		return (VRRP_EINVAL);
74511076SCathy.Zhou@Sun.COM 	}
74611076SCathy.Zhou@Sun.COM 
74711076SCathy.Zhou@Sun.COM 	if (linkidp != NULL)
74811076SCathy.Zhou@Sun.COM 		*linkidp = linkid;
74911076SCathy.Zhou@Sun.COM 	if (vidp != NULL)
75011076SCathy.Zhou@Sun.COM 		*vidp = vid;
75111076SCathy.Zhou@Sun.COM 
75211076SCathy.Zhou@Sun.COM 	/*
75311076SCathy.Zhou@Sun.COM 	 * Find the assoicated vnic with the given vrid/vid/af/linkid
75411076SCathy.Zhou@Sun.COM 	 */
75511076SCathy.Zhou@Sun.COM 	lva.lva_vrid = vrid;
75611076SCathy.Zhou@Sun.COM 	lva.lva_vid = vid;
75711076SCathy.Zhou@Sun.COM 	lva.lva_af = af;
75811076SCathy.Zhou@Sun.COM 	lva.lva_linkid = linkid;
75911076SCathy.Zhou@Sun.COM 	lva.lva_vh = vh;
76011076SCathy.Zhou@Sun.COM 	lva.lva_vnic[0] = '\0';
76111076SCathy.Zhou@Sun.COM 
76211076SCathy.Zhou@Sun.COM 	(void) dladm_walk_datalink_id(lookup_vnic, vh->vh_dh, &lva,
76311076SCathy.Zhou@Sun.COM 	    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
76411076SCathy.Zhou@Sun.COM 	if (strlen(lva.lva_vnic) != 0) {
76511076SCathy.Zhou@Sun.COM 		(void) strlcpy(vnic, lva.lva_vnic, len);
76611076SCathy.Zhou@Sun.COM 		return (VRRP_SUCCESS);
76711076SCathy.Zhou@Sun.COM 	}
76811076SCathy.Zhou@Sun.COM 
76911076SCathy.Zhou@Sun.COM 	return (VRRP_ENOVNIC);
77011076SCathy.Zhou@Sun.COM }
771