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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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