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