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