4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * CDDL HEADER START
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * The contents of this file are subject to the terms of the
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Common Development and Distribution License (the "License").
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * You may not use this file except in compliance with the License.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * or http://www.opensolaris.org/os/licensing.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * See the License for the specific language governing permissions
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * and limitations under the License.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * When distributing Covered Code, include this CDDL HEADER in each
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * If applicable, add the following below this CDDL HEADER, with the
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * fields enclosed by brackets "[]" replaced with your own identifying
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * information: Portions Copyright [yyyy] [name of copyright owner]
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * CDDL HEADER END
327151705b7439cb7ab35c370f682cac7ef9523aCathy Zhou * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * bridged - bridging control daemon. This module handles events and general
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * port-related operations.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaidladm_bridge_prot_t protect = DLADM_BRIDGE_PROT_STP;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * The 'allports' array is an array of pointers to the struct portdata
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * structures. We reallocate 'allports' as needed, but the portdata must
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * remain where it's initially allocated, because libdlpi's notification
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * mechanism has a copy of a pointer to this structure.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai/* Port allocation increment (arbitrary) */
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) dladm_destroy_datalink_id(dlhandle, main_linkid,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if ((control_fd = open(BRIDGE_CTLPATH, O_RDWR | O_NONBLOCK)) == -1) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) snprintf(bnb.bnb_name, sizeof (bnb.bnb_name), "%s0",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai status = dladm_name2info(dlhandle, bnb.bnb_name, &bnb.bnb_linkid, NULL,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) fprintf(stderr, "bridged: %s: %s\n", bnb.bnb_name,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (strioctl(control_fd, BRIOC_NEWBRIDGE, &bnb, sizeof (bnb)) == -1) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (strioctl(control_fd, BRIOC_TABLEMAX, &tablemax,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "cannot set table max %lu on bridge %s: %m",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * This covers for any previous incarnation where we might have crashed
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * or been SIGKILL'd and failed to take down the datalink.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai status = dladm_up_datalink_id(dlhandle, bnb.bnb_linkid);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) fprintf(stderr, "bridged: %s link up: %s\n",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai bnb.bnb_name, dladm_status2str(status, buf));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai for (i = 0; i < nextport; i++) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaiset_vlan(dladm_handle_t handle, datalink_id_t linkid, void *arg)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai status = dladm_vlan_info(handle, linkid, &vinfo, DLADM_OPT_ACTIVE);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_DEBUG, "can't get VLAN info on link ID %u: %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai linkid, dladm_status2str(status, pointless));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (strioctl(control_fd, BRIOC_VLANENAB, &bve, sizeof (bve)) == -1) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "unable to enable VLAN %d on linkid %u: %m",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * If the named port already exists, then update its configuration. If it
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * doesn't, then create and enable it.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaiupdate_port(int vlan_id, const char *portname, datalink_id_t linkid,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai /* If we need to allocate more array space, then do so in chunks. */
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai sizeof (*newarr) * (nextport + ALLOCINCR));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai sizeof (*fds) * (nextport + ALLOCINCR + FDOFFSET));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "unable to add %s; no memory",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai /* If our linkid search ran to the end, then this is a new port. */
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if ((port = calloc(1, sizeof (*port))) == NULL) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "unable to add %s; no memory",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai /* Located port by linkid; we're just updating existing data */
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * If it changed name, then close and reopen so we log under
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * the most current name for this port.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (port->name != NULL && strcmp(portname, port->name) != 0) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * If the port is not yet attached to the bridge in the kernel, then do
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) strlcpy(adddata.linkname, portname,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (strioctl(control_fd, BRIOC_ADDLINK, &adddata,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai sizeof (adddata.linkid) + strlen(adddata.linkname)) == -1) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "cannot bridge %s: %m", portname);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai status = dladm_get_linkprop_values(dlhandle, linkid,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai DLADM_PROP_VAL_PERSISTENT, "forward", &propval, &valcnt);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai status = dladm_get_linkprop_values(dlhandle, linkid,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai DLADM_PROP_VAL_PERSISTENT, "default_tag", &propval, &valcnt);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (strioctl(control_fd, BRIOC_SETPVID, &bsv, sizeof (bsv)) == -1) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "can't set PVID on %s: %m", portname);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (!port_dlpi_open(portname, port, class))
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (strioctl(control_fd, BRIOC_REMLINK, &port->linkid,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "cannot remove from bridge %s: %m",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaiupdate_link(dladm_handle_t handle, datalink_id_t linkid, void *arg)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai char bridge[MAXLINKNAMELEN], linkname[MAXLINKNAMELEN];
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (status == DLADM_STATUS_OK && strcmp(bridge, instance_name) == 0) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai status = dladm_datalink_id2info(handle, linkid, NULL, &class,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "unable to get link info for ID %u: %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai linkid, dladm_status2str(status, pointless));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai "unable to get bridge data for ID %u: %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai linkid, dladm_status2str(status, pointless));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_DEBUG, "link ID %u is on bridge %s, not %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Refresh action - reread configuration properties.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai /* Drain signal events from pipe */
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai status = dladm_bridge_get_privprop(instance_name, &new_debug,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_DEBUG, "changed tablemax from %lu to %lu",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (strioctl(control_fd, BRIOC_TABLEMAX, &new_tablemax,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "%s: unable to refresh bridge properties: %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai instance_name, dladm_status2str(status, buf));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai for (i = 0; i < nextport; i++)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * libdladm doesn't guarantee anything about link ordering in a walk,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * so we do this walk twice: once to pick up the ports, and a second
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * time to get the enabled VLANs on all ports.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) dladm_walk_datalink_id(update_link, dlhandle, NULL,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) dladm_walk_datalink_id(set_vlan, dlhandle, NULL,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * If any ports now show up as unreferenced, then they've been removed
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * from the configuration.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai for (i = 0; i < nextport; i++) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai &pdp->linkid, sizeof (pdp->linkid)) == -1)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai "%u from bridge %s: %m",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Handle messages on the common control stream. This currently just deals
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * with port SDU mismatches.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai retv = read(control_fd, &bc, sizeof (bc));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if ((port = find_by_linkid(bc.bc_linkid)) == NULL)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (!port->phys_status || !port->admin_status ||
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai bss.bss_state = !port->sdu_failed && !port->bpdu_protect ?
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (strioctl(control_fd, BRIOC_SETSTATE, &bss,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "cannot set STP state on %s: %m",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if ((rc = STP_IN_enable_port(port->port_index, !bc.bc_failed)) != 0)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "STP can't %s port %s for SDU failure: %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai port->name, bc.bc_failed ? "disable" : "enable",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai uint16_t buffer[ETHERMAX / sizeof (uint16_t)];
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai rc = dlpi_recv(port->dlpi, NULL, NULL, buffer, &buflen, 1, NULL);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "receive failure on %s: %s", port->name,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * If we're administratively disabled, then don't deliver packets to
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * the STP state machine. It will re-enable the port because it uses
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * the same variable for both link status and administrative state.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (!port->admin_status || protect != DLADM_BRIDGE_PROT_STP) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai "discard BPDU on non-forwarding interface %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * There's a mismatch between the librstp and libdlpi expectations on
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * receive. librstp wants the packet to start with the 802 length
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * field, not the destination address.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai rc = STP_IN_check_bpdu_header((BPDU_T *)&eh->ether_type, buflen);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Note that we attempt to avoid calling the relatively expensive
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * _link_ntoa function unless we're going to use the result. In normal
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * usage, we don't need this string.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (port->admin_non_stp && !port->bpdu_protect) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) _link_ntoa(eh->ether_shost.ether_addr_octet,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_WARNING, "unexpected BPDU on %s from %s; "
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai "forwarding disabled", port->name, sender);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (strioctl(control_fd, BRIOC_SETSTATE, &bss,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "cannot set STP state on "
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) _link_ntoa(eh->ether_shost.ether_addr_octet,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_DEBUG, "got BPDU from %s on %s; %d bytes",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai rc = STP_IN_rx_bpdu(port->vlan_id, port->port_index,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) _link_ntoa(eh->ether_shost.ether_addr_octet, sender,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai "discarded malformed packet on %s from %s: %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai port->name, sender, STP_IN_get_error_explanation(rc));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai status = dladm_get_single_mac_stat(dlhandle, port->linkid, "ifspeed",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (status == DLADM_STATUS_OK && ifspeed != 0)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (strioctl(control_fd, BRIOC_SETSTATE, &bss, sizeof (bss)) == -1)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai syslog(LOG_ERR, "cannot set STP state on %s: %m", port->name);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai /* Bootstrap configuration */
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai tout = 1000 - (now - last_time) / 1000000ll;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) poll(fdarray, nextport + FDOFFSET, tout);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai for (i = 0; i < nextport; i++) {