Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/net Add support for building Ethernet bridges, based on ...



details:   https://anonhg.NetBSD.org/src/rev/df3a30e952ef
branches:  trunk
changeset: 513924:df3a30e952ef
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Fri Aug 17 21:37:27 2001 +0000

description:
Add support for building Ethernet bridges, based on Jason Wright's
bridge driver from OpenBSD, although the bridge code has been *heavily*
modified by me (the 802.1D code remains mostly unchanged from the
original).

diffstat:

 sys/net/bridgestp.c    |  1120 ++++++++++++++++++++++++++++++
 sys/net/if_bridge.c    |  1776 ++++++++++++++++++++++++++++++++++++++++++++++++
 sys/net/if_bridgevar.h |   306 ++++++++
 3 files changed, 3202 insertions(+), 0 deletions(-)

diffs (truncated from 3214 to 300 lines):

diff -r a89ea8e453f2 -r df3a30e952ef sys/net/bridgestp.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/bridgestp.c       Fri Aug 17 21:37:27 2001 +0000
@@ -0,0 +1,1120 @@
+/*     $NetBSD: bridgestp.c,v 1.1 2001/08/17 21:37:28 thorpej Exp $    */
+
+/*
+ * Copyright (c) 2000 Jason L. Wright (jason%thought.net@localhost)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * OpenBSD: bridgestp.c,v 1.5 2001/03/22 03:48:29 jason Exp
+ */
+
+/*
+ * Implementation of the spanning tree protocol as defined in
+ * ISO/IEC Final DIS 15802-3 (IEEE P802.1D/D17), May 25, 1998.
+ * (In English: IEEE 802.1D, Draft 17, 1998)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/callout.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_llc.h>
+
+#include <net/if_ether.h>
+#include <net/if_bridgevar.h>
+
+/* BPDU message types */
+#define        BSTP_MSGTYPE_CFG        0x00            /* Configuration */
+#define        BSTP_MSGTYPE_TCN        0x80            /* Topology chg notification */
+
+/* BPDU flags */
+#define        BSTP_FLAG_TC            0x01            /* Topology change */
+#define        BSTP_FLAG_TCA           0x80            /* Topology change ack */
+
+#define        BSTP_MESSAGE_AGE_INCR   (1 * 256)       /* in 256ths of a second */
+#define        BSTP_TICK_VAL           (1 * 256)       /* in 256ths of a second */
+
+/*
+ * Because BPDU's do not make nicely aligned structures, two different
+ * declarations are used: bstp_?bpdu (wire representation, packed) and
+ * bstp_*_unit (internal, nicely aligned version).
+ */
+
+/* configuration bridge protocol data unit */
+struct bstp_cbpdu {
+       uint8_t         cbu_dsap;               /* LLC: destination sap */
+       uint8_t         cbu_ssap;               /* LLC: source sap */
+       uint8_t         cbu_ctl;                /* LLC: control */
+       uint16_t        cbu_protoid;            /* protocol id */
+       uint8_t         cbu_protover;           /* protocol version */
+       uint8_t         cbu_bpdutype;           /* message type */
+       uint8_t         cbu_flags;              /* flags (below) */
+
+       /* root id */
+       uint16_t        cbu_rootpri;            /* root priority */
+       uint8_t cbu_rootaddr[6];        /* root address */
+
+       uint32_t        cbu_rootpathcost;       /* root path cost */
+
+       /* bridge id */
+       uint16_t        cbu_bridgepri;          /* bridge priority */
+       uint8_t         cbu_bridgeaddr[6];      /* bridge address */
+
+       uint16_t        cbu_portid;             /* port id */
+       uint16_t        cbu_messageage;         /* current message age */
+       uint16_t        cbu_maxage;             /* maximum age */
+       uint16_t        cbu_hellotime;          /* hello time */
+       uint16_t        cbu_forwarddelay;       /* forwarding delay */
+} __attribute__((__packed__));
+
+/* topology change notification bridge protocol data unit */
+struct bstp_tbpdu {
+       uint8_t         tbu_dsap;               /* LLC: destination sap */
+       uint8_t         tbu_ssap;               /* LLC: source sap */
+       uint8_t         tbu_ctl;                /* LLC: control */
+       uint16_t        tbu_protoid;            /* protocol id */
+       uint8_t         tbu_protover;           /* protocol version */
+       uint8_t         tbu_bpdutype;           /* message type */
+} __attribute__((__packed__));
+
+const uint8_t bstp_etheraddr[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
+
+void   bstp_initialize_port(struct bridge_softc *, struct bridge_iflist *);
+void   bstp_ifupdstatus(struct bridge_softc *, struct bridge_iflist *);
+void   bstp_enable_port(struct bridge_softc *, struct bridge_iflist *);
+void   bstp_disable_port(struct bridge_softc *, struct bridge_iflist *);
+void   bstp_enable_change_detection(struct bridge_iflist *);
+void   bstp_disable_change_detection(struct bridge_iflist *);
+int    bstp_root_bridge(struct bridge_softc *sc);
+int    bstp_supersedes_port_info(struct bridge_softc *,
+           struct bridge_iflist *, struct bstp_config_unit *);
+int    bstp_designated_port(struct bridge_softc *, struct bridge_iflist *);
+int    bstp_designated_for_some_port(struct bridge_softc *);
+void   bstp_transmit_config(struct bridge_softc *, struct bridge_iflist *);
+void   bstp_transmit_tcn(struct bridge_softc *);
+void   bstp_received_config_bpdu(struct bridge_softc *,
+           struct bridge_iflist *, struct bstp_config_unit *);
+void   bstp_received_tcn_bpdu(struct bridge_softc *, struct bridge_iflist *,
+           struct bstp_tcn_unit *);
+void   bstp_record_config_information(struct bridge_softc *,
+           struct bridge_iflist *, struct bstp_config_unit *);
+void   bstp_record_config_timeout_values(struct bridge_softc *,
+           struct bstp_config_unit *);
+void   bstp_config_bpdu_generation(struct bridge_softc *);
+void   bstp_send_config_bpdu(struct bridge_softc *, struct bridge_iflist *,
+           struct bstp_config_unit *);
+void   bstp_configuration_update(struct bridge_softc *);
+void   bstp_root_selection(struct bridge_softc *);
+void   bstp_designated_port_selection(struct bridge_softc *);
+void   bstp_become_designated_port(struct bridge_softc *,
+           struct bridge_iflist *);
+void   bstp_port_state_selection(struct bridge_softc *);
+void   bstp_make_forwarding(struct bridge_softc *, struct bridge_iflist *);
+void   bstp_make_blocking(struct bridge_softc *, struct bridge_iflist *);
+void   bstp_set_port_state(struct bridge_iflist *, uint8_t);
+void   bstp_set_bridge_priority(struct bridge_softc *, uint64_t);
+void   bstp_set_port_priority(struct bridge_softc *, struct bridge_iflist *,
+           uint16_t);
+void   bstp_set_path_cost(struct bridge_softc *, struct bridge_iflist *,
+           uint32_t);
+void   bstp_topology_change_detection(struct bridge_softc *);
+void   bstp_topology_change_acknowledged(struct bridge_softc *);
+void   bstp_acknowledge_topology_change(struct bridge_softc *,
+           struct bridge_iflist *);
+
+void   bstp_tick(void *);
+void   bstp_timer_start(struct bridge_timer *, uint16_t);
+void   bstp_timer_stop(struct bridge_timer *);
+int    bstp_timer_expired(struct bridge_timer *, uint16_t);
+
+void   bstp_hold_timer_expiry(struct bridge_softc *, struct bridge_iflist *);
+void   bstp_message_age_timer_expiry(struct bridge_softc *,
+           struct bridge_iflist *);
+void   bstp_forward_delay_timer_expiry(struct bridge_softc *,
+           struct bridge_iflist *);
+void   bstp_topology_change_timer_expiry(struct bridge_softc *);
+void   bstp_tcn_timer_expiry(struct bridge_softc *);
+void   bstp_hello_timer_expiry(struct bridge_softc *);
+
+void
+bstp_transmit_config(struct bridge_softc *sc, struct bridge_iflist *bif)
+{
+       if (bif->bif_hold_timer.active) {
+               bif->bif_config_pending = 1;
+               return;
+       }
+
+       bif->bif_config_bpdu.cu_message_type = BSTP_MSGTYPE_CFG;
+       bif->bif_config_bpdu.cu_rootid = sc->sc_designated_root;
+       bif->bif_config_bpdu.cu_root_path_cost = sc->sc_root_path_cost;
+       bif->bif_config_bpdu.cu_bridge_id = sc->sc_bridge_id;
+       bif->bif_config_bpdu.cu_port_id = bif->bif_port_id;
+
+       if (bstp_root_bridge(sc))
+               bif->bif_config_bpdu.cu_message_age = 0;
+       else
+               bif->bif_config_bpdu.cu_message_age =
+                   sc->sc_root_port->bif_message_age_timer.value +
+                   BSTP_MESSAGE_AGE_INCR;
+
+       bif->bif_config_bpdu.cu_max_age = sc->sc_max_age;
+       bif->bif_config_bpdu.cu_hello_time = sc->sc_hello_time;
+       bif->bif_config_bpdu.cu_forward_delay = sc->sc_forward_delay;
+       bif->bif_config_bpdu.cu_topology_change_acknowledgment
+           = bif->bif_topology_change_acknowledge;
+       bif->bif_config_bpdu.cu_topology_change = sc->sc_topology_change;
+
+       if (bif->bif_config_bpdu.cu_message_age < sc->sc_max_age) {
+               bif->bif_topology_change_acknowledge = 0;
+               bif->bif_config_pending = 0;
+               bstp_send_config_bpdu(sc, bif, &bif->bif_config_bpdu);
+               bstp_timer_start(&bif->bif_hold_timer, 0);
+       }
+}
+
+void
+bstp_send_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
+    struct bstp_config_unit *cu)
+{
+       struct ifnet *ifp;
+       struct mbuf *m;
+       struct ether_header *eh;
+       struct bstp_cbpdu bpdu;
+       int s;
+
+       ifp = bif->bif_ifp;
+
+       if ((ifp->if_flags & IFF_RUNNING) == 0)
+               return;
+
+       MGETHDR(m, M_DONTWAIT, MT_DATA);
+       if (m == NULL)
+               return;
+
+       eh = mtod(m, struct ether_header *);
+
+       m->m_pkthdr.rcvif = ifp;
+       m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
+       m->m_len = m->m_pkthdr.len;
+
+       bpdu.cbu_ssap = bpdu.cbu_dsap = LLC_8021D_LSAP;
+       bpdu.cbu_ctl = LLC_UI;
+       bpdu.cbu_protoid = htons(0);
+       bpdu.cbu_protover = 0;
+       bpdu.cbu_bpdutype = cu->cu_message_type;
+       bpdu.cbu_flags = (cu->cu_topology_change ? BSTP_FLAG_TC : 0) |
+           (cu->cu_topology_change_acknowledgment ? BSTP_FLAG_TCA : 0);
+
+       bpdu.cbu_rootpri = htons(cu->cu_rootid >> 48);
+       bpdu.cbu_rootaddr[0] = cu->cu_rootid >> 40;
+       bpdu.cbu_rootaddr[1] = cu->cu_rootid >> 32;
+       bpdu.cbu_rootaddr[2] = cu->cu_rootid >> 24;
+       bpdu.cbu_rootaddr[3] = cu->cu_rootid >> 16;
+       bpdu.cbu_rootaddr[4] = cu->cu_rootid >> 8;
+       bpdu.cbu_rootaddr[5] = cu->cu_rootid >> 0;
+
+       bpdu.cbu_rootpathcost = htonl(cu->cu_root_path_cost);
+
+       bpdu.cbu_bridgepri = htons(cu->cu_rootid >> 48);
+       bpdu.cbu_bridgeaddr[0] = cu->cu_rootid >> 40;
+       bpdu.cbu_bridgeaddr[1] = cu->cu_rootid >> 32;
+       bpdu.cbu_bridgeaddr[2] = cu->cu_rootid >> 24;
+       bpdu.cbu_bridgeaddr[3] = cu->cu_rootid >> 16;
+       bpdu.cbu_bridgeaddr[4] = cu->cu_rootid >> 8;
+       bpdu.cbu_bridgeaddr[5] = cu->cu_rootid >> 0;
+
+       bpdu.cbu_portid = htons(cu->cu_port_id);
+       bpdu.cbu_messageage = htons(cu->cu_message_age);
+       bpdu.cbu_maxage = htons(cu->cu_max_age);
+       bpdu.cbu_hellotime = htons(cu->cu_hello_time);
+       bpdu.cbu_forwarddelay = htons(cu->cu_forward_delay);
+
+       memcpy(eh->ether_shost, LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
+       memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
+       eh->ether_type = htons(sizeof(bpdu));
+
+       memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
+
+       s = splnet();
+       bridge_enqueue(sc, ifp, m);
+       splx(s);
+}
+
+int
+bstp_root_bridge(struct bridge_softc *sc)
+{
+       return (sc->sc_designated_root == sc->sc_bridge_id);
+}
+
+int
+bstp_supersedes_port_info(struct bridge_softc *sc, struct bridge_iflist *bif,
+    struct bstp_config_unit *cu)
+{
+       if (cu->cu_rootid < bif->bif_designated_root)
+               return (1);
+       if (cu->cu_rootid > bif->bif_designated_root)
+               return (0);
+
+       if (cu->cu_root_path_cost < bif->bif_designated_cost)
+               return (1);
+       if (cu->cu_root_path_cost > bif->bif_designated_cost)
+               return (0);
+
+       if (cu->cu_bridge_id < bif->bif_designated_bridge)



Home | Main Index | Thread Index | Old Index