diff options
Diffstat (limited to 'usr/src/lib/libdladm/common')
-rw-r--r-- | usr/src/lib/libdladm/common/libdladm.c | 85 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/libdladm.h | 22 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/libdladm_impl.h | 7 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/libdllink.c | 28 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/libdllink.h | 6 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/libdlmgmt.c | 19 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/libdloverlay.c | 887 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/libdloverlay.h | 107 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/libdlvlan.c | 2 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/libdlvnic.c | 39 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/libdlvnic.h | 3 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/linkprop.c | 69 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/llib-ldladm | 2 | ||||
-rw-r--r-- | usr/src/lib/libdladm/common/mapfile-vers | 19 |
14 files changed, 1261 insertions, 34 deletions
diff --git a/usr/src/lib/libdladm/common/libdladm.c b/usr/src/lib/libdladm/common/libdladm.c index cf113e7357..37823ce913 100644 --- a/usr/src/lib/libdladm/common/libdladm.c +++ b/usr/src/lib/libdladm/common/libdladm.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Joyent, Inc. */ #include <unistd.h> @@ -29,6 +30,9 @@ #include <strings.h> #include <dirent.h> #include <stdlib.h> +#include <assert.h> +#include <stdio.h> +#include <stdarg.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/param.h> @@ -418,6 +422,9 @@ dladm_status2str(dladm_status_t status, char *buf) case DLADM_STATUS_INVALID_MTU: s = "MTU check failed, MTU outside of device's supported range"; break; + case DLADM_STATUS_BAD_ENCAP: + s = "invalid encapsulation protocol"; + break; default: s = "<unknown error>"; break; @@ -654,6 +661,9 @@ dladm_class2str(datalink_class_t class, char *buf) case DATALINK_CLASS_PART: s = "part"; break; + case DATALINK_CLASS_OVERLAY: + s = "overlay"; + break; default: s = "unknown"; break; @@ -1132,15 +1142,15 @@ dladm_strs2range(char **prop_val, uint_t val_cnt, * Convert a mac_propval_range_t structure into an array of elements. */ dladm_status_t -dladm_range2list(mac_propval_range_t *rangep, void *elem, uint_t *nelem) +dladm_range2list(const mac_propval_range_t *rangep, void *elem, uint_t *nelem) { int i, j, k; dladm_status_t status = DLADM_STATUS_OK; switch (rangep->mpr_type) { case MAC_PROPVAL_UINT32: { - mac_propval_uint32_range_t *ur; - uint32_t *elem32 = elem; + const mac_propval_uint32_range_t *ur; + uint32_t *elem32 = elem; k = 0; ur = &rangep->mpr_range_uint32[0]; @@ -1168,13 +1178,13 @@ dladm_range2list(mac_propval_range_t *rangep, void *elem, uint_t *nelem) * of single elements or ranges. */ int -dladm_range2strs(mac_propval_range_t *rangep, char **prop_val) +dladm_range2strs(const mac_propval_range_t *rangep, char **prop_val) { int i; switch (rangep->mpr_type) { case MAC_PROPVAL_UINT32: { - mac_propval_uint32_range_t *ur; + const mac_propval_uint32_range_t *ur; /* Write ranges and individual elements */ ur = &rangep->mpr_range_uint32[0]; @@ -1191,6 +1201,20 @@ dladm_range2strs(mac_propval_range_t *rangep, char **prop_val) } return (0); } + case MAC_PROPVAL_STR: { + const mac_propval_str_range_t *str; + size_t coff, len; + + coff = 0; + str = &rangep->u.mpr_str; + for (i = 0; i < rangep->mpr_count; i++) { + len = strlen(&str->mpur_data[coff]); + (void) strlcpy(prop_val[i], &str->mpur_data[coff], + DLADM_PROP_VAL_MAX); + coff += len + 1; + } + return (0); + } default: break; } @@ -1268,3 +1292,54 @@ dladm_list2range(void *elem, uint_t nelem, mac_propval_type_t type, return (status); } + +void +dladm_errlist_init(dladm_errlist_t *erl) +{ + bzero(erl, sizeof (dladm_errlist_t)); +} + +void +dladm_errlist_reset(dladm_errlist_t *erl) +{ + uint_t i; + + for (i = 0; i < erl->el_count; i++) + free(erl->el_errs[i]); + free(erl->el_errs); + dladm_errlist_init(erl); +} + +dladm_status_t +dladm_errlist_append(dladm_errlist_t *erl, const char *fmt, ...) +{ + int ret; + va_list ap; + char *m = NULL; + + if (erl->el_count == erl->el_alloc) { + int alloc; + void *addr; + if (erl->el_alloc == 0) { + assert(erl->el_errs == NULL); + alloc = 32; + } else { + alloc = erl->el_alloc + 32; + } + addr = realloc(erl->el_errs, sizeof (char *) * alloc); + if (addr == NULL) + return (DLADM_STATUS_NOMEM); + + erl->el_errs = addr; + erl->el_alloc = alloc; + } + + va_start(ap, fmt); + ret = vasprintf(&m, fmt, ap); + va_end(ap); + if (ret == -1) + return (dladm_errno2status(errno)); + erl->el_errs[erl->el_count] = m; + erl->el_count++; + return (DLADM_STATUS_OK); +} diff --git a/usr/src/lib/libdladm/common/libdladm.h b/usr/src/lib/libdladm/common/libdladm.h index c2fceb25ab..2a0491c048 100644 --- a/usr/src/lib/libdladm/common/libdladm.h +++ b/usr/src/lib/libdladm/common/libdladm.h @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2015, Joyent, Inc. */ #ifndef _LIBDLADM_H @@ -71,6 +72,10 @@ extern "C" { * - DLADM_OPT_BOOT: * Bypass check functions during boot (used by pool property since pools * can come up after link properties are set) + * + * - DLADM_OPT_TRANSIENT: + * Indicates that the link assigned to a zone is transient and will be + * removed when the zone shuts down. */ #define DLADM_OPT_ACTIVE 0x00000001 #define DLADM_OPT_PERSIST 0x00000002 @@ -81,6 +86,7 @@ extern "C" { #define DLADM_OPT_VLAN 0x00000040 #define DLADM_OPT_NOREFRESH 0x00000080 #define DLADM_OPT_BOOT 0x00000100 +#define DLADM_OPT_TRANSIENT 0x00000200 #define DLADM_WALK_TERMINATE 0 #define DLADM_WALK_CONTINUE -1 @@ -173,7 +179,8 @@ typedef enum { DLADM_STATUS_NO_IB_HW_RESOURCE, DLADM_STATUS_INVALID_PKEY_TBL_SIZE, DLADM_STATUS_PORT_NOPROTO, - DLADM_STATUS_INVALID_MTU + DLADM_STATUS_INVALID_MTU, + DLADM_STATUS_BAD_ENCAP } dladm_status_t; typedef enum { @@ -221,6 +228,12 @@ typedef struct dladm_arg_list { char *al_buf; } dladm_arg_list_t; +typedef struct dladm_errlist { + uint_t el_count; + uint_t el_alloc; + char **el_errs; +} dladm_errlist_t; + typedef enum { DLADM_LOGTYPE_LINK = 1, DLADM_LOGTYPE_FLOW @@ -282,12 +295,15 @@ extern dladm_status_t dladm_zone_halt(dladm_handle_t, zoneid_t); extern dladm_status_t dladm_strs2range(char **, uint_t, mac_propval_type_t, mac_propval_range_t **); -extern dladm_status_t dladm_range2list(mac_propval_range_t *, void*, +extern dladm_status_t dladm_range2list(const mac_propval_range_t *, void *, uint_t *); -extern int dladm_range2strs(mac_propval_range_t *, char **); +extern int dladm_range2strs(const mac_propval_range_t *, char **); extern dladm_status_t dladm_list2range(void *, uint_t, mac_propval_type_t, mac_propval_range_t **); +extern void dladm_errlist_init(dladm_errlist_t *); +extern void dladm_errlist_reset(dladm_errlist_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libdladm/common/libdladm_impl.h b/usr/src/lib/libdladm/common/libdladm_impl.h index 13169285e3..e1a3177808 100644 --- a/usr/src/lib/libdladm/common/libdladm_impl.h +++ b/usr/src/lib/libdladm/common/libdladm_impl.h @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2015, Joyent, Inc. */ #ifndef _LIBDLADM_IMPL_H @@ -168,6 +169,12 @@ typedef struct resource_prop_s { */ #define FBRIDGE "bridge" /* string */ +/* + * For error lists + */ +extern dladm_status_t dladm_errlist_append(dladm_errlist_t *, + const char *, ...); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libdladm/common/libdllink.c b/usr/src/lib/libdladm/common/libdllink.c index 8a3c5759ee..303885e929 100644 --- a/usr/src/lib/libdladm/common/libdllink.c +++ b/usr/src/lib/libdladm/common/libdllink.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, Joyent Inc. All rights reserved. */ #include <sys/types.h> @@ -386,10 +387,14 @@ dladm_linkduplex2str(link_duplex_t duplex, char *buf) /* * Case 1: rename an existing link1 to a link2 that does not exist. * Result: <linkid1, link2> + * The zonename parameter is used to allow us to create a VNIC in the global + * zone which is assigned to a non-global zone. Since there is a race condition + * in the create process if two VNICs have the same name, we need to rename it + * after it has been assigned to the zone. */ static dladm_status_t i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1, - const char *link1, const char *link2, uint32_t flags) + const char *link1, const char *link2, uint32_t flags, const char *zonename) { dld_ioc_rename_t dir; dladm_status_t status = DLADM_STATUS_OK; @@ -402,6 +407,10 @@ i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1, dir.dir_linkid1 = linkid1; dir.dir_linkid2 = DATALINK_INVALID_LINKID; (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN); + if (zonename != NULL) + dir.dir_zoneinit = B_TRUE; + else + dir.dir_zoneinit = B_FALSE; if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) { status = dladm_errno2status(errno); @@ -412,6 +421,7 @@ i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1, status = dladm_remap_datalink_id(handle, linkid1, link2); if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) { (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN); + dir.dir_zoneinit = B_FALSE; (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir); } return (status); @@ -508,6 +518,7 @@ i_dladm_rename_link_c2(dladm_handle_t handle, datalink_id_t linkid1, */ dir.dir_linkid1 = linkid1; dir.dir_linkid2 = linkid2; + dir.dir_zoneinit = B_FALSE; if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) status = dladm_errno2status(errno); @@ -617,7 +628,8 @@ done: } dladm_status_t -dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2) +dladm_rename_link(dladm_handle_t handle, const char *zonename, + const char *link1, const char *link2) { datalink_id_t linkid1 = DATALINK_INVALID_LINKID; datalink_id_t linkid2 = DATALINK_INVALID_LINKID; @@ -627,11 +639,11 @@ dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2) boolean_t remphy2 = B_FALSE; dladm_status_t status; - (void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1, - &media1); - if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2, - &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) && - (flags2 == DLADM_OPT_PERSIST)) { + (void) dladm_zname2info(handle, zonename, link1, &linkid1, &flags1, + &class1, &media1); + if ((dladm_zname2info(handle, zonename, link2, &linkid2, &flags2, + &class2, &media2) == DLADM_STATUS_OK) && + (class2 == DATALINK_CLASS_PHYS) && (flags2 == DLADM_OPT_PERSIST)) { /* * see whether link2 is a removed physical link. */ @@ -645,7 +657,7 @@ dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2) * does not exist. */ status = i_dladm_rename_link_c1(handle, linkid1, link1, - link2, flags1); + link2, flags1, zonename); } else if (remphy2) { /* * case 2: rename an available link to a REMOVED diff --git a/usr/src/lib/libdladm/common/libdllink.h b/usr/src/lib/libdladm/common/libdllink.h index a2830b5e37..a858e78aa3 100644 --- a/usr/src/lib/libdladm/common/libdllink.h +++ b/usr/src/lib/libdladm/common/libdllink.h @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, Joyent Inc. All rights reserved. */ #ifndef _LIBDLLINK_H @@ -121,7 +122,7 @@ extern dladm_status_t dladm_info(dladm_handle_t, datalink_id_t, dladm_attr_t *); extern dladm_status_t dladm_rename_link(dladm_handle_t, const char *, - const char *); + const char *, const char *); extern dladm_status_t dladm_set_linkprop(dladm_handle_t, datalink_id_t, const char *, char **, uint_t, uint_t); @@ -170,6 +171,9 @@ extern dladm_status_t dladm_up_datalink_id(dladm_handle_t, datalink_id_t); extern dladm_status_t dladm_name2info(dladm_handle_t, const char *, datalink_id_t *, uint32_t *, datalink_class_t *, uint32_t *); +extern dladm_status_t dladm_zname2info(dladm_handle_t, const char *, + const char *, datalink_id_t *, uint32_t *, + datalink_class_t *, uint32_t *); extern dladm_status_t dladm_datalink_id2info(dladm_handle_t, datalink_id_t, uint32_t *, datalink_class_t *, uint32_t *, char *, size_t); diff --git a/usr/src/lib/libdladm/common/libdlmgmt.c b/usr/src/lib/libdladm/common/libdlmgmt.c index 4b0753417c..c9c7906934 100644 --- a/usr/src/lib/libdladm/common/libdlmgmt.c +++ b/usr/src/lib/libdladm/common/libdlmgmt.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, Joyent Inc. All rights reserved. */ #include <door.h> @@ -528,12 +529,24 @@ dladm_getnext_conf_linkprop(dladm_handle_t handle, dladm_conf_t conf, } /* - * Get the link ID that is associated with the given name. + * Get the link ID that is associated with the given name in the current zone. */ dladm_status_t dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp, uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap) { + return (dladm_zname2info(handle, NULL, link, linkidp, flagp, classp, + mediap)); +} + +/* + * Get the link ID that is associated with the given zone/name pair. + */ +dladm_status_t +dladm_zname2info(dladm_handle_t handle, const char *zonename, const char *link, + datalink_id_t *linkidp, uint32_t *flagp, datalink_class_t *classp, + uint32_t *mediap) +{ dlmgmt_door_getlinkid_t getlinkid; dlmgmt_getlinkid_retval_t retval; datalink_id_t linkid; @@ -542,6 +555,10 @@ dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp, getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); + if (zonename != NULL) + getlinkid.ld_zoneid = getzoneidbyname(zonename); + else + getlinkid.ld_zoneid = -1; if ((status = dladm_door_call(handle, &getlinkid, sizeof (getlinkid), &retval, &sz)) != DLADM_STATUS_OK) { diff --git a/usr/src/lib/libdladm/common/libdloverlay.c b/usr/src/lib/libdladm/common/libdloverlay.c new file mode 100644 index 0000000000..3da9005183 --- /dev/null +++ b/usr/src/lib/libdladm/common/libdloverlay.c @@ -0,0 +1,887 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2015 Joyent, Inc. + */ + +#include <libdladm_impl.h> +#include <libdllink.h> +#include <libdloverlay.h> +#include <sys/dld.h> +#include <sys/overlay.h> +#include <strings.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <limits.h> +#include <libvarpd_client.h> + +#define VARPD_PROPERTY_NAME "varpd/id" + +static const char *dladm_overlay_doorpath = "/var/run/varpd/varpd.door"; + +typedef struct dladm_overlay_propinfo { + boolean_t dop_isvarpd; + union { + overlay_ioc_propinfo_t *dop_overlay; + varpd_client_prop_handle_t *dop_varpd; + } dop_un; +} dladm_overlay_propinfo_t; + +dladm_status_t +dladm_overlay_prop_info(dladm_overlay_propinfo_handle_t phdl, + const char **namep, uint_t *typep, uint_t *protp, const void **defp, + uint32_t *sizep, const mac_propval_range_t **possp) +{ + dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)phdl; + overlay_ioc_propinfo_t *oinfop = infop->dop_un.dop_overlay; + + if (infop->dop_isvarpd == B_FALSE) { + if (namep != NULL) + *namep = oinfop->oipi_name; + if (typep != NULL) + *typep = oinfop->oipi_type; + if (protp != NULL) + *protp = oinfop->oipi_prot; + if (defp != NULL) + *defp = oinfop->oipi_default; + if (sizep != NULL) + *sizep = oinfop->oipi_defsize; + if (possp != NULL) { + /* LINTED: E_BAD_PTR_CAST_ALIGN */ + *possp = (const mac_propval_range_t *)oinfop->oipi_poss; + } + + } else { + int ret; + ret = libvarpd_c_prop_info(infop->dop_un.dop_varpd, namep, + typep, protp, defp, sizep, possp); + if (ret != 0) + return (dladm_errno2status(ret)); + + } + + return (DLADM_STATUS_OK); +} + +static dladm_status_t +dladm_overlay_parse_prop(overlay_prop_type_t type, void *buf, uint32_t *sizep, + const char *val) +{ + int ret; + int64_t ival; + uint64_t uval; + char *eptr; + struct in6_addr ipv6; + struct in_addr ip; + + switch (type) { + case OVERLAY_PROP_T_INT: + errno = 0; + ival = strtol(val, &eptr, 10); + if ((ival == 0 && errno == EINVAL) || + ((ival == LONG_MAX || ival == LONG_MIN) && + errno == ERANGE)) + return (DLADM_STATUS_BADARG); + bcopy(&ival, buf, sizeof (int64_t)); + *sizep = sizeof (int64_t); + break; + case OVERLAY_PROP_T_UINT: + errno = 0; + uval = strtol(val, &eptr, 10); + if ((uval == 0 && errno == EINVAL) || + (uval == ULONG_MAX && errno == ERANGE)) + return (DLADM_STATUS_BADARG); + bcopy(&uval, buf, sizeof (uint64_t)); + *sizep = sizeof (uint64_t); + break; + case OVERLAY_PROP_T_STRING: + ret = strlcpy((char *)buf, val, OVERLAY_PROP_SIZEMAX); + if (ret >= OVERLAY_PROP_SIZEMAX) + return (DLADM_STATUS_BADARG); + *sizep = ret + 1; + break; + case OVERLAY_PROP_T_IP: + /* + * Always try to parse the IP as an IPv6 address. If that fails, + * try to interpret it as an IPv4 address and transform it into + * an IPv6 mapped IPv4 address. + */ + if (inet_pton(AF_INET6, val, &ipv6) != 1) { + if (inet_pton(AF_INET, val, &ip) != 1) + return (DLADM_STATUS_BADARG); + + IN6_INADDR_TO_V4MAPPED(&ip, &ipv6); + } + bcopy(&ipv6, buf, sizeof (struct in6_addr)); + *sizep = sizeof (struct in6_addr); + break; + default: + abort(); + } + + return (DLADM_STATUS_OK); +} + +/* ARGSUSED */ +static dladm_status_t +dladm_overlay_varpd_setprop(dladm_handle_t handle, varpd_client_handle_t *chdl, + uint64_t inst, const char *name, char *const *valp, uint_t cnt) +{ + int ret; + uint32_t size; + uint8_t buf[LIBVARPD_PROP_SIZEMAX]; + varpd_client_prop_handle_t *phdl; + uint_t type; + dladm_status_t status; + + if ((ret = libvarpd_c_prop_handle_alloc(chdl, inst, &phdl)) != 0) + return (dladm_errno2status(ret)); + + if ((ret = libvarpd_c_prop_info_fill_by_name(phdl, name)) != 0) { + libvarpd_c_prop_handle_free(phdl); + return (dladm_errno2status(ret)); + } + + if ((ret = libvarpd_c_prop_info(phdl, NULL, &type, NULL, NULL, NULL, + NULL)) != 0) { + libvarpd_c_prop_handle_free(phdl); + return (dladm_errno2status(ret)); + } + + if ((status = dladm_overlay_parse_prop(type, buf, &size, valp[0])) != + DLADM_STATUS_OK) { + libvarpd_c_prop_handle_free(phdl); + return (status); + } + + ret = libvarpd_c_prop_set(phdl, buf, size); + libvarpd_c_prop_handle_free(phdl); + + return (dladm_errno2status(ret)); +} + +dladm_status_t +dladm_overlay_setprop(dladm_handle_t handle, datalink_id_t linkid, + const char *name, char *const *valp, uint_t cnt) +{ + int ret; + dladm_status_t status; + overlay_ioc_propinfo_t info; + overlay_ioc_prop_t prop; + + if (linkid == DATALINK_INVALID_LINKID || + name == NULL || valp == NULL || cnt != 1) + return (DLADM_STATUS_BADARG); + + bzero(&info, sizeof (overlay_ioc_propinfo_t)); + info.oipi_linkid = linkid; + info.oipi_id = -1; + if (strlcpy(info.oipi_name, name, OVERLAY_PROP_NAMELEN) >= + OVERLAY_PROP_NAMELEN) + return (DLADM_STATUS_BADARG); + + status = DLADM_STATUS_OK; + ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &info); + if (ret != 0) + status = dladm_errno2status(errno); + + if (status != DLADM_STATUS_OK) + return (status); + + prop.oip_linkid = linkid; + prop.oip_id = info.oipi_id; + prop.oip_name[0] = '\0'; + if ((ret = dladm_overlay_parse_prop(info.oipi_type, prop.oip_value, + &prop.oip_size, valp[0])) != DLADM_STATUS_OK) + return (ret); + + status = DLADM_STATUS_OK; + ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_SETPROP, &prop); + if (ret != 0) + status = dladm_errno2status(errno); + + return (ret); +} + +/* + * Tell the user about any unset required properties. + */ +static int +dladm_overlay_activate_cb(dladm_handle_t handle, datalink_id_t linkid, + dladm_overlay_propinfo_handle_t phdl, void *arg) +{ + dladm_status_t status; + uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX]; + uint_t prot; + size_t size = sizeof (buf); + const char *name; + dladm_errlist_t *errs = arg; + + if ((status = dladm_overlay_prop_info(phdl, &name, NULL, &prot, NULL, + NULL, NULL)) != DLADM_STATUS_OK) + return (status); + + if ((prot & OVERLAY_PROP_PERM_REQ) == 0) + return (DLADM_WALK_CONTINUE); + + if (dladm_overlay_get_prop(handle, linkid, phdl, buf, &size) != + DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + if (size == 0) + (void) dladm_errlist_append(errs, "unset required property: %s", + name); + + return (DLADM_WALK_CONTINUE); +} + +/* + * We need to clean up the world here. The problem is that we may or may not + * actually have everything created. While in the normal case, we'd always have + * an overlay device, assigned datalink id, and a varpd instance, we might not + * have any of those, except for the datalink instance. Therefore, as long as + * the id refers to a valid overlay, we should try to clean up as much of the + * state as possible and most importantly, we need to make sure we delete the + * datalink id. If we fail to do that, then that name will become lost to time. + */ +dladm_status_t +dladm_overlay_delete(dladm_handle_t handle, datalink_id_t linkid) +{ + datalink_class_t class; + overlay_ioc_delete_t oid; + varpd_client_handle_t *chdl; + int ret; + uint32_t flags; + uint64_t varpdid; + + if (dladm_datalink_id2info(handle, linkid, &flags, &class, NULL, + NULL, 0) != DLADM_STATUS_OK) + return (DLADM_STATUS_BADARG); + + if (class != DATALINK_CLASS_OVERLAY) + return (DLADM_STATUS_BADARG); + + oid.oid_linkid = linkid; + ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_DELETE, &oid); + if (ret != 0 && errno != ENOENT) { + return (dladm_errno2status(errno)); + } + + if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) { + return (dladm_errno2status(ret)); + } + + if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { + if (ret == ENOENT) { + goto finish; + } + (void) libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + + ret = libvarpd_c_instance_destroy(chdl, varpdid); +finish: + (void) libvarpd_c_destroy(chdl); + (void) dladm_destroy_datalink_id(handle, linkid, flags); + + return (dladm_errno2status(ret)); +} + +dladm_status_t +dladm_overlay_get_prop(dladm_handle_t handle, datalink_id_t linkid, + dladm_overlay_propinfo_handle_t infohdl, void *buf, size_t *sizep) +{ + int ret; + overlay_ioc_prop_t oip; + dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)infohdl; + + /* + * It'd be nice if we had a better or more specific error for this. If + * this kind of error becomes common place, let's get a better dladm + * error. + */ + if (*sizep < DLADM_OVERLAY_PROP_SIZEMAX) + return (dladm_errno2status(ERANGE)); + + if (infop->dop_isvarpd == B_FALSE) { + bzero(&oip, sizeof (overlay_ioc_prop_t)); + oip.oip_linkid = linkid; + oip.oip_id = infop->dop_un.dop_overlay->oipi_id; + ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_GETPROP, &oip); + if (ret != 0) + return (dladm_errno2status(errno)); + bcopy(oip.oip_value, buf, DLADM_OVERLAY_PROP_SIZEMAX); + *sizep = oip.oip_size; + } else { + uint32_t size = *sizep; + + ret = libvarpd_c_prop_get(infop->dop_un.dop_varpd, buf, &size); + if (ret != 0) + return (dladm_errno2status(errno)); + *sizep = size; + } + + return (DLADM_STATUS_OK); +} + +static dladm_status_t +dladm_overlay_walk_varpd_prop(dladm_handle_t handle, datalink_id_t linkid, + uint64_t varpdid, dladm_overlay_prop_f func, void *arg) +{ + int ret, i; + varpd_client_handle_t *chdl; + varpd_client_prop_handle_t *phdl; + uint_t nprops; + dladm_status_t status; + + if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) + return (dladm_errno2status(ret)); + + if ((ret = libvarpd_c_prop_handle_alloc(chdl, varpdid, &phdl)) != 0) { + (void) libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + + if ((ret = libvarpd_c_prop_nprops(chdl, varpdid, &nprops)) != 0) { + libvarpd_c_prop_handle_free(phdl); + (void) libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + + status = DLADM_STATUS_OK; + for (i = 0; i < nprops; i++) { + dladm_overlay_propinfo_t dop; + + bzero(&dop, sizeof (dop)); + dop.dop_isvarpd = B_TRUE; + dop.dop_un.dop_varpd = phdl; + + if ((ret = libvarpd_c_prop_info_fill(phdl, i)) != 0) { + status = dladm_errno2status(ret); + break; + } + + ret = func(handle, linkid, + (dladm_overlay_propinfo_handle_t)&dop, arg); + if (ret == DLADM_WALK_TERMINATE) + break; + } + + libvarpd_c_prop_handle_free(phdl); + libvarpd_c_destroy(chdl); + + return (status); +} + +dladm_status_t +dladm_overlay_walk_prop(dladm_handle_t handle, datalink_id_t linkid, + dladm_overlay_prop_f func, void *arg, dladm_errlist_t *errs) +{ + int i, ret; + datalink_class_t class; + overlay_ioc_nprops_t oin; + overlay_ioc_propinfo_t oipi; + dladm_overlay_propinfo_t dop; + uint64_t varpdid = UINT64_MAX; + + if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, + NULL, 0) != DLADM_STATUS_OK) + return (DLADM_STATUS_BADARG); + + if (class != DATALINK_CLASS_OVERLAY) + return (DLADM_STATUS_BADARG); + + bzero(&oin, sizeof (overlay_ioc_nprops_t)); + oin.oipn_linkid = linkid; + ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_NPROPS, &oin); + if (ret != 0) + return (dladm_errno2status(errno)); + + for (i = 0; i < oin.oipn_nprops; i++) { + bzero(&dop, sizeof (dladm_overlay_propinfo_t)); + bzero(&oipi, sizeof (overlay_ioc_propinfo_t)); + oipi.oipi_linkid = linkid; + oipi.oipi_id = i; + ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &oipi); + if (ret != 0) { + (void) dladm_errlist_append(errs, "failed to get " + "propinfo for property %d: %s", i, strerror(errno)); + return (dladm_errno2status(errno)); + } + + dop.dop_isvarpd = B_FALSE; + dop.dop_un.dop_overlay = &oipi; + ret = func(handle, linkid, + (dladm_overlay_propinfo_handle_t)&dop, arg); + if (ret == DLADM_WALK_TERMINATE) + break; + + if (strcmp(oipi.oipi_name, VARPD_PROPERTY_NAME) == 0) { + uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX]; + size_t bufsize = sizeof (buf); + uint64_t *vp; + + if (dladm_overlay_get_prop(handle, linkid, + (dladm_overlay_propinfo_handle_t)&dop, buf, + &bufsize) != DLADM_STATUS_OK) + continue; + + /* LINTED: E_BAD_PTR_CAST_ALIGN */ + vp = (uint64_t *)buf; + varpdid = *vp; + } + } + + /* Should this really be possible? */ + if (varpdid == UINT64_MAX) + return (DLADM_STATUS_OK); + + return (dladm_overlay_walk_varpd_prop(handle, linkid, varpdid, func, + arg)); +} + +dladm_status_t +dladm_overlay_create(dladm_handle_t handle, const char *name, + const char *encap, const char *search, uint64_t vid, + dladm_arg_list_t *props, dladm_errlist_t *errs, uint32_t flags) +{ + int ret, i; + dladm_status_t status; + datalink_id_t linkid; + overlay_ioc_create_t oic; + overlay_ioc_activate_t oia; + size_t slen; + varpd_client_handle_t *vch; + uint64_t id; + + status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_OVERLAY, + DL_ETHER, flags, &linkid); + if (status != DLADM_STATUS_OK) + return (status); + + bzero(&oic, sizeof (oic)); + oic.oic_linkid = linkid; + oic.oic_vnetid = vid; + (void) strlcpy(oic.oic_encap, encap, MAXLINKNAMELEN); + + status = DLADM_STATUS_OK; + ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_CREATE, &oic); + if (ret != 0) { + /* + * It'd be nice if we had private errors so we could better + * distinguish between different classes of errors. + */ + status = dladm_errno2status(errno); + } + + if (status != DLADM_STATUS_OK) { + (void) dladm_destroy_datalink_id(handle, linkid, flags); + return (status); + } + + slen = strlen(search); + for (i = 0; props != NULL && i < props->al_count; i++) { + dladm_arg_info_t *aip = &props->al_info[i]; + + /* + * If it's a property for the search plugin, eg. it has the + * prefix '<search>/', then we don't set the property on the + * overlay device and instead set it on the varpd instance. + */ + if (strncmp(aip->ai_name, search, slen) == 0 && + aip->ai_name[slen] == '/') + continue; + status = dladm_overlay_setprop(handle, linkid, aip->ai_name, + aip->ai_val, aip->ai_count); + if (status != DLADM_STATUS_OK) { + (void) dladm_errlist_append(errs, + "failed to set property %s", + aip->ai_name); + (void) dladm_overlay_delete(handle, linkid); + return (status); + } + } + + if ((ret = libvarpd_c_create(&vch, dladm_overlay_doorpath)) != 0) { + (void) dladm_errlist_append(errs, + "failed to create libvarpd handle: %s", strerror(ret)); + (void) dladm_overlay_delete(handle, linkid); + return (dladm_errno2status(ret)); + } + + if ((ret = libvarpd_c_instance_create(vch, linkid, search, + &id)) != 0) { + (void) dladm_errlist_append(errs, + "failed to create varpd instance: %s", strerror(ret)); + libvarpd_c_destroy(vch); + (void) dladm_overlay_delete(handle, linkid); + return (dladm_errno2status(ret)); + } + + for (i = 0; props != NULL && i < props->al_count; i++) { + dladm_arg_info_t *aip = &props->al_info[i]; + + /* + * Skip arguments we've processed already. + */ + if (strncmp(aip->ai_name, search, slen) != 0) + continue; + + if (aip->ai_name[slen] != '/') + continue; + + ret = dladm_overlay_varpd_setprop(handle, vch, id, aip->ai_name, + aip->ai_val, aip->ai_count); + if (ret != 0) { + (void) dladm_errlist_append(errs, + "failed to set varpd prop: %s\n", + aip->ai_name); + (void) libvarpd_c_instance_destroy(vch, id); + libvarpd_c_destroy(vch); + (void) dladm_overlay_delete(handle, linkid); + return (dladm_errno2status(ret)); + } + } + + if ((ret = libvarpd_c_instance_activate(vch, id)) != 0) { + (void) dladm_errlist_append(errs, + "failed to activate varpd instance: %s", strerror(ret)); + (void) dladm_overlay_walk_varpd_prop(handle, linkid, id, + dladm_overlay_activate_cb, errs); + (void) libvarpd_c_instance_destroy(vch, id); + libvarpd_c_destroy(vch); + (void) dladm_overlay_delete(handle, linkid); + return (dladm_errno2status(ret)); + + } + + bzero(&oia, sizeof (oia)); + oia.oia_linkid = linkid; + status = DLADM_STATUS_OK; + ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_ACTIVATE, &oia); + if (ret != 0) { + ret = errno; + (void) dladm_errlist_append(errs, "failed to activate " + "device: %s", strerror(ret)); + (void) libvarpd_c_instance_destroy(vch, id); + (void) dladm_overlay_walk_prop(handle, linkid, + dladm_overlay_activate_cb, errs, errs); + status = dladm_errno2status(ret); + (void) libvarpd_c_instance_destroy(vch, id); + } + + libvarpd_c_destroy(vch); + if (status != DLADM_STATUS_OK) + (void) dladm_overlay_delete(handle, linkid); + + return (status); +} + + + +typedef struct overlay_walk_cb { + dladm_handle_t owc_handle; + datalink_id_t owc_linkid; + void *owc_arg; + dladm_overlay_cache_f owc_func; + uint_t owc_mode; + uint_t owc_dest; +} overlay_walk_cb_t; + +/* ARGSUSED */ +static int +dladm_overlay_walk_cache_cb(varpd_client_handle_t *chdl, uint64_t varpdid, + const struct ether_addr *key, const varpd_client_cache_entry_t *entry, + void *arg) +{ + overlay_walk_cb_t *owc = arg; + dladm_overlay_point_t point; + + bzero(&point, sizeof (dladm_overlay_point_t)); + point.dop_dest = owc->owc_dest; + point.dop_mac = entry->vcp_mac; + point.dop_flags = entry->vcp_flags; + point.dop_ip = entry->vcp_ip; + point.dop_port = entry->vcp_port; + + if (owc->owc_mode == OVERLAY_TARGET_POINT) + point.dop_flags |= DLADM_OVERLAY_F_DEFAULT; + + if (owc->owc_func(owc->owc_handle, owc->owc_linkid, key, &point, + owc->owc_arg) == DLADM_WALK_TERMINATE) + return (1); + return (0); +} + +dladm_status_t +dladm_overlay_walk_cache(dladm_handle_t handle, datalink_id_t linkid, + dladm_overlay_cache_f func, void *arg) +{ + int ret; + uint_t mode, dest; + uint64_t varpdid; + varpd_client_handle_t *chdl; + overlay_walk_cb_t cbarg; + + if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) + return (dladm_errno2status(ret)); + + if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + + if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid, + &dest, &mode)) != 0) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + + cbarg.owc_handle = handle; + cbarg.owc_linkid = linkid; + cbarg.owc_arg = arg; + cbarg.owc_func = func; + cbarg.owc_dest = dest; + cbarg.owc_mode = mode; + ret = libvarpd_c_instance_cache_walk(chdl, varpdid, + dladm_overlay_walk_cache_cb, &cbarg); + libvarpd_c_destroy(chdl); + + return (dladm_errno2status(ret)); +} + +/* ARGSUSED */ +dladm_status_t +dladm_overlay_cache_flush(dladm_handle_t handle, datalink_id_t linkid) +{ + int ret; + uint64_t varpdid; + varpd_client_handle_t *chdl; + + if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) + return (dladm_errno2status(ret)); + + if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + + ret = libvarpd_c_instance_cache_flush(chdl, varpdid); + libvarpd_c_destroy(chdl); + + return (dladm_errno2status(ret)); +} + +/* ARGSUSED */ +dladm_status_t +dladm_overlay_cache_delete(dladm_handle_t handle, datalink_id_t linkid, + const struct ether_addr *key) +{ + int ret; + uint64_t varpdid; + varpd_client_handle_t *chdl; + + if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) + return (dladm_errno2status(ret)); + + if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + + ret = libvarpd_c_instance_cache_delete(chdl, varpdid, key); + libvarpd_c_destroy(chdl); + + return (dladm_errno2status(ret)); +} + +/* ARGSUSED */ +dladm_status_t +dladm_overlay_cache_set(dladm_handle_t handle, datalink_id_t linkid, + const struct ether_addr *key, char *val) +{ + int ret; + uint_t dest; + uint64_t varpdid; + char *ip, *port = NULL; + varpd_client_handle_t *chdl; + varpd_client_cache_entry_t vcp; + + + if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) + return (dladm_errno2status(ret)); + + if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + + if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid, + &dest, NULL)) != 0) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + + /* + * Mode tells us what we should expect in val. It we have more than one + * thing listed, the canonical format of it right now is mac,ip:port. + */ + bzero(&vcp, sizeof (varpd_client_cache_entry_t)); + + if (strcasecmp(val, "drop") == 0) { + vcp.vcp_flags = OVERLAY_TARGET_CACHE_DROP; + goto send; + } + + if (dest & OVERLAY_PLUGIN_D_ETHERNET) { + if (ether_aton_r(val, &vcp.vcp_mac) == NULL) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(EINVAL)); + } + } + + if (dest & OVERLAY_PLUGIN_D_IP) { + if (dest & OVERLAY_PLUGIN_D_ETHERNET) { + if ((ip = strchr(val, ',')) == NULL) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + ip++; + } else { + ip = val; + } + + if (dest & OVERLAY_PLUGIN_D_PORT) { + if ((port = strchr(val, ':')) == NULL) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + *port = '\0'; + port++; + } + + /* Try v6, then fall back to v4 */ + ret = inet_pton(AF_INET6, ip, &vcp.vcp_ip); + if (ret == -1) + abort(); + if (ret == 0) { + struct in_addr v4; + + ret = inet_pton(AF_INET, ip, &v4); + if (ret == -1) + abort(); + if (ret == 0) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + IN6_INADDR_TO_V4MAPPED(&v4, &vcp.vcp_ip); + } + } + + if (dest & OVERLAY_PLUGIN_D_PORT) { + char *eptr; + unsigned long l; + if (port == NULL && (dest & OVERLAY_PLUGIN_D_ETHERNET)) { + if ((port = strchr(val, ',')) == NULL) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(EINVAL)); + } + } else if (port == NULL) + port = val; + + errno = 0; + l = strtoul(port, &eptr, 10); + if (errno != 0 || *eptr != '\0') { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(EINVAL)); + } + if (l == 0 || l > UINT16_MAX) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(EINVAL)); + } + vcp.vcp_port = l; + } + +send: + ret = libvarpd_c_instance_cache_set(chdl, varpdid, key, &vcp); + + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); +} + +/* ARGSUSED */ +dladm_status_t +dladm_overlay_cache_get(dladm_handle_t handle, datalink_id_t linkid, + const struct ether_addr *key, dladm_overlay_point_t *point) +{ + int ret; + uint_t dest, mode; + uint64_t varpdid; + varpd_client_handle_t *chdl; + varpd_client_cache_entry_t entry; + + if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) + return (dladm_errno2status(ret)); + + if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + + if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid, + &dest, &mode)) != 0) { + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); + } + + ret = libvarpd_c_instance_cache_get(chdl, varpdid, key, &entry); + if (ret == 0) { + point->dop_dest = dest; + point->dop_mac = entry.vcp_mac; + point->dop_flags = entry.vcp_flags; + point->dop_ip = entry.vcp_ip; + point->dop_port = entry.vcp_port; + if (mode == OVERLAY_TARGET_POINT) + point->dop_flags |= DLADM_OVERLAY_F_DEFAULT; + } + + libvarpd_c_destroy(chdl); + return (dladm_errno2status(ret)); +} + +dladm_status_t +dladm_overlay_status(dladm_handle_t handle, datalink_id_t linkid, + dladm_overlay_status_f func, void *arg) +{ + int ret; + dladm_status_t status; + overlay_ioc_status_t ois; + dladm_overlay_status_t dos; + + ois.ois_linkid = linkid; + status = DLADM_STATUS_OK; + ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_STATUS, &ois); + if (ret != 0) + status = dladm_errno2status(errno); + if (status != DLADM_STATUS_OK) + return (status); + + dos.dos_degraded = ois.ois_status == OVERLAY_I_DEGRADED ? B_TRUE : + B_FALSE; + (void) strlcpy(dos.dos_fmamsg, ois.ois_message, + sizeof (dos.dos_fmamsg)); + func(handle, linkid, &dos, arg); + return (DLADM_STATUS_OK); +} diff --git a/usr/src/lib/libdladm/common/libdloverlay.h b/usr/src/lib/libdladm/common/libdloverlay.h new file mode 100644 index 0000000000..39b01ccae3 --- /dev/null +++ b/usr/src/lib/libdladm/common/libdloverlay.h @@ -0,0 +1,107 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2015 Joyent, Inc. + */ + +#ifndef _LIBDLOVERLAY_H +#define _LIBDLOVERLAY_H + +/* + * libdladm Overlay device routines + */ + +#include <libdladm.h> +#include <libdladm_impl.h> +#include <sys/overlay.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define DLADM_OVERLAY_F_DROP 0x0001 +#define DLADM_OVERLAY_F_DEFAULT 0xf000 + +typedef struct dladm_overlay_point { + uint_t dop_dest; + struct ether_addr dop_mac; + uint16_t dop_flags; + struct in6_addr dop_ip; + uint16_t dop_port; +} dladm_overlay_point_t; + +typedef struct dladm_overlay_status { + boolean_t dos_degraded; + char dos_fmamsg[256]; +} dladm_overlay_status_t; + +extern dladm_status_t dladm_overlay_create(dladm_handle_t, const char *, + const char *, const char *, uint64_t, dladm_arg_list_t *, dladm_errlist_t *, + uint32_t); +extern dladm_status_t dladm_overlay_delete(dladm_handle_t, datalink_id_t); + +typedef void (*dladm_overlay_status_f)(dladm_handle_t, datalink_id_t, + dladm_overlay_status_t *, void *); +extern dladm_status_t dladm_overlay_status(dladm_handle_t, datalink_id_t, + dladm_overlay_status_f, void *); + +extern dladm_status_t dladm_overlay_cache_flush(dladm_handle_t, datalink_id_t); +extern dladm_status_t dladm_overlay_cache_delete(dladm_handle_t, datalink_id_t, + const struct ether_addr *); +extern dladm_status_t dladm_overlay_cache_set(dladm_handle_t, datalink_id_t, + const struct ether_addr *, char *); +extern dladm_status_t dladm_overlay_cache_get(dladm_handle_t, datalink_id_t, + const struct ether_addr *, dladm_overlay_point_t *); + +#define DLADM_OVERLAY_PROP_SIZEMAX 256 +#define DLADM_OVERLAY_PROP_NAMELEN 32 + +typedef struct __dladm_overlay_propinfo *dladm_overlay_propinfo_handle_t; + +extern dladm_status_t dladm_overlay_prop_info(dladm_overlay_propinfo_handle_t, + const char **, uint_t *, uint_t *, const void **, uint32_t *, + const mac_propval_range_t **); +extern dladm_status_t dladm_overlay_get_prop(dladm_handle_t, datalink_id_t, + dladm_overlay_propinfo_handle_t, void *buf, size_t *bufsize); + +typedef int (*dladm_overlay_prop_f)(dladm_handle_t, datalink_id_t, + dladm_overlay_propinfo_handle_t, void *); +extern dladm_status_t dladm_overlay_walk_prop(dladm_handle_t, datalink_id_t, + dladm_overlay_prop_f, void *arg, dladm_errlist_t *); + +typedef int (*dladm_overlay_cache_f)(dladm_handle_t, datalink_id_t, + const struct ether_addr *, const dladm_overlay_point_t *, void *); +extern dladm_status_t dladm_overlay_walk_cache(dladm_handle_t, datalink_id_t, + dladm_overlay_cache_f, void *); + +/* + * Some day we'll want to support being able to set properties after creation. + * If we do, the following strawman API might serve us well. + * + * extern dladm_status_t dladm_overlay_prop_lookup(dladm_handle_t, + * datalink_id_t, const char *, dladm_overlay_propinfo_handle_t *); + * extern void dladm_overlay_prop_handle_free(dladm_handle_t, datalink_id_t, + * dladm_overlay_propinfo_handle_t *); + * extern dladm_status_t dladm_overlay_set_prop(dladm_handle_t, datalink_id_t, + * dladm_propinfo_handle_t, void *buf, size_t *bufsize); + * extern dladm_status_t dladm_overlay_str_to_buf(dladm_handle_t, datalink_id_t, + * dladm_overlay_propinfo_handle_t *, const char *, void *, size_t *); + * extern dladm_status_t dladm_overlay_buf_to_str(dladm_handle_t, datalink_id_t, + * dladm_overlay_propinfo_handle_t *, const void *, const size_t, char *, + * size_t *); + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBDLOVERLAY_H */ diff --git a/usr/src/lib/libdladm/common/libdlvlan.c b/usr/src/lib/libdladm/common/libdlvlan.c index 943728dc03..34c1e6682d 100644 --- a/usr/src/lib/libdladm/common/libdlvlan.c +++ b/usr/src/lib/libdladm/common/libdlvlan.c @@ -64,7 +64,7 @@ dladm_vlan_create(dladm_handle_t handle, const char *vlan, datalink_id_t linkid, { return (dladm_vnic_create(handle, vlan, linkid, VNIC_MAC_ADDR_TYPE_PRIMARY, NULL, 0, NULL, 0, vid, VRRP_VRID_NONE, - AF_UNSPEC, vlan_id_out, proplist, flags | DLADM_OPT_VLAN)); + AF_UNSPEC, vlan_id_out, proplist, NULL, flags | DLADM_OPT_VLAN)); } /* diff --git a/usr/src/lib/libdladm/common/libdlvnic.c b/usr/src/lib/libdladm/common/libdlvnic.c index 44f8bb2726..189b848f8e 100644 --- a/usr/src/lib/libdladm/common/libdlvnic.c +++ b/usr/src/lib/libdladm/common/libdlvnic.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2015, Joyent Inc. */ #include <stdio.h> @@ -399,7 +400,7 @@ dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid, vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, uint_t mac_len, int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid, int af, datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist, - uint32_t flags) + dladm_errlist_t *errs, uint32_t flags) { dladm_vnic_attr_t attr; datalink_id_t vnic_id; @@ -539,27 +540,41 @@ dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid, vnic_created = B_TRUE; /* Save vnic configuration and its properties */ - if (!(flags & DLADM_OPT_PERSIST)) - goto done; + if (flags & DLADM_OPT_PERSIST) { + status = dladm_vnic_persist_conf(handle, name, &attr, class); + if (status == DLADM_STATUS_OK) + conf_set = B_TRUE; + } - status = dladm_vnic_persist_conf(handle, name, &attr, class); - if (status != DLADM_STATUS_OK) - goto done; - conf_set = B_TRUE; +done: + if (status == DLADM_STATUS_OK && proplist != NULL) { + uint32_t flg; + + flg = (flags & DLADM_OPT_PERSIST) ? + DLADM_OPT_PERSIST : DLADM_OPT_ACTIVE; - if (proplist != NULL) { for (i = 0; i < proplist->al_count; i++) { dladm_arg_info_t *aip = &proplist->al_info[i]; + if (strcmp(aip->ai_name, "zone") == 0 && + flags & DLADM_OPT_TRANSIENT) + flg |= DLADM_OPT_TRANSIENT; + else + flg &= ~DLADM_OPT_TRANSIENT; + status = dladm_set_linkprop(handle, vnic_id, - aip->ai_name, aip->ai_val, aip->ai_count, - DLADM_OPT_PERSIST); - if (status != DLADM_STATUS_OK) + aip->ai_name, aip->ai_val, aip->ai_count, flg); + if (status != DLADM_STATUS_OK) { + char errmsg[DLADM_STRSIZE]; + (void) dladm_errlist_append(errs, + "failed to set property %s: %s", + aip->ai_name, + dladm_status2str(status, errmsg)); break; + } } } -done: if (status != DLADM_STATUS_OK) { if (conf_set) (void) dladm_remove_conf(handle, vnic_id); diff --git a/usr/src/lib/libdladm/common/libdlvnic.h b/usr/src/lib/libdladm/common/libdlvnic.h index 94b656aadf..839b2de9f2 100644 --- a/usr/src/lib/libdladm/common/libdlvnic.h +++ b/usr/src/lib/libdladm/common/libdlvnic.h @@ -55,7 +55,8 @@ typedef struct dladm_vnic_attr { extern dladm_status_t dladm_vnic_create(dladm_handle_t, const char *, datalink_id_t, vnic_mac_addr_type_t, uchar_t *, uint_t, int *, uint_t, uint16_t, vrid_t, int, - datalink_id_t *, dladm_arg_list_t *, uint32_t); + datalink_id_t *, dladm_arg_list_t *, + dladm_errlist_t *, uint32_t); extern dladm_status_t dladm_vnic_delete(dladm_handle_t, datalink_id_t, uint32_t); diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c index c3eea9a7f1..8d43e2d6b9 100644 --- a/usr/src/lib/libdladm/common/linkprop.c +++ b/usr/src/lib/libdladm/common/linkprop.c @@ -153,11 +153,13 @@ static pd_getf_t get_zone, get_autopush, get_rate_mod, get_rate, get_bridge_pvid, get_protection, get_rxrings, get_txrings, get_cntavail, get_secondary_macs, get_allowedips, get_allowedcids, get_pool, - get_rings_range, get_linkmode_prop; + get_rings_range, get_linkmode_prop, + get_promisc_filtered; static pd_setf_t set_zone, set_rate, set_powermode, set_radio, set_public_prop, set_resource, set_stp_prop, - set_bridge_forward, set_bridge_pvid, set_secondary_macs; + set_bridge_forward, set_bridge_pvid, set_secondary_macs, + set_promisc_filtered; static pd_checkf_t check_zone, check_autopush, check_rate, check_hoplimit, check_encaplim, check_uint32, check_maxbw, check_cpus, @@ -365,6 +367,8 @@ static link_attr_t link_attr[] = { { MAC_PROP_IB_LINKMODE, sizeof (uint32_t), "linkmode"}, + { MAC_PROP_VN_PROMISC_FILTERED, sizeof (boolean_t), "promisc-filtered"}, + { MAC_PROP_SECONDARY_ADDRS, sizeof (mac_secondary_addr_t), "secondary-macs"}, @@ -422,6 +426,11 @@ static val_desc_t link_protect_vals[] = { { "dhcp-nospoof", MPT_DHCPNOSPOOF }, }; +static val_desc_t link_promisc_filtered_vals[] = { + { "off", B_FALSE }, + { "on", B_TRUE }, +}; + static val_desc_t dladm_wlan_radio_vals[] = { { "on", DLADM_WLAN_RADIO_ON }, { "off", DLADM_WLAN_RADIO_OFF } @@ -698,6 +707,12 @@ static prop_desc_t prop_table[] = { set_resource, NULL, get_protection, check_prop, 0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, + { "promisc-filtered", { "on", 1 }, + link_promisc_filtered_vals, VALCNT(link_promisc_filtered_vals), + set_promisc_filtered, NULL, get_promisc_filtered, check_prop, 0, + DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE }, + + { "allowed-ips", { "--", 0 }, NULL, 0, set_resource, NULL, get_allowedips, check_allowedips, PD_CHECK_ALLOC, @@ -1529,6 +1544,9 @@ set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, if (zid_new == zid_old) return (DLADM_STATUS_OK); + if (flags & DLADM_OPT_TRANSIENT) + dzp->diz_transient = B_TRUE; + if ((status = set_public_prop(handle, pdp, linkid, vdp, val_cnt, flags, media)) != DLADM_STATUS_OK) return (status); @@ -4770,3 +4788,50 @@ get_linkmode_prop(dladm_handle_t handle, prop_desc_t *pdp, *val_cnt = 1; return (DLADM_STATUS_OK); } + +/*ARGSUSED*/ +static dladm_status_t +get_promisc_filtered(dladm_handle_t handle, prop_desc_t *pdp, + datalink_id_t linkid, char **prop_val, uint_t *val_cnt, + datalink_media_t media, uint_t flags, uint_t *perm_flags) +{ + char *s; + dladm_status_t status; + boolean_t filt; + + status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, + perm_flags, &filt, sizeof (filt)); + if (status != DLADM_STATUS_OK) + return (status); + + if (filt != 0) + s = link_promisc_filtered_vals[1].vd_name; + else + s = link_promisc_filtered_vals[0].vd_name; + (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", s); + + *val_cnt = 1; + return (DLADM_STATUS_OK); +} + +/* ARGSUSED */ +static dladm_status_t +set_promisc_filtered(dladm_handle_t handle, prop_desc_t *pdp, + datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags, + datalink_media_t media) +{ + dld_ioc_macprop_t *dip; + dladm_status_t status = DLADM_STATUS_OK; + + dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, + 0, &status); + + if (dip == NULL) + return (status); + + (void) memcpy(dip->pr_val, &vdp->vd_val, dip->pr_valsize); + status = i_dladm_macprop(handle, dip, B_TRUE); + + free(dip); + return (status); +} diff --git a/usr/src/lib/libdladm/common/llib-ldladm b/usr/src/lib/libdladm/common/llib-ldladm index 8e5eac0614..e5366fb92d 100644 --- a/usr/src/lib/libdladm/common/llib-ldladm +++ b/usr/src/lib/libdladm/common/llib-ldladm @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2015 Joyent, Inc. */ /*LINTLIBRARY*/ @@ -38,3 +39,4 @@ #include <libdlether.h> #include <libdlsim.h> #include <libdlbridge.h> +#include <libdloverlay.h> diff --git a/usr/src/lib/libdladm/common/mapfile-vers b/usr/src/lib/libdladm/common/mapfile-vers index b781c93aff..f2847cab55 100644 --- a/usr/src/lib/libdladm/common/mapfile-vers +++ b/usr/src/lib/libdladm/common/mapfile-vers @@ -20,6 +20,7 @@ # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright 2015 Joyent, Inc. # # @@ -134,6 +135,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { dladm_remap_datalink_id; dladm_up_datalink_id; dladm_name2info; + dladm_zname2info; dladm_datalink_id2info; dladm_walk_datalink_id; dladm_create_conf; @@ -270,6 +272,23 @@ SYMBOL_VERSION SUNWprivate_1.1 { dladm_strs2range; dladm_range2list; dladm_list2range; + + dladm_errlist_init; + dladm_errlist_reset; + dladm_errlist_append; + + dladm_overlay_create; + dladm_overlay_delete; + dladm_overlay_status; + dladm_overlay_prop_info; + dladm_overlay_get_prop; + dladm_overlay_walk_prop; + + dladm_overlay_cache_set; + dladm_overlay_cache_get; + dladm_overlay_cache_delete; + dladm_overlay_cache_flush; + dladm_overlay_walk_cache; local: *; }; |