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