# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include $(SRC)/lib/Makefile.lib HDRS = netinet/vrrp.h libvrrpadm.h HDRDIR = common # Hammerhead: amd64-only SUBDIRS = $(MACH64) POFILE = libvrrpadm.po MSGFILES = common/libvrrpadm.c XGETFLAGS = -a -x libvrrpadm.xcl all : TARGET = all clean : TARGET = clean clobber : TARGET = clobber install : TARGET = install .KEEP_STATE: all clean clobber install: $(SUBDIRS) install_h: $(ROOTHDRS) $(POFILE): pofile_MSGFILES _msg: $(MSGDOMAINPOFILE) check: $(CHECKHDRS) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY = libvrrpadm.a VERS = .1 OBJECTS = libvrrpadm.o include ../../Makefile.lib # install this library in the root filesystem #include ../../Makefile.rootfs LIBS = $(DYNLIB) LDLIBS += -lc -lsocket -ldladm -lscf SRCDIR = ../common CFLAGS += $(CCVERBOSE) CPPFLAGS += -I$(SRCDIR) -D_REENTRANT CSTD = $(CSTD_GNU99) .KEEP_STATE: all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../Makefile.com include ../../Makefile.lib.64 install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTCOMPATLINKS64) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* LIFNAMSIZ */ #include #include #include #include #include #include #include #include #define VRRP_SERVICE "network/vrrp:default" typedef vrrp_err_t vrrp_cmd_func_t(int, void *); static boolean_t vrrp_svc_isonline(char *svc_name) { char *s; boolean_t isonline = B_FALSE; if ((s = smf_get_state(svc_name)) != NULL) { if (strcmp(s, SCF_STATE_STRING_ONLINE) == 0) isonline = B_TRUE; free(s); } return (isonline); } #define MAX_WAIT_TIME 15 static vrrp_err_t vrrp_enable_service() { int i; if (vrrp_svc_isonline(VRRP_SERVICE)) return (VRRP_SUCCESS); if (smf_enable_instance(VRRP_SERVICE, 0) == -1) { if (scf_error() == SCF_ERROR_PERMISSION_DENIED) return (VRRP_EPERM); else return (VRRP_ENOSVC); } /* * Wait up to MAX_WAIT_TIME seconds for the VRRP service being brought * up online */ for (i = 0; i < MAX_WAIT_TIME; i++) { if (vrrp_svc_isonline(VRRP_SERVICE)) break; (void) sleep(1); } if (i == MAX_WAIT_TIME) return (VRRP_ENOSVC); return (VRRP_SUCCESS); } /* * Disable the VRRP service if there is no VRRP router left. */ static void vrrp_disable_service_when_no_router() { uint32_t cnt = 0; /* * Get the number of the existing routers. If there is no routers * left, disable the service. */ if (vrrp_list(NULL, VRRP_VRID_NONE, NULL, AF_UNSPEC, &cnt, NULL) == VRRP_SUCCESS && cnt == 0) { (void) smf_disable_instance(VRRP_SERVICE, 0); } } static vrrp_err_t vrrp_cmd_request(void *cmd, size_t csize, vrrp_cmd_func_t func, void *arg) { struct sockaddr_un to; int sock, flags; size_t len, cur_size = 0; vrrp_ret_t ret; vrrp_err_t err; if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) return (VRRP_ESYS); /* * Set it to be non-blocking. */ flags = fcntl(sock, F_GETFL, 0); (void) fcntl(sock, F_SETFL, (flags | O_NONBLOCK)); (void) memset(&to, 0, sizeof (to)); to.sun_family = AF_UNIX; (void) strlcpy(to.sun_path, VRRPD_SOCKET, sizeof (to.sun_path)); /* * Connect to vrrpd */ if (connect(sock, (const struct sockaddr *)&to, sizeof (to)) < 0) { (void) close(sock); return (VRRP_ENOSVC); } /* * Send the request */ while (cur_size < csize) { len = write(sock, (char *)cmd + cur_size, csize - cur_size); if (len == (size_t)-1 && errno == EAGAIN) { continue; } else if (len > 0) { cur_size += len; continue; } (void) close(sock); return (VRRP_ENOSVC); } /* * Expect the ack, first get the error code. */ cur_size = 0; while (cur_size < sizeof (vrrp_err_t)) { len = read(sock, (char *)&ret + cur_size, sizeof (vrrp_err_t) - cur_size); if (len == (size_t)-1 && errno == EAGAIN) { continue; } else if (len > 0) { cur_size += len; continue; } (void) close(sock); return (VRRP_ESYS); } if ((err = ret.vr_err) != VRRP_SUCCESS) goto done; /* * The specific callback gets the rest of the information. */ if (func != NULL) err = func(sock, arg); done: (void) close(sock); return (err); } /* * public APIs */ const char * vrrp_err2str(vrrp_err_t err) { switch (err) { case VRRP_SUCCESS: return (dgettext(TEXT_DOMAIN, "success")); case VRRP_ENOMEM: return (dgettext(TEXT_DOMAIN, "not enough memory")); case VRRP_EINVALVRNAME: return (dgettext(TEXT_DOMAIN, "invalid router name")); case VRRP_ENOPRIM: return (dgettext(TEXT_DOMAIN, "no primary IP")); case VRRP_EEXIST: return (dgettext(TEXT_DOMAIN, "already exists")); case VRRP_ENOVIRT: return (dgettext(TEXT_DOMAIN, "no virtual IPs")); case VRRP_EIPADM: return (dgettext(TEXT_DOMAIN, "ip configuration failure")); case VRRP_EDLADM: return (dgettext(TEXT_DOMAIN, "data-link configuration " "failure")); case VRRP_EDB: return (dgettext(TEXT_DOMAIN, "configuration update error")); case VRRP_EBADSTATE: return (dgettext(TEXT_DOMAIN, "invalid state")); case VRRP_EVREXIST: return (dgettext(TEXT_DOMAIN, "VRRP router already exists")); case VRRP_ETOOSMALL: return (dgettext(TEXT_DOMAIN, "not enough space")); case VRRP_EINSTEXIST: return (dgettext(TEXT_DOMAIN, "router name already exists")); case VRRP_ENOTFOUND: return (dgettext(TEXT_DOMAIN, "VRRP router not found")); case VRRP_EINVALADDR: return (dgettext(TEXT_DOMAIN, "invalid IP address")); case VRRP_EINVALAF: return (dgettext(TEXT_DOMAIN, "invalid IP address family")); case VRRP_EINVALLINK: return (dgettext(TEXT_DOMAIN, "invalid data-link")); case VRRP_EPERM: return (dgettext(TEXT_DOMAIN, "permission denied")); case VRRP_ESYS: return (dgettext(TEXT_DOMAIN, "system error")); case VRRP_EAGAIN: return (dgettext(TEXT_DOMAIN, "try again")); case VRRP_EALREADY: return (dgettext(TEXT_DOMAIN, "operation already in progress")); case VRRP_ENOVNIC: return (dgettext(TEXT_DOMAIN, "VRRP VNIC has not been " "created")); case VRRP_ENOLINK: return (dgettext(TEXT_DOMAIN, "the data-link does not exist")); case VRRP_ENOSVC: return (dgettext(TEXT_DOMAIN, "the VRRP service cannot " "be enabled")); case VRRP_EINVAL: default: return (dgettext(TEXT_DOMAIN, "invalid argument")); } } const char * vrrp_state2str(vrrp_state_t state) { switch (state) { case VRRP_STATE_NONE: return (dgettext(TEXT_DOMAIN, "NONE")); case VRRP_STATE_INIT: return (dgettext(TEXT_DOMAIN, "INIT")); case VRRP_STATE_MASTER: return (dgettext(TEXT_DOMAIN, "MASTER")); case VRRP_STATE_BACKUP: return (dgettext(TEXT_DOMAIN, "BACKUP")); default: return (dgettext(TEXT_DOMAIN, "INVALID")); } } vrrp_err_t vrrp_open(vrrp_handle_t *vh) { dladm_handle_t dh; if (dladm_open(&dh) != DLADM_STATUS_OK) return (VRRP_EDLADM); if ((*vh = malloc(sizeof (struct vrrp_handle))) == NULL) { dladm_close(dh); return (VRRP_ENOMEM); } (*vh)->vh_dh = dh; return (VRRP_SUCCESS); } void vrrp_close(vrrp_handle_t vh) { if (vh != NULL) { dladm_close(vh->vh_dh); free(vh); } } boolean_t vrrp_valid_name(const char *name) { const char *c; /* * The legal characters in a valid router name are: * alphanumeric (a-z, A-Z, 0-9), underscore ('_'), and '.'. */ for (c = name; *c != '\0'; c++) { if ((isalnum(*c) == 0) && (*c != '_')) return (B_FALSE); } return (B_TRUE); } /*ARGSUSED*/ vrrp_err_t vrrp_create(vrrp_handle_t vh, vrrp_vr_conf_t *conf) { vrrp_cmd_create_t cmd; vrrp_err_t err; again: /* * Enable the VRRP service if it is not already enabled. */ if ((err = vrrp_enable_service()) != VRRP_SUCCESS) return (err); cmd.vcc_cmd = VRRP_CMD_CREATE; (void) memcpy(&cmd.vcc_conf, conf, sizeof (vrrp_vr_conf_t)); err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL); if (err == VRRP_ENOSVC) { /* * This may be due to another process is deleting the last * router and disabled the VRRP service, try again. */ goto again; } else if (err != VRRP_SUCCESS) { /* * If router cannot be created, check if the VRRP service * should be disabled, and disable if needed. */ vrrp_disable_service_when_no_router(); } return (err); } /*ARGSUSED*/ vrrp_err_t vrrp_delete(vrrp_handle_t vh, const char *vn) { vrrp_cmd_delete_t cmd; vrrp_err_t err; /* * If the VRRP service is not enabled, we assume there is no router * configured. */ if (!vrrp_svc_isonline(VRRP_SERVICE)) return (VRRP_ENOTFOUND); cmd.vcd_cmd = VRRP_CMD_DELETE; if (strlcpy(cmd.vcd_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX) return (VRRP_EINVAL); err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL); if (err == VRRP_SUCCESS) vrrp_disable_service_when_no_router(); return (err); } /*ARGSUSED*/ vrrp_err_t vrrp_enable(vrrp_handle_t vh, const char *vn) { vrrp_cmd_enable_t cmd; vrrp_err_t err; /* * If the VRRP service is not enabled, we assume there is no router * configured. */ if (!vrrp_svc_isonline(VRRP_SERVICE)) return (VRRP_ENOTFOUND); cmd.vcs_cmd = VRRP_CMD_ENABLE; if (strlcpy(cmd.vcs_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX) return (VRRP_EINVAL); err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL); return (err); } /*ARGSUSED*/ vrrp_err_t vrrp_disable(vrrp_handle_t vh, const char *vn) { vrrp_cmd_disable_t cmd; vrrp_err_t err; /* * If the VRRP service is not enabled, we assume there is no router * configured. */ if (!vrrp_svc_isonline(VRRP_SERVICE)) return (VRRP_ENOTFOUND); cmd.vcx_cmd = VRRP_CMD_DISABLE; if (strlcpy(cmd.vcx_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX) return (VRRP_EINVAL); err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL); return (err); } /*ARGSUSED*/ vrrp_err_t vrrp_modify(vrrp_handle_t vh, vrrp_vr_conf_t *conf, uint32_t mask) { vrrp_cmd_modify_t cmd; vrrp_err_t err; /* * If the VRRP service is not enabled, we assume there is no router * configured. */ if (!vrrp_svc_isonline(VRRP_SERVICE)) return (VRRP_ENOTFOUND); cmd.vcm_cmd = VRRP_CMD_MODIFY; cmd.vcm_mask = mask; (void) memcpy(&cmd.vcm_conf, conf, sizeof (vrrp_vr_conf_t)); err = vrrp_cmd_request(&cmd, sizeof (cmd), NULL, NULL); return (err); } typedef struct vrrp_cmd_list_arg { uint32_t *vfl_cnt; char *vfl_names; } vrrp_cmd_list_arg_t; static vrrp_err_t vrrp_list_func(int sock, void *arg) { vrrp_cmd_list_arg_t *list_arg = arg; uint32_t in_cnt = *(list_arg->vfl_cnt); uint32_t out_cnt; vrrp_ret_list_t ret; size_t len, cur_size = 0; /* * Get the rest of vrrp_ret_list_t besides the error code. */ cur_size = sizeof (vrrp_err_t); while (cur_size < sizeof (vrrp_ret_list_t)) { len = read(sock, (char *)&ret + cur_size, sizeof (vrrp_ret_list_t) - cur_size); if (len == (size_t)-1 && errno == EAGAIN) { continue; } else if (len > 0) { cur_size += len; continue; } return (VRRP_ESYS); } *(list_arg->vfl_cnt) = out_cnt = ret.vrl_cnt; out_cnt = (in_cnt <= out_cnt) ? in_cnt : out_cnt; cur_size = 0; while (cur_size < VRRP_NAME_MAX * out_cnt) { len = read(sock, (char *)list_arg->vfl_names + cur_size, VRRP_NAME_MAX * out_cnt - cur_size); if (len == (size_t)-1 && errno == EAGAIN) { continue; } else if (len > 0) { cur_size += len; continue; } return (VRRP_ESYS); } return (VRRP_SUCCESS); } /* * Looks up the vrrp instances that matches the given variable. * * If the given cnt is 0, names should be set to NULL. In this case, only * the count of the matched instances is returned. * * If the given cnt is non-zero, caller must allocate "names" whose size * is (cnt * VRRP_NAME_MAX). * * Return value: the current count of matched instances, and names will be * points to the list of the current vrrp instances names. Note that * only MIN(in_cnt, out_cnt) number of names will be returned. */ /*ARGSUSED*/ vrrp_err_t vrrp_list(vrrp_handle_t vh, vrid_t vrid, const char *intf, int af, uint32_t *cnt, char *names) { vrrp_cmd_list_t cmd; vrrp_err_t err; vrrp_cmd_list_arg_t list_arg; if ((cnt == NULL) || (*cnt != 0 && names == NULL)) return (VRRP_EINVAL); cmd.vcl_ifname[0] = '\0'; if (intf != NULL && (strlcpy(cmd.vcl_ifname, intf, LIFNAMSIZ) >= LIFNAMSIZ)) { return (VRRP_EINVAL); } /* * If the service is not online, we assume there is no router * configured. */ if (!vrrp_svc_isonline(VRRP_SERVICE)) { *cnt = 0; return (VRRP_SUCCESS); } cmd.vcl_cmd = VRRP_CMD_LIST; cmd.vcl_vrid = vrid; cmd.vcl_af = af; list_arg.vfl_cnt = cnt; list_arg.vfl_names = names; err = vrrp_cmd_request(&cmd, sizeof (cmd), vrrp_list_func, &list_arg); return (err); } static vrrp_err_t vrrp_query_func(int sock, void *arg) { vrrp_queryinfo_t *qinfo = arg; size_t len, cur_size = 0, total; uint32_t in_cnt = qinfo->show_va.va_vipcnt; uint32_t out_cnt; /* * Expect the ack, first get the vrrp_ret_t. */ total = sizeof (vrrp_queryinfo_t); while (cur_size < total) { len = read(sock, (char *)qinfo + cur_size, total - cur_size); if (len == (size_t)-1 && errno == EAGAIN) { continue; } else if (len > 0) { cur_size += len; continue; } return (VRRP_ESYS); } out_cnt = qinfo->show_va.va_vipcnt; /* * Even if there is no IP virtual IP address, there is always * space in the vrrp_queryinfo_t structure for one virtual * IP address. */ out_cnt = (out_cnt == 0) ? 1 : out_cnt; out_cnt = (in_cnt < out_cnt ? in_cnt : out_cnt) - 1; total += out_cnt * sizeof (vrrp_addr_t); while (cur_size < total) { len = read(sock, (char *)qinfo + cur_size, total - cur_size); if (len == (size_t)-1 && errno == EAGAIN) { continue; } else if (len > 0) { cur_size += len; continue; } return (VRRP_ESYS); } return (VRRP_SUCCESS); } /* * *vqp is allocated inside this function and must be freed by the caller. */ /*ARGSUSED*/ vrrp_err_t vrrp_query(vrrp_handle_t vh, const char *vn, vrrp_queryinfo_t **vqp) { vrrp_cmd_query_t cmd; vrrp_queryinfo_t *qinfo; vrrp_err_t err; size_t size; uint32_t vipcnt = 1; if (strlcpy(cmd.vcq_name, vn, VRRP_NAME_MAX) >= VRRP_NAME_MAX) return (VRRP_EINVAL); /* * If the service is not online, we assume there is no router * configured. */ if (!vrrp_svc_isonline(VRRP_SERVICE)) return (VRRP_ENOTFOUND); cmd.vcq_cmd = VRRP_CMD_QUERY; /* * Allocate enough room for virtual IPs. */ again: size = sizeof (vrrp_queryinfo_t); size += (vipcnt == 0) ? 0 : (vipcnt - 1) * sizeof (vrrp_addr_t); if ((qinfo = malloc(size)) == NULL) { err = VRRP_ENOMEM; goto done; } qinfo->show_va.va_vipcnt = vipcnt; err = vrrp_cmd_request(&cmd, sizeof (cmd), vrrp_query_func, qinfo); if (err != VRRP_SUCCESS) { free(qinfo); goto done; } /* * If the returned number of virtual IPs is greater than we expected, * allocate more room and try again. */ if (qinfo->show_va.va_vipcnt > vipcnt) { vipcnt = qinfo->show_va.va_vipcnt; free(qinfo); goto again; } *vqp = qinfo; done: return (err); } struct lookup_vnic_arg { vrid_t lva_vrid; datalink_id_t lva_linkid; int lva_af; uint16_t lva_vid; vrrp_handle_t lva_vh; char lva_vnic[MAXLINKNAMELEN]; }; /* * Is this a special VNIC interface created for VRRP? If so, return * the linkid the VNIC was created on, the VRRP ID and address family. */ 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) { dladm_vnic_attr_t vattr; if (dladm_vnic_info(vh->vh_dh, vnicid, &vattr, DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) { return (B_FALSE); } *vridp = vattr.va_vrid; *vidp = vattr.va_vid; *afp = vattr.va_af; *linkidp = vattr.va_link_id; return (vattr.va_vrid != VRRP_VRID_NONE); } static int lookup_vnic(dladm_handle_t dh, datalink_id_t vnicid, void *arg) { vrid_t vrid; uint16_t vid; datalink_id_t linkid; int af; struct lookup_vnic_arg *lva = arg; if (vrrp_is_vrrp_vnic(lva->lva_vh, vnicid, &linkid, &vid, &vrid, &af) && lva->lva_vrid == vrid && lva->lva_linkid == linkid && (lva->lva_vid == VLAN_ID_NONE || lva->lva_vid == vid) && lva->lva_af == af) { if (dladm_datalink_id2info(dh, vnicid, NULL, NULL, NULL, lva->lva_vnic, sizeof (lva->lva_vnic)) == DLADM_STATUS_OK) { return (DLADM_WALK_TERMINATE); } } return (DLADM_WALK_CONTINUE); } /* * Given the primary link name, find the assoicated VRRP vnic name, if * the vnic does not exist yet, return the linkid, vid of the primary link. */ 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) { datalink_id_t linkid; uint32_t flags; uint16_t vid = VLAN_ID_NONE; datalink_class_t class; dladm_vlan_attr_t vlan_attr; dladm_vnic_attr_t vnic_attr; struct lookup_vnic_arg lva; uint32_t media; if ((strlen(link) == 0) || dladm_name2info(vh->vh_dh, link, &linkid, &flags, &class, &media) != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) { return (VRRP_EINVAL); } if (class == DATALINK_CLASS_VLAN) { if (dladm_vlan_info(vh->vh_dh, linkid, &vlan_attr, DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) { return (VRRP_EINVAL); } linkid = vlan_attr.dv_linkid; vid = vlan_attr.dv_vid; if ((dladm_datalink_id2info(vh->vh_dh, linkid, NULL, &class, &media, NULL, 0)) != DLADM_STATUS_OK) { return (VRRP_EINVAL); } } if (class == DATALINK_CLASS_VNIC) { if (dladm_vnic_info(vh->vh_dh, linkid, &vnic_attr, DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) { return (VRRP_EINVAL); } linkid = vnic_attr.va_link_id; vid = vnic_attr.va_vid; } /* * Only VRRP over vnics, aggrs and physical ethernet links is supported */ if ((class != DATALINK_CLASS_PHYS && class != DATALINK_CLASS_AGGR && class != DATALINK_CLASS_VNIC) || media != DL_ETHER) { return (VRRP_EINVAL); } if (linkidp != NULL) *linkidp = linkid; if (vidp != NULL) *vidp = vid; /* * Find the assoicated vnic with the given vrid/vid/af/linkid */ lva.lva_vrid = vrid; lva.lva_vid = vid; lva.lva_af = af; lva.lva_linkid = linkid; lva.lva_vh = vh; lva.lva_vnic[0] = '\0'; (void) dladm_walk_datalink_id(lookup_vnic, vh->vh_dh, &lva, DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); if (strlen(lva.lva_vnic) != 0) { (void) strlcpy(vnic, lva.lva_vnic, len); return (VRRP_SUCCESS); } return (VRRP_ENOVNIC); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _LIBVRRPADM_H #define _LIBVRRPADM_H #include #include #include /* in(6)_addr_t */ #include #include /* LIFNAMSIZ */ #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define VRRP_NAME_MAX 32 #define VRRPD_SOCKET "/var/run/vrrpd.socket" /* * to store the IP addresses */ typedef struct vrrp_addr { union { struct sockaddr_in a4; struct sockaddr_in6 a6; } in; #define in4 in.a4 #define in6 in.a6 } vrrp_addr_t; /* * VRRP instance (configuration information). * Passed to vrrp_create(), returned by vrrp_query(). */ typedef struct vrrp_vr_conf_s { char vvc_name[VRRP_NAME_MAX]; /* VRRP router name */ char vvc_link[MAXLINKNAMELEN]; /* data-link name */ vrid_t vvc_vrid; /* VRID */ int vvc_af; /* IPv4/IPv6 */ int vvc_pri; uint32_t vvc_adver_int; /* in ms */ boolean_t vvc_preempt; boolean_t vvc_accept; boolean_t vvc_enabled; } vrrp_vr_conf_t; /* * VRRP state machine */ typedef enum { VRRP_STATE_NONE = -1, VRRP_STATE_INIT, VRRP_STATE_MASTER, VRRP_STATE_BACKUP } vrrp_state_t; /* * VRRP status structure * Returned by vrrp_query() as part of vrrp_queryinfo_t. */ typedef struct vrrp_statusinfo_s { vrrp_state_t vs_state; vrrp_state_t vs_prev_state; struct timeval vs_st_time; /* timestamp of last state trans */ } vrrp_stateinfo_t; /* * The information obtained from peer's advertisements * Returned by vrrp_query() as part of vrrp_queryinfo_t. */ typedef struct vrrp_peer_s { vrrp_addr_t vp_addr; /* source IP addr of the message */ int vp_prio; /* priority in adv message */ struct timeval vp_time; /* timestamp of the adv message */ int vp_adver_int; /* adv interval in adv message */ } vrrp_peer_t; /* * Useful timer information, in ms */ typedef struct vrrp_timeinfo_s { int vt_since_last_tran; /* time since last state transition */ int vt_since_last_adv; /* time since last advertisement */ int vt_master_down_intv; /* timer interval for backup to */ /* declare master down */ } vrrp_timerinfo_t; /* * Address information */ typedef struct vrrp_addrinfo_s { char va_vnic[MAXLINKNAMELEN]; vrrp_addr_t va_primary; uint32_t va_vipcnt; vrrp_addr_t va_vips[1]; } vrrp_addrinfo_t; /* * VRRP instance configuration and run-time states information * Returned by vrrp_query(). */ typedef struct vrrp_queryinfo { vrrp_vr_conf_t show_vi; vrrp_stateinfo_t show_vs; vrrp_peer_t show_vp; vrrp_timerinfo_t show_vt; vrrp_addrinfo_t show_va; } vrrp_queryinfo_t; /* * flags sent with the VRRP_CMD_MODIFY command. Used in vrrp_setprop(). */ #define VRRP_CONF_PRIORITY 0x01 #define VRRP_CONF_INTERVAL 0x02 #define VRRP_CONF_PREEMPT 0x04 #define VRRP_CONF_ACCEPT 0x08 /* * Errors */ typedef enum { VRRP_SUCCESS = 0, VRRP_EINVAL, /* invalid parameter */ VRRP_EINVALVRNAME, /* invalid router name */ VRRP_ENOMEM, /* no memory */ VRRP_ENOVIRT, /* no virtual IP addresses */ VRRP_ENOPRIM, /* no primary IP address */ VRRP_ENOVNIC, /* no vnic created */ VRRP_ENOLINK, /* the link does not exist */ VRRP_EINVALLINK, /* invalid link */ VRRP_EINVALADDR, /* invalid IP address */ VRRP_EINVALAF, /* invalid IP address familty */ VRRP_EDB, /* configuration error */ VRRP_EPERM, /* permission denied */ VRRP_EBADSTATE, /* VRRP router in bad state */ VRRP_EVREXIST, /* three-tuple exists */ VRRP_EINSTEXIST, /* router name already exists */ VRRP_EEXIST, /* already exists */ VRRP_ENOTFOUND, /* vrrp router not found */ VRRP_ETOOSMALL, /* too small space */ VRRP_EAGAIN, /* Try again */ VRRP_EALREADY, /* already */ VRRP_EDLADM, /* dladm failure */ VRRP_EIPADM, /* ipadm failure */ VRRP_ESYS, /* system error */ VRRP_ENOSVC /* VRRP service not enabled */ } vrrp_err_t; /* * Internal commands used between vrrpadm and vrrpd. */ typedef enum { VRRP_CMD_RETURN = 0, VRRP_CMD_CREATE, VRRP_CMD_DELETE, VRRP_CMD_ENABLE, VRRP_CMD_DISABLE, VRRP_CMD_MODIFY, VRRP_CMD_LIST, VRRP_CMD_QUERY } vrrp_cmd_type_t; #define addr_len(af) ((af) == AF_INET ? sizeof (in_addr_t): sizeof (in6_addr_t)) #define VRRPADDR_UNSPECIFIED(af, addr) \ (((af) == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED( \ &(addr)->in6.sin6_addr)) || ((af) == AF_INET && \ ((addr)->in4.sin_addr.s_addr == INADDR_ANY))) #define VRRPADDR2STR(af, addr, abuf, size, append) { \ char ap[INET6_ADDRSTRLEN]; \ \ if (VRRPADDR_UNSPECIFIED(af, addr)) { \ (void) strlcpy(ap, "--", INET6_ADDRSTRLEN); \ } else if ((af) == AF_INET) { \ (void) inet_ntop((af), &(addr)->in4.sin_addr, ap, \ INET6_ADDRSTRLEN); \ } else { \ (void) inet_ntop((af), &(addr)->in6.sin6_addr, ap, \ INET6_ADDRSTRLEN); \ } \ if (append) \ (void) strlcat(abuf, ap, size); \ else \ (void) strlcpy(abuf, ap, size); \ } typedef struct vrrp_cmd_create_s { uint32_t vcc_cmd; vrrp_vr_conf_t vcc_conf; } vrrp_cmd_create_t; typedef struct vrrp_ret_create_s { vrrp_err_t vrc_err; } vrrp_ret_create_t; typedef struct vrrp_cmd_delete_s { uint32_t vcd_cmd; char vcd_name[VRRP_NAME_MAX]; } vrrp_cmd_delete_t; typedef struct vrrp_ret_delete_s { vrrp_err_t vrd_err; } vrrp_ret_delete_t; typedef struct vrrp_cmd_enable_s { uint32_t vcs_cmd; char vcs_name[VRRP_NAME_MAX]; } vrrp_cmd_enable_t; typedef struct vrrp_ret_enable_s { vrrp_err_t vrs_err; } vrrp_ret_enable_t; typedef struct vrrp_cmd_disable_s { uint32_t vcx_cmd; char vcx_name[VRRP_NAME_MAX]; } vrrp_cmd_disable_t; typedef struct vrrp_ret_disable_s { vrrp_err_t vrx_err; } vrrp_ret_disable_t; typedef struct vrrp_cmd_modify_s { uint32_t vcm_cmd; uint32_t vcm_mask; vrrp_vr_conf_t vcm_conf; } vrrp_cmd_modify_t; typedef struct vrrp_ret_modify_s { vrrp_err_t vrm_err; } vrrp_ret_modify_t; typedef struct vrrp_cmd_list_s { uint32_t vcl_cmd; vrid_t vcl_vrid; char vcl_ifname[LIFNAMSIZ]; int vcl_af; } vrrp_cmd_list_t; typedef struct vrrp_ret_list_s { vrrp_err_t vrl_err; uint32_t vrl_cnt; /* * When vrl_cnt is non-zero, the return structure will be followed * by the list of router names, separated by '\0'. Its size will * be vrl_cnt * VRRP_NAME_MAX. */ } vrrp_ret_list_t; typedef struct vrrp_cmd_query_s { uint32_t vcq_cmd; char vcq_name[VRRP_NAME_MAX]; } vrrp_cmd_query_t; typedef struct vrrp_ret_query_s { vrrp_err_t vrq_err; vrrp_queryinfo_t vrq_qinfo; } vrrp_ret_query_t; /* * Union of all VRRP commands */ typedef union vrrp_cmd_s { uint32_t vc_cmd; vrrp_cmd_create_t vc_cmd_create; vrrp_cmd_delete_t vc_cmd_delete; vrrp_cmd_enable_t vc_cmd_enable; vrrp_cmd_disable_t vc_cmd_disable; vrrp_cmd_modify_t vc_cmd_modify; vrrp_cmd_list_t vc_cmd_list; } vrrp_cmd_t; /* * Union of all VRRP replies of the VRRP commands */ typedef union vrrp_ret_s { vrrp_err_t vr_err; vrrp_ret_create_t vr_ret_create; vrrp_ret_delete_t vr_ret_delete; vrrp_ret_enable_t vr_ret_enable; vrrp_ret_disable_t vr_ret_disable; vrrp_ret_modify_t vr_ret_modify; vrrp_ret_list_t vr_ret_list; vrrp_ret_query_t vr_ret_query; } vrrp_ret_t; /* * Public APIs */ struct vrrp_handle { dladm_handle_t vh_dh; }; typedef struct vrrp_handle *vrrp_handle_t; const char *vrrp_err2str(vrrp_err_t); const char *vrrp_state2str(vrrp_state_t); vrrp_err_t vrrp_open(vrrp_handle_t *); void vrrp_close(vrrp_handle_t); boolean_t vrrp_valid_name(const char *); vrrp_err_t vrrp_create(vrrp_handle_t, vrrp_vr_conf_t *); vrrp_err_t vrrp_delete(vrrp_handle_t, const char *); vrrp_err_t vrrp_enable(vrrp_handle_t, const char *); vrrp_err_t vrrp_disable(vrrp_handle_t, const char *); vrrp_err_t vrrp_modify(vrrp_handle_t, vrrp_vr_conf_t *, uint32_t); vrrp_err_t vrrp_query(vrrp_handle_t, const char *, vrrp_queryinfo_t **); vrrp_err_t vrrp_list(vrrp_handle_t, vrid_t, const char *, int, uint32_t *, char *); boolean_t vrrp_is_vrrp_vnic(vrrp_handle_t, datalink_id_t, datalink_id_t *, uint16_t *, vrid_t *, int *); vrrp_err_t vrrp_get_vnicname(vrrp_handle_t, vrid_t, int, char *, datalink_id_t *, uint16_t *, char *, size_t); #ifdef __cplusplus } #endif #endif /* _LIBVRRPADM_H */ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNWprivate_1.1 { global: vrrp_close; vrrp_create; vrrp_delete; vrrp_disable; vrrp_enable; vrrp_err2str; vrrp_get_vnicname; vrrp_is_vrrp_vnic; vrrp_list; vrrp_modify; vrrp_open; vrrp_query; vrrp_state2str; vrrp_valid_name; local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _VRRP_H #define _VRRP_H #include #ifdef __cplusplus extern "C" { #endif typedef struct vrrp_pkt_s { uint8_t vp_vers_type; uint8_t vp_vrid; uint8_t vp_prio; uint8_t vp_ipnum; uint16_t vp_rsvd_adver_int; uint16_t vp_chksum; /* then follows IPvX addresses */ /* then follows NO authentification data */ } vrrp_pkt_t; #define IPPROTO_VRRP 112 /* IP protocol number */ #define VRRP_AUTH_LEN 0 /* XXX length of a chunk of Auth Data */ #define VRRP_IP_TTL 255 /* IPv4 TTL, IPv6 hop limit */ #define VRRP_VERSION 3 /* current version */ #define VRRP_PKT_ADVERT 1 /* packet type */ #define VRRP_VER_MASK 0xf0 /* version mask */ #define VRRP_TYPE_MASK 0x0f /* packet type mask */ #define VRRP_PRI_OWNER 255 /* priority of IP address owner */ #define VRRP_PRI_MIN 1 /* minimum priority */ #define VRRP_PRIO_ZERO 0 /* stop participating VRRP */ #define VRRP_PRI_DEFAULT VRRP_PRI_OWNER /* default priority */ #define VRRP_VRID_NONE 0 #define VRRP_VRID_MIN 1 #define VRRP_VRID_MAX 255 #define CENTISEC2MSEC(centisec) ((centisec) * 10) #define MSEC2CENTISEC(msec) ((msec) / 10) /* Max advertisement interval, in msec */ #define VRRP_MAX_ADVER_INT_MIN CENTISEC2MSEC(1) #define VRRP_MAX_ADVER_INT_MAX CENTISEC2MSEC(4095) /* (2^12 -1) */ #define VRRP_MAX_ADVER_INT_DFLT CENTISEC2MSEC(100) /* 1 sec */ #ifdef __cplusplus } #endif #endif /* _VRRP_H */ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # msgid "VRRP" msgid "vrrpd" msgid "VNIC" msgid "NONE" msgid "INIT" msgid "MASTER" msgid "BACKUP"