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
vrrp_svc_isonline(char * svc_name)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
vrrp_enable_service()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
vrrp_disable_service_when_no_router()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
vrrp_cmd_request(void * cmd,size_t csize,vrrp_cmd_func_t func,void * arg)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 *
vrrp_err2str(vrrp_err_t err)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 *
vrrp_state2str(vrrp_state_t state)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
vrrp_open(vrrp_handle_t * vh)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
vrrp_close(vrrp_handle_t vh)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
vrrp_valid_name(const char * name)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
vrrp_create(vrrp_handle_t vh,vrrp_vr_conf_t * conf)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
vrrp_delete(vrrp_handle_t vh,const char * vn)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
vrrp_enable(vrrp_handle_t vh,const char * vn)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
vrrp_disable(vrrp_handle_t vh,const char * vn)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
vrrp_modify(vrrp_handle_t vh,vrrp_vr_conf_t * conf,uint32_t mask)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
vrrp_list_func(int sock,void * arg)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
vrrp_list(vrrp_handle_t vh,vrid_t vrid,const char * intf,int af,uint32_t * cnt,char * names)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
vrrp_query_func(int sock,void * arg)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
vrrp_query(vrrp_handle_t vh,const char * vn,vrrp_queryinfo_t ** vqp)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
vrrp_is_vrrp_vnic(vrrp_handle_t vh,datalink_id_t vnicid,datalink_id_t * linkidp,uint16_t * vidp,vrid_t * vridp,int * afp)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
lookup_vnic(dladm_handle_t dh,datalink_id_t vnicid,void * arg)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
vrrp_get_vnicname(vrrp_handle_t vh,vrid_t vrid,int af,char * link,datalink_id_t * linkidp,uint16_t * vidp,char * vnic,size_t len)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