kernel - Greatly enhance if_bridge
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 23 Feb 2011 04:56:42 +0000 (20:56 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 23 Feb 2011 04:56:42 +0000 (20:56 -0800)
* Document the link0 feature, which enables transparent bridging.

* Implement the link1 feature, automatic failover using a slight mangling
  of the 802.11d protocol.  Both ends must implement the feature for this
  to work.  Essentially this causes CFG 802.11d messages to be generated
  on the hello interval even if a bridge is not the root bridge.

  The bridge also monitors for this traffic and places the link in a special
  L1BLOCKING state if it fails to receive any frames in (10 x hello) (around
  20 seconds usually).  This will automatically cause the bridge to failover
  to other links.

  This only operates on links participating in the STP protocol (see man
  ifconfig), when link1 is set on the bridge interface.  For ethernet
  bridging the link interfaces are typically multiple TAP interfaces.

* Allow all link interfaces participating in a bridge to have the same
  MAC address (used with TAP interfaces typically).  This is mandatory
  if you also intend to use the link1 feature and want your failover to
  be reasonably smooth.  The feature can be useful regardless.

* The ifconfig bridge output now shows additional information about
  link state and who it thinks the root node is.

sbin/ifconfig/ifbridge.c
share/man/man4/bridge.4
sys/net/bridge/bridgestp.c
sys/net/bridge/if_bridge.c
sys/net/bridge/if_bridgevar.h

index b01ffcd..5f86d6e 100644 (file)
@@ -116,6 +116,7 @@ bridge_interfaces(int s, const char *prefix)
                "learning",
                "forwarding",
                "blocking",
+               "blocking (link1)"
        };
        struct ifbifconf bifc;
        struct ifbreq *req;
@@ -163,6 +164,14 @@ bridge_interfaces(int s, const char *prefix)
                                printf(" <unknown state %d>",
                                    req->ifbr_state);
                        printf("\n");
+                       printf("%sdesignated root:   %016jx\n",
+                               pad, (intmax_t)req->ifbr_designated_root);
+                       printf("%sdesignated bridge: %016jx\n",
+                               pad, (intmax_t)req->ifbr_designated_bridge);
+                       printf("%sdesignated cost:   %u\n",
+                               pad, req->ifbr_designated_cost);
+                       printf("%sdesignated port:   %u\n",
+                               pad, req->ifbr_designated_port);
                }
        }
 
index 14f0293..ef7b50f 100644 (file)
@@ -2,6 +2,7 @@
 .\" All rights reserved.
 .\"
 .\" Written by Jason R. Thorpe for Wasabi Systems, Inc.
+.\" Spanning tree modifications by Matthew Dillon
 .\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $NetBSD: bridge.4,v 1.7 2005/06/23 12:47:38 peter Exp $
-.\" $DragonFly: src/share/man/man4/bridge.4,v 1.10 2007/07/29 17:27:45 swildner Exp $
 .\"
-.Dd August 30, 2006
+.Dd February 22, 2011
 .Dt BRIDGE 4
 .Os
 .Sh NAME
@@ -124,6 +123,48 @@ as on the interface on which the packet arrives or departs.
 .Pp
 The MTU of the first member interface to be added is used as the bridge MTU,
 all additional members are required to have exactly the same value.
+.Sh EXTRA FEATURES
+.Dx
+implements two additional features to make spanning tree operation more
+resilient.
+.Pp
+Specifying
+.Cm link0
+on the bridge interface places the bridge in transparent bridging mode.
+The bridge will make every attempt to retain the original source MAC in
+the ethernet link header.
+.Pp
+Specifying
+.Cm link1
+on the bridge interface forces the bridge to generate a 802.11d CFG
+message on every hello interval for all interfaces participating
+in the STP protocol.
+Normally CFG messages are only generated by the root bridge interface
+or during topology changes.
+In addition the bridge code expects to receive 802.11d frames from
+all interface participating in the STP protocol.
+.Pp
+An interface which fails to receive a 802.11d frame within 10 times
+the hello interval (usually 20 seconds) automatically goes into
+l1blocking mode, which can be observed in the ifconfig output for
+the bridge.  This removes the interface from consideration and the
+bridge code automatically routes around it.
+.Pp
+Using
+.Cm link0
+and
+.Cm link1
+together between two
+.Dx
+boxes allows you to maintain multiple parallel vpns between those
+boxes via different networks (if you happen to be on more than one
+with internet access).
+Use separate openvpn instances and tap devices for each vpn link
+to accomplish this, placing them in the same bridge interface on
+the two endpoints.
+The tap devices do not need any IP configuration when bridged and
+can be assigned the same ether MAC (in fact they have to be
+if you want the failover to work nicely).
 .Sh SEE ALSO
 .Xr pf 4 ,
 .Xr ifconfig 8
index 7c7edc5..f3a4690 100644 (file)
@@ -160,6 +160,8 @@ static void bstp_make_forwarding(struct bridge_softc *,
                    struct bridge_iflist *);
 static void    bstp_make_blocking(struct bridge_softc *,
                    struct bridge_iflist *);
+static void    bstp_make_l1blocking(struct bridge_softc *sc,
+                   struct bridge_iflist *bif);
 static void    bstp_set_port_state(struct bridge_iflist *, uint8_t);
 #ifdef notused
 static void    bstp_set_bridge_priority(struct bridge_softc *, uint64_t);
@@ -218,7 +220,8 @@ bstp_transmit_config(struct bridge_softc *sc, struct bridge_iflist *bif)
            = 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) {
+       if (bif->bif_config_bpdu.cu_message_age < sc->sc_max_age ||
+           (sc->sc_ifp->if_flags & IFF_LINK1)) {
                bif->bif_topology_change_acknowledge = 0;
                bif->bif_config_pending = 0;
                bstp_send_config_bpdu(sc, bif, &bif->bif_config_bpdu);
@@ -228,7 +231,7 @@ bstp_transmit_config(struct bridge_softc *sc, struct bridge_iflist *bif)
 
 static void
 bstp_send_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
-    struct bstp_config_unit *cu)
+                     struct bstp_config_unit *cu)
 {
        struct ifnet *ifp;
        struct mbuf *m;
@@ -352,9 +355,11 @@ bstp_config_bpdu_generation(struct bridge_softc *sc)
        LIST_FOREACH_MUTABLE(bif, &sc->sc_iflists[mycpuid], bif_next, nbif) {
                if ((bif->bif_flags & IFBIF_STP) == 0)
                        continue;
-               if (bstp_designated_port(sc, bif) &&
-                   (bif->bif_state != BSTP_IFSTATE_DISABLED))
+               if (bif->bif_state != BSTP_IFSTATE_DISABLED &&
+                   ((sc->sc_ifp->if_flags & IFF_LINK1) ||
+                    bstp_designated_port(sc, bif))) {
                        bstp_transmit_config(sc, bif);
+               }
 
                if (nbif != NULL && !nbif->bif_onlist) {
                        KKASSERT(bif->bif_onlist);
@@ -551,8 +556,9 @@ bstp_make_forwarding(struct bridge_softc *sc, struct bridge_iflist *bif)
 static void
 bstp_make_blocking(struct bridge_softc *sc, struct bridge_iflist *bif)
 {
-       if ((bif->bif_state != BSTP_IFSTATE_DISABLED) &&
-           (bif->bif_state != BSTP_IFSTATE_BLOCKING)) {
+       if (bif->bif_state != BSTP_IFSTATE_DISABLED &&
+           bif->bif_state != BSTP_IFSTATE_BLOCKING &&
+           bif->bif_state != BSTP_IFSTATE_L1BLOCKING) {
                if ((bif->bif_state == BSTP_IFSTATE_FORWARDING) ||
                    (bif->bif_state == BSTP_IFSTATE_LEARNING)) {
                        if (bif->bif_change_detection_enabled) {
@@ -566,6 +572,24 @@ bstp_make_blocking(struct bridge_softc *sc, struct bridge_iflist *bif)
 }
 
 static void
+bstp_make_l1blocking(struct bridge_softc *sc, struct bridge_iflist *bif)
+{
+       switch(bif->bif_state) {
+       case BSTP_IFSTATE_LISTENING:
+       case BSTP_IFSTATE_LEARNING:
+       case BSTP_IFSTATE_FORWARDING:
+       case BSTP_IFSTATE_BLOCKING:
+               bstp_set_port_state(bif, BSTP_IFSTATE_L1BLOCKING);
+               bridge_rtdelete(sc, bif->bif_ifp, IFBF_FLUSHDYN);
+               bstp_timer_stop(&bif->bif_forward_delay_timer);
+               bstp_timer_stop(&bif->bif_link1_timer);
+               break;
+       default:
+               break;
+       }
+}
+
+static void
 bstp_set_port_state(struct bridge_iflist *bif, uint8_t state)
 {
        bif->bif_state = state;
@@ -612,6 +636,19 @@ bstp_input(struct bridge_softc *sc, struct bridge_iflist *bif, struct mbuf *m)
        if ((bif->bif_flags & IFBIF_STP) == 0)
                goto out;
 
+       /*
+        * The L1BLOCKING (ping pong failover) test needs to reset the
+        * timer if LINK1 is active.
+        */
+       if (bif->bif_state == BSTP_IFSTATE_L1BLOCKING) {
+               bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
+               if (sc->sc_ifp->if_flags & IFF_LINK1)
+                       bstp_timer_start(&bif->bif_link1_timer, 0);
+               bstp_make_forwarding(sc, bif);
+       } else if (sc->sc_ifp->if_flags & IFF_LINK1) {
+               bstp_timer_start(&bif->bif_link1_timer, 0);
+       }
+
        eh = mtod(m, struct ether_header *);
 
        len = ntohs(eh->ether_type);
@@ -700,7 +737,13 @@ bstp_received_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
                        bstp_port_state_selection(sc);
 
                        if ((bstp_root_bridge(sc) == 0) && root) {
-                               bstp_timer_stop(&sc->sc_hello_timer);
+                               /*
+                                * We continuously transmit hello's if
+                                * link1 is set (topology change bit will
+                                * be zero so they shouldn't propagate).
+                                */
+                               if ((sc->sc_ifp->if_flags & IFF_LINK1) == 0)
+                                       bstp_timer_stop(&sc->sc_hello_timer);
 
                                if (sc->sc_topology_change_detected) {
                                        bstp_timer_stop(
@@ -733,16 +776,23 @@ bstp_received_tcn_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
        }
 }
 
+/*
+ * link1 forces continuous hello's (the bridge interface must be cycled
+ * to start them up), so keep the timer hot if that is the case, otherwise
+ * only send HELLO's if we are the root.
+ */
 static void
 bstp_hello_timer_expiry(struct bridge_softc *sc)
 {
        bstp_config_bpdu_generation(sc);
-       bstp_timer_start(&sc->sc_hello_timer, 0);
+
+       if ((sc->sc_ifp->if_flags & IFF_LINK1) || bstp_root_bridge(sc))
+               bstp_timer_start(&sc->sc_hello_timer, 0);
 }
 
 static void
 bstp_message_age_timer_expiry(struct bridge_softc *sc,
-    struct bridge_iflist *bif)
+                             struct bridge_iflist *bif)
 {
        int root;
 
@@ -751,6 +801,11 @@ bstp_message_age_timer_expiry(struct bridge_softc *sc,
        bstp_configuration_update(sc);
        bstp_port_state_selection(sc);
 
+       /*
+        * If we've become the root and were not the root before
+        * we have some cleanup to do.  This also occurs if we
+        * wind up being completely isolated.
+        */
        if ((bstp_root_bridge(sc)) && (root == 0)) {
                sc->sc_max_age = sc->sc_bridge_max_age;
                sc->sc_hello_time = sc->sc_bridge_hello_time;
@@ -814,6 +869,18 @@ bstp_hold_timer_expiry(struct bridge_softc *sc, struct bridge_iflist *bif)
                bstp_transmit_config(sc, bif);
 }
 
+/*
+ * If no traffic received directly on this port for the specified
+ * period with link1 set we go into a special blocking mode to
+ * fail-over traffic to another port.
+ */
+static void
+bstp_link1_timer_expiry(struct bridge_softc *sc, struct bridge_iflist *bif)
+{
+       if (sc->sc_ifp->if_flags & IFF_LINK1)
+               bstp_make_l1blocking(sc, bif);
+}
+
 static int
 bstp_addr_cmp(const uint8_t *a, const uint8_t *b)
 {
@@ -885,6 +952,8 @@ bstp_initialization(struct bridge_softc *sc)
                    bstp_tick, sc);
 
        LIST_FOREACH_MUTABLE(bif, &sc->sc_iflists[mycpuid], bif_next, nbif) {
+               if (sc->sc_ifp->if_flags & IFF_LINK1)
+                       bstp_timer_start(&bif->bif_link1_timer, 0);
                if (bif->bif_flags & IFBIF_STP)
                        bstp_ifupdstatus(sc, bif);
                else
@@ -914,6 +983,7 @@ bstp_stop(struct bridge_softc *sc)
                bstp_timer_stop(&bif->bif_hold_timer);
                bstp_timer_stop(&bif->bif_message_age_timer);
                bstp_timer_stop(&bif->bif_forward_delay_timer);
+               bstp_timer_stop(&bif->bif_link1_timer);
        }
 
        callout_stop(&sc->sc_bstpcallout);
@@ -942,12 +1012,15 @@ bstp_initialize_port(struct bridge_softc *sc, struct bridge_iflist *bif)
        bstp_timer_stop(&bif->bif_message_age_timer);
        bstp_timer_stop(&bif->bif_forward_delay_timer);
        bstp_timer_stop(&bif->bif_hold_timer);
+       bstp_timer_stop(&bif->bif_link1_timer);
 }
 
 static void
 bstp_enable_port(struct bridge_softc *sc, struct bridge_iflist *bif)
 {
        bstp_initialize_port(sc, bif);
+       if (sc->sc_ifp->if_flags & IFF_LINK1)
+               bstp_timer_start(&bif->bif_link1_timer, 0);
        bstp_port_state_selection(sc);
 }
 
@@ -963,6 +1036,7 @@ bstp_disable_port(struct bridge_softc *sc, struct bridge_iflist *bif)
        bif->bif_config_pending = 0;
        bstp_timer_stop(&bif->bif_message_age_timer);
        bstp_timer_stop(&bif->bif_forward_delay_timer);
+       bstp_timer_stop(&bif->bif_link1_timer);
        bstp_configuration_update(sc);
        bstp_port_state_selection(sc);
        bridge_rtdelete(sc, bif->bif_ifp, IFBF_FLUSHDYN);
@@ -1192,6 +1266,10 @@ bstp_tick_handler(netmsg_t msg)
                if (bstp_timer_expired(&bif->bif_hold_timer,
                    sc->sc_hold_time))
                        bstp_hold_timer_expiry(sc, bif);
+
+               if (bstp_timer_expired(&bif->bif_link1_timer,
+                   sc->sc_hello_time * 10))
+                       bstp_link1_timer_expiry(sc, bif);
        }
 
        if (sc->sc_ifp->if_flags & IFF_RUNNING)
index 3720f5c..a9f35f0 100644 (file)
@@ -1251,6 +1251,10 @@ bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
        req->ifbr_priority = bif->bif_priority;
        req->ifbr_path_cost = bif->bif_path_cost;
        req->ifbr_portno = bif->bif_ifp->if_index & 0xff;
+       req->ifbr_designated_root = bif->bif_designated_root;
+       req->ifbr_designated_bridge = bif->bif_designated_bridge;
+       req->ifbr_designated_cost = bif->bif_designated_cost;
+       req->ifbr_designated_port = bif->bif_designated_port;
 
        return (0);
 }
@@ -1363,6 +1367,10 @@ bridge_ioctl_gifs(struct bridge_softc *sc, void *arg)
                breq->ifbr_priority = bif->bif_priority;
                breq->ifbr_path_cost = bif->bif_path_cost;
                breq->ifbr_portno = bif->bif_ifp->if_index & 0xff;
+               breq->ifbr_designated_root = bif->bif_designated_root;
+               breq->ifbr_designated_bridge = bif->bif_designated_bridge;
+               breq->ifbr_designated_cost = bif->bif_designated_cost;
+               breq->ifbr_designated_port = bif->bif_designated_port;
                breq++;
                count++;
                len -= sizeof(*breq);
@@ -1841,6 +1849,7 @@ static int
 bridge_output(struct ifnet *ifp, struct mbuf *m)
 {
        struct bridge_softc *sc = ifp->if_bridge;
+       struct bridge_iflist *bif, *nbif;
        struct ether_header *eh;
        struct ifnet *dst_if, *bifp;
        int from_us;
@@ -1887,7 +1896,6 @@ bridge_output(struct ifnet *ifp, struct mbuf *m)
        else
                dst_if = bridge_rtlookup(sc, eh->ether_dhost);
        if (dst_if == NULL) {
-               struct bridge_iflist *bif, *nbif;
                struct mbuf *mc;
                int used = 0;
 
@@ -1909,6 +1917,7 @@ bridge_output(struct ifnet *ifp, struct mbuf *m)
                        if (dst_if != ifp &&
                            (bif->bif_flags & IFBIF_STP) != 0) {
                                switch (bif->bif_state) {
+                               case BSTP_IFSTATE_L1BLOCKING:
                                case BSTP_IFSTATE_BLOCKING:
                                case BSTP_IFSTATE_LISTENING:
                                case BSTP_IFSTATE_DISABLED:
@@ -1944,8 +1953,44 @@ bridge_output(struct ifnet *ifp, struct mbuf *m)
 
 sendunicast:
        /*
-        * XXX Spanning tree consideration here?
+        * If STP is enabled on the target and it is not in a good state
+        * scan all bridged interfaces for any with a matching MAC which is
+        * in a good state and use that one.
+        *
+        * We need to do this because arp entries tag onto a particular
+        * interface and if it happens to be dead then the packets will
+        * go into a bit bucket.
         */
+       bif = bridge_lookup_member_if(sc, dst_if);
+       if (bif->bif_flags & IFBIF_STP) {
+               switch (bif->bif_state) {
+               case BSTP_IFSTATE_L1BLOCKING:
+               case BSTP_IFSTATE_BLOCKING:
+               case BSTP_IFSTATE_LISTENING:
+               case BSTP_IFSTATE_DISABLED:
+                       LIST_FOREACH_MUTABLE(bif, &sc->sc_iflists[mycpuid],
+                                            bif_next, nbif) {
+                               if (memcmp(IF_LLADDR(bif->bif_ifp),
+                                          IF_LLADDR(dst_if),
+                                          ETHER_ADDR_LEN) != 0) {
+                                       continue;
+                               }
+                               if (bif->bif_state == BSTP_IFSTATE_L1BLOCKING||
+                                   bif->bif_state == BSTP_IFSTATE_BLOCKING ||
+                                   bif->bif_state == BSTP_IFSTATE_LISTENING||
+                                   bif->bif_state == BSTP_IFSTATE_DISABLED) {
+                                       continue;
+                               }
+                               dst_if = bif->bif_ifp;
+                               break;
+                       }
+                       break;
+               default:
+                       /* keep dst_if */
+                       break;
+               }
+       }
+
        if (sc->sc_span)
                bridge_span(sc, m);
        if ((dst_if->if_flags & IFF_RUNNING) == 0)
@@ -2035,6 +2080,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
 
        if (bif->bif_flags & IFBIF_STP) {
                switch (bif->bif_state) {
+               case BSTP_IFSTATE_L1BLOCKING:
                case BSTP_IFSTATE_BLOCKING:
                case BSTP_IFSTATE_LISTENING:
                case BSTP_IFSTATE_DISABLED:
@@ -2111,6 +2157,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
                switch (bif->bif_state) {
                case BSTP_IFSTATE_DISABLED:
                case BSTP_IFSTATE_BLOCKING:
+               case BSTP_IFSTATE_L1BLOCKING:
                        m_freem(m);
                        return;
                }
@@ -2238,7 +2285,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
        if (m->m_flags & (M_BCAST | M_MCAST)) {
                /* Tap off 802.1D packets; they do not get forwarded. */
                if (memcmp(eh->ether_dhost, bstp_etheraddr,
-                   ETHER_ADDR_LEN) == 0) {
+                           ETHER_ADDR_LEN) == 0) {
                        ifnet_serialize_all(bifp);
                        bstp_input(sc, bif, m);
                        ifnet_deserialize_all(bifp);
@@ -2250,6 +2297,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
 
                if (bif->bif_flags & IFBIF_STP) {
                        switch (bif->bif_state) {
+                       case BSTP_IFSTATE_L1BLOCKING:
                        case BSTP_IFSTATE_BLOCKING:
                        case BSTP_IFSTATE_LISTENING:
                        case BSTP_IFSTATE_DISABLED:
@@ -2305,6 +2353,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
 
        if (bif->bif_flags & IFBIF_STP) {
                switch (bif->bif_state) {
+               case BSTP_IFSTATE_L1BLOCKING:
                case BSTP_IFSTATE_BLOCKING:
                case BSTP_IFSTATE_LISTENING:
                case BSTP_IFSTATE_DISABLED:
@@ -2401,6 +2450,7 @@ bridge_start_bcast(struct bridge_softc *sc, struct mbuf *m)
 
                if (bif->bif_flags & IFBIF_STP) {
                        switch (bif->bif_state) {
+                       case BSTP_IFSTATE_L1BLOCKING:
                        case BSTP_IFSTATE_BLOCKING:
                        case BSTP_IFSTATE_DISABLED:
                                continue;
@@ -2481,6 +2531,7 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
 
                if (bif->bif_flags & IFBIF_STP) {
                        switch (bif->bif_state) {
+                       case BSTP_IFSTATE_L1BLOCKING:
                        case BSTP_IFSTATE_BLOCKING:
                        case BSTP_IFSTATE_DISABLED:
                                continue;
index ab6bb5f..0bb866f 100644 (file)
@@ -120,6 +120,11 @@ struct ifbreq {
        uint8_t         ifbr_priority;          /* member if STP priority */
        uint8_t         ifbr_path_cost;         /* member if STP cost */
        uint8_t         ifbr_portno;            /* member if port number */
+       uint64_t        ifbr_designated_root;   /* current root id */
+       uint64_t        ifbr_designated_bridge; /* current bridge id */
+       uint32_t        ifbr_designated_cost;   /* current cost calc */
+       uint16_t        ifbr_designated_port;   /* current port calc */
+       uint16_t        unused01;
 };
 
 /* BRDGGIFFLAGS, BRDGSIFFLAGS */
@@ -141,6 +146,7 @@ struct ifbreq {
 #define        BSTP_IFSTATE_LEARNING   2
 #define        BSTP_IFSTATE_FORWARDING 3
 #define        BSTP_IFSTATE_BLOCKING   4
+#define        BSTP_IFSTATE_L1BLOCKING 5       /* link1 blocking mode no-activity */
 
 /*
  * Interface list structure.
@@ -239,6 +245,7 @@ struct bridge_ifinfo {
        struct bridge_timer     bifi_hold_timer;
        struct bridge_timer     bifi_message_age_timer;
        struct bridge_timer     bifi_forward_delay_timer;
+       struct bridge_timer     bifi_link1_timer;
        struct bstp_config_unit bifi_config_bpdu;
        uint16_t                bifi_port_id;
        uint16_t                bifi_designated_port;
@@ -258,6 +265,7 @@ struct bridge_ifinfo {
 #define bif_hold_timer                 bif_info->bifi_hold_timer
 #define bif_message_age_timer          bif_info->bifi_message_age_timer
 #define bif_forward_delay_timer                bif_info->bifi_forward_delay_timer
+#define bif_link1_timer                        bif_info->bifi_link1_timer
 #define bif_config_bpdu                        bif_info->bifi_config_bpdu
 #define bif_port_id                    bif_info->bifi_port_id
 #define bif_designated_port            bif_info->bifi_designated_port