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