Improve STP library.
authorBen Pfaff <blp@nicira.com>
Tue, 6 Jan 2009 00:04:05 +0000 (16:04 -0800)
committerBen Pfaff <blp@nicira.com>
Tue, 6 Jan 2009 00:04:05 +0000 (16:04 -0800)
- Don't expose the funny STP time units; instead, convert to and from
  milliseconds at the module boundary.

- Allow the client to configure the max age, hello time, and forward delay
  parameters.

- Do more of the construction of BPDUs internally, instead of making the
  client do it.

16 files changed:
lib/stp.c
lib/stp.h
secchan/stp-secchan.c
tests/test-stp-ieee802.1d-1998
tests/test-stp-ieee802.1d-2004-fig17.4
tests/test-stp-ieee802.1d-2004-fig17.6
tests/test-stp-ieee802.1d-2004-fig17.7
tests/test-stp-iol-io-1.1
tests/test-stp-iol-io-1.2
tests/test-stp-iol-io-1.4
tests/test-stp-iol-io-1.5
tests/test-stp-iol-op-1.4
tests/test-stp-iol-op-3.1
tests/test-stp-iol-op-3.3
tests/test-stp-iol-op-3.4
tests/test-stp.c

index 0847f57a170d5f8073c104114223a2236ce9305a..fa9dd010a8e57f2e1901ea3bc59261823cc72419 100644 (file)
--- a/lib/stp.c
+++ b/lib/stp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
+/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford
  * Junior University
  *
  * We are making the OpenFlow specification and associated documentation
@@ -39,6 +39,7 @@
 #include <assert.h>
 #include <inttypes.h>
 #include <stdlib.h>
+#include "ofpbuf.h"
 #include "packets.h"
 #include "util.h"
 #include "xtoxll.h"
@@ -121,6 +122,10 @@ struct stp {
     int bridge_max_age;             /* 8.5.3.8: max_age when we're root. */
     int bridge_hello_time;          /* 8.5.3.9: hello_time as root. */
     int bridge_forward_delay;       /* 8.5.3.10: forward_delay as root. */
+    int rq_max_age;                 /* User-requested max age, in ms. */
+    int rq_hello_time;              /* User-requested hello time, in ms. */
+    int rq_forward_delay;           /* User-requested forward delay, in ms. */
+    int elapsed_remainder;          /* Left-over msecs from last stp_tick(). */
 
     /* Dynamic bridge data. */
     stp_identifier designated_root; /* 8.5.3.1: Bridge believed to be root. */
@@ -139,8 +144,7 @@ struct stp {
 
     /* Interface to client. */
     struct stp_port *first_changed_port;
-    void (*send_bpdu)(const void *bpdu, size_t bpdu_size,
-                      int port_no, void *aux);
+    void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux);
     void *aux;
 };
 
@@ -159,8 +163,6 @@ stp_next_enabled_port(const struct stp *stp, const struct stp_port *port)
     return NULL;
 }
 
-#define SECONDS_TO_TIMER(SECS) ((SECS) * 0x100)
-
 #define MESSAGE_AGE_INCREMENT 1
 
 static void stp_transmit_config(struct stp_port *);
@@ -198,27 +200,33 @@ static void stp_tcn_timer_expiry(struct stp *);
 static void stp_topology_change_timer_expiry(struct stp *);
 static void stp_hold_timer_expiry(struct stp_port *);
 static void stp_initialize_port(struct stp_port *, enum stp_state);
-static void stp_become_root_bridge(struct stp *stp);
+static void stp_become_root_bridge(struct stp *);
+static void stp_update_bridge_timers(struct stp *);
 
+static int clamp(int x, int min, int max);
+static int ms_to_timer(int ms);
+static int ms_to_timer_remainder(int ms);
+static int timer_to_ms(int timer);
 static void stp_start_timer(struct stp_timer *, int value);
 static void stp_stop_timer(struct stp_timer *);
 static bool stp_timer_expired(struct stp_timer *, int elapsed, int timeout);
 
-/* Creates and returns a new STP instance that initially has no port enabled.
+static void stp_send_bpdu(struct stp_port *, const void *, size_t);
+
+/* Creates and returns a new STP instance that initially has no ports enabled.
  *
  * 'bridge_id' should be a 48-bit MAC address as returned by
  * eth_addr_to_uint64().  'bridge_id' may also have a priority value in its top
- * 16 bits; if those bits are set to 0, the default bridge priority of 32768 is
- * used.  (This priority may be changed with stp_set_bridge_priority().)
+ * 16 bits; if those bits are set to 0, STP_DEFAULT_BRIDGE_PRIORITY is used.
+ * (This priority may be changed with stp_set_bridge_priority().)
  *
- * When the bridge needs to send out a BPDU, it calls 'send_bpdu', passing
- * 'aux' as auxiliary data.  This callback may be called from stp_tick() or
- * stp_received_bpdu().
+ * When the bridge needs to send out a BPDU, it calls 'send_bpdu'.  This
+ * callback may be called from stp_tick() or stp_received_bpdu().  The
+ * arguments to 'send_bpdu' are an STP BPDU encapsulated in 
  */
 struct stp *
 stp_create(const char *name, stp_identifier bridge_id,
-           void (*send_bpdu)(const void *bpdu, size_t bpdu_size,
-                             int port_no, void *aux),
+           void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux),
            void *aux)
 {
     struct stp *stp;
@@ -228,18 +236,16 @@ stp_create(const char *name, stp_identifier bridge_id,
     stp->name = xstrdup(name);
     stp->bridge_id = bridge_id;
     if (!(stp->bridge_id >> 48)) {
-        stp->bridge_id |= UINT64_C(32768) << 48;
+        stp->bridge_id |= (uint64_t) STP_DEFAULT_BRIDGE_PRIORITY << 48;
     }
-    stp->max_age = SECONDS_TO_TIMER(6);
-    stp->hello_time = SECONDS_TO_TIMER(2);
-    stp->forward_delay = SECONDS_TO_TIMER(4);
-    stp->bridge_max_age = stp->max_age;
-    stp->bridge_hello_time = stp->hello_time;
-    stp->bridge_forward_delay = stp->forward_delay;
 
-    /* Verify constraints stated by 802.1D. */
-    assert(2 * (stp->forward_delay - SECONDS_TO_TIMER(1)) >= stp->max_age);
-    assert(stp->max_age >= 2 * (stp->hello_time + SECONDS_TO_TIMER(1)));
+    stp->rq_max_age = 6000;
+    stp->rq_hello_time = 2000;
+    stp->rq_forward_delay = 4000;
+    stp_update_bridge_timers(stp);
+    stp->max_age = stp->bridge_max_age;
+    stp->hello_time = stp->bridge_hello_time;
+    stp->forward_delay = stp->bridge_forward_delay;
 
     stp->designated_root = stp->bridge_id;
     stp->root_path_cost = 0;
@@ -257,7 +263,7 @@ stp_create(const char *name, stp_identifier bridge_id,
     stp->first_changed_port = &stp->ports[ARRAY_SIZE(stp->ports)];
     for (p = stp->ports; p < &stp->ports[ARRAY_SIZE(stp->ports)]; p++) {
         p->stp = stp;
-        p->port_id = (stp_port_no(p) + 1) | (128 << 8);
+        p->port_id = (stp_port_no(p) + 1) | (STP_DEFAULT_PORT_PRIORITY << 8);
         p->path_cost = 19;      /* Recommended default for 100 Mb/s link. */
         stp_initialize_port(p, STP_DISABLED);
     }
@@ -271,10 +277,22 @@ stp_destroy(struct stp *stp)
     free(stp);
 }
 
+/* Runs 'stp' given that 'ms' milliseconds have passed. */
 void
-stp_tick(struct stp *stp, int elapsed)
+stp_tick(struct stp *stp, int ms)
 {
     struct stp_port *p;
+    int elapsed;
+
+    /* Convert 'ms' to STP timer ticks.  Preserve any leftover milliseconds
+     * from previous stp_tick() calls so that we don't lose STP ticks when we
+     * are called too frequently. */
+    ms = clamp(ms, 0, INT_MAX - 1000) + stp->elapsed_remainder;
+    elapsed = ms_to_timer(ms);
+    stp->elapsed_remainder = ms_to_timer_remainder(ms);
+    if (!elapsed) {
+        return;
+    }
 
     if (stp_timer_expired(&stp->hello_timer, elapsed, stp->hello_time)) {
         stp_hello_timer_expiry(stp);
@@ -296,7 +314,7 @@ stp_tick(struct stp *stp, int elapsed)
                               stp->forward_delay)) {
             stp_forward_delay_timer_expiry(p);
         }
-        if (stp_timer_expired(&p->hold_timer, elapsed, SECONDS_TO_TIMER(1))) {
+        if (stp_timer_expired(&p->hold_timer, elapsed, ms_to_timer(1000))) {
             stp_hold_timer_expiry(p);
         }
     }
@@ -340,6 +358,40 @@ stp_set_bridge_priority(struct stp *stp, uint16_t new_priority)
                         | ((uint64_t) new_priority << 48)));
 }
 
+/* Sets the desired hello time for 'stp' to 'ms', in milliseconds.  The actual
+ * hello time is clamped to the range of 1 to 10 seconds and subject to the
+ * relationship (bridge_max_age >= 2 * (bridge_hello_time + 1 s)).  The bridge
+ * hello time is only used when 'stp' is the root bridge. */
+void
+stp_set_hello_time(struct stp *stp, int ms)
+{
+    stp->rq_hello_time = ms;
+    stp_update_bridge_timers(stp);
+}
+
+/* Sets the desired max age for 'stp' to 'ms', in milliseconds.  The actual max
+ * age is clamped to the range of 6 to 40 seconds and subject to the
+ * relationships (2 * (bridge_forward_delay - 1 s) >= bridge_max_age) and
+ * (bridge_max_age >= 2 * (bridge_hello_time + 1 s)).  The bridge max age is
+ * only used when 'stp' is the root bridge. */
+void
+stp_set_max_age(struct stp *stp, int ms)
+{
+    stp->rq_max_age = ms;
+    stp_update_bridge_timers(stp);
+}
+
+/* Sets the desired forward delay for 'stp' to 'ms', in milliseconds.  The
+ * actual forward delay is clamped to the range of 4 to 30 seconds and subject
+ * to the relationship (2 * (bridge_forward_delay - 1 s) >= bridge_max_age).
+ * The bridge forward delay is only used when 'stp' is the root bridge. */
+void
+stp_set_forward_delay(struct stp *stp, int ms)
+{
+    stp->rq_forward_delay = ms;
+    stp_update_bridge_timers(stp);
+}
+
 /* Returns the name given to 'stp' in the call to stp_create(). */
 const char *
 stp_get_name(const struct stp *stp)
@@ -376,6 +428,35 @@ stp_get_root_path_cost(const struct stp *stp)
     return stp->root_path_cost;
 }
 
+/* Returns the bridge hello time, in ms.  The returned value is not necessarily
+ * the value passed to stp_set_hello_time(): it is clamped to the valid range
+ * and quantized to the STP timer resolution.  */
+int
+stp_get_hello_time(const struct stp *stp)
+{
+    return timer_to_ms(stp->bridge_hello_time);
+}
+
+/* Returns the bridge max age, in ms.  The returned value is not necessarily
+ * the value passed to stp_set_max_age(): it is clamped to the valid range,
+ * quantized to the STP timer resolution, and adjusted to match the constraints
+ * due to the hello time.  */
+int
+stp_get_max_age(const struct stp *stp)
+{
+    return timer_to_ms(stp->bridge_max_age);
+}
+
+/* Returns the bridge forward delay, in ms.  The returned value is not
+ * necessarily the value passed to stp_set_forward_delay(): it is clamped to
+ * the valid range, quantized to the STP timer resolution, and adjusted to
+ * match the constraints due to the forward delay.  */
+int
+stp_get_forward_delay(const struct stp *stp)
+{
+    return timer_to_ms(stp->bridge_forward_delay);
+}
+
 /* Returns the port in 'stp' with index 'port_no', which must be between 0 and
  * STP_MAX_PORTS. */
 struct stp_port *
@@ -437,19 +518,25 @@ stp_state_name(enum stp_state state)
 }
 
 /* Returns true if 'state' is one in which packets received on a port should
- * be forwarded, false otherwise. */
+ * be forwarded, false otherwise.
+ *
+ * Returns true if 'state' is STP_DISABLED, since presumably in that case the
+ * port should still work, just not have STP applied to it. */
 bool
 stp_forward_in_state(enum stp_state state)
 {
-    return state == STP_FORWARDING;
+    return (state & (STP_DISABLED | STP_FORWARDING)) != 0;
 }
 
 /* Returns true if 'state' is one in which MAC learning should be done on
- * packets received on a port, false otherwise. */
+ * packets received on a port, false otherwise.
+ *
+ * Returns true if 'state' is STP_DISABLED, since presumably in that case the
+ * port should still work, just not have STP applied to it. */
 bool
 stp_learn_in_state(enum stp_state state)
 {
-    return state & (STP_LEARNING | STP_FORWARDING);
+    return (state & (STP_DISABLED | STP_LEARNING | STP_FORWARDING)) != 0;
 }
 
 /* Notifies the STP entity that bridge protocol data unit 'bpdu', which is
@@ -586,7 +673,7 @@ stp_port_set_priority(struct stp_port *p, uint8_t new_priority)
  * used to indicate faster links.  Use stp_port_set_speed() to automatically
  * generate a default path cost from a link speed. */
 void
-stp_port_set_path_cost(struct stp_port *p, unsigned int path_cost)
+stp_port_set_path_cost(struct stp_port *p, uint16_t path_cost)
 {
     if (p->path_cost != path_cost) {
         struct stp *stp = p->stp;
@@ -662,7 +749,7 @@ stp_transmit_config(struct stp_port *p)
         if (ntohs(config.message_age) < stp->max_age) {
             p->topology_change_ack = false;
             p->config_pending = false;
-            stp->send_bpdu(&config, sizeof config, stp_port_no(p), stp->aux);
+            stp_send_bpdu(p, &config, sizeof config);
             stp_start_timer(&p->hold_timer, 0);
         }
     }
@@ -735,7 +822,7 @@ stp_transmit_tcn(struct stp *stp)
     tcn_bpdu.header.protocol_id = htons(STP_PROTOCOL_ID);
     tcn_bpdu.header.protocol_version = STP_PROTOCOL_VERSION;
     tcn_bpdu.header.bpdu_type = STP_TYPE_TCN;
-    stp->send_bpdu(&tcn_bpdu, sizeof tcn_bpdu, stp_port_no(p), stp->aux);
+    stp_send_bpdu(p, &tcn_bpdu, sizeof tcn_bpdu);
 }
 
 static void
@@ -1081,3 +1168,78 @@ stp_timer_expired(struct stp_timer *timer, int elapsed, int timeout)
     return false;
 }
 
+/* Returns the number of whole STP timer ticks in 'ms' milliseconds.  There
+ * are 256 STP timer ticks per second. */
+static int
+ms_to_timer(int ms)
+{
+    return ms * 0x100 / 1000;
+}
+
+/* Returns the number of leftover milliseconds when 'ms' is converted to STP
+ * timer ticks. */
+static int
+ms_to_timer_remainder(int ms)
+{
+    return ms * 0x100 % 1000;
+}
+
+/* Returns the number of whole milliseconds in 'timer' STP timer ticks.  There
+ * are 256 STP timer ticks per second. */
+static int
+timer_to_ms(int timer)
+{
+    return timer * 1000 / 0x100;
+}
+
+static int
+clamp(int x, int min, int max)
+{
+    return x < min ? min : x > max ? max : x;
+}
+
+static void
+stp_update_bridge_timers(struct stp *stp)
+{
+    int ht, ma, fd;
+
+    ht = clamp(stp->rq_hello_time, 1000, 10000);
+    ma = clamp(stp->rq_max_age, MAX(2 * (ht + 1000), 6000), 40000);
+    fd = clamp(stp->rq_forward_delay, ma / 2 + 1000, 30000);
+
+    stp->bridge_hello_time = ms_to_timer(ht);
+    stp->bridge_max_age = ms_to_timer(ma);
+    stp->bridge_forward_delay = ms_to_timer(fd);
+
+    if (stp_is_root_bridge(stp)) {
+        stp->max_age = stp->bridge_max_age;
+        stp->hello_time = stp->bridge_hello_time;
+        stp->forward_delay = stp->bridge_forward_delay;
+    }
+}
+
+static void
+stp_send_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size)
+{
+    struct eth_header *eth;
+    struct llc_header *llc;
+    struct ofpbuf *pkt;
+
+    /* Skeleton. */
+    pkt = ofpbuf_new(ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size);
+    pkt->l2 = eth = ofpbuf_put_zeros(pkt, sizeof *eth);
+    llc = ofpbuf_put_zeros(pkt, sizeof *llc);
+    pkt->l3 = ofpbuf_put(pkt, bpdu, bpdu_size);
+
+    /* 802.2 header. */
+    memcpy(eth->eth_dst, stp_eth_addr, ETH_ADDR_LEN);
+    /* p->stp->send_bpdu() must fill in source address. */
+    eth->eth_type = htons(pkt->size - ETH_HEADER_LEN);
+
+    /* LLC header. */
+    llc->llc_dsap = STP_LLC_DSAP;
+    llc->llc_ssap = STP_LLC_SSAP;
+    llc->llc_cntl = STP_LLC_CNTL;
+
+    p->stp->send_bpdu(pkt, stp_port_no(p), p->stp->aux);
+}
index 5e09c2f167a898d7bde7b824810482d5103a27b7..a51c92f16e3846739429e1fb67d0fa5b8a7937c6 100644 (file)
--- a/lib/stp.h
+++ b/lib/stp.h
@@ -42,6 +42,8 @@
 #include "compiler.h"
 #include "util.h"
 
+struct ofpbuf;
+
 /* Ethernet address used as the destination for STP frames. */
 extern const uint8_t stp_eth_addr[6];
 
@@ -50,6 +52,10 @@ extern const uint8_t stp_eth_addr[6];
 #define STP_LLC_DSAP 0x42
 #define STP_LLC_CNTL 0x03
 
+/* Bridge and port priorities that should be used by default. */
+#define STP_DEFAULT_BRIDGE_PRIORITY 32768
+#define STP_DEFAULT_PORT_PRIORITY 128
+
 /* Bridge identifier.  Top 16 bits are a priority value (numerically lower
  * values are higher priorities).  Bottom 48 bits are MAC address of bridge. */
 typedef uint64_t stp_identifier;
@@ -57,13 +63,16 @@ typedef uint64_t stp_identifier;
 /* Basic STP functionality. */
 #define STP_MAX_PORTS 255
 struct stp *stp_create(const char *name, stp_identifier bridge_id,
-                       void (*send_bpdu)(const void *bpdu, size_t bpdu_size,
-                                         int port_no, void *aux),
+                       void (*send_bpdu)(struct ofpbuf *bpdu, int port_no,
+                                         void *aux),
                        void *aux);
 void stp_destroy(struct stp *);
-void stp_tick(struct stp *, int elapsed);
+void stp_tick(struct stp *, int ms);
 void stp_set_bridge_id(struct stp *, stp_identifier bridge_id);
 void stp_set_bridge_priority(struct stp *, uint16_t new_priority);
+void stp_set_hello_time(struct stp *, int ms);
+void stp_set_max_age(struct stp *, int ms);
+void stp_set_forward_delay(struct stp *, int ms);
 
 /* STP properties. */
 const char *stp_get_name(const struct stp *);
@@ -71,6 +80,9 @@ stp_identifier stp_get_bridge_id(const struct stp *);
 stp_identifier stp_get_designated_root(const struct stp *);
 bool stp_is_root_bridge(const struct stp *);
 int stp_get_root_path_cost(const struct stp *);
+int stp_get_hello_time(const struct stp *);
+int stp_get_max_age(const struct stp *);
+int stp_get_forward_delay(const struct stp *);
 
 /* Obtaining STP ports. */
 struct stp_port *stp_get_port(struct stp *, int port_no);
@@ -100,7 +112,7 @@ enum stp_state stp_port_get_state(const struct stp_port *);
 void stp_port_enable(struct stp_port *);
 void stp_port_disable(struct stp_port *);
 void stp_port_set_priority(struct stp_port *, uint8_t new_priority);
-void stp_port_set_path_cost(struct stp_port *, unsigned int path_cost);
+void stp_port_set_path_cost(struct stp_port *, uint16_t path_cost);
 void stp_port_set_speed(struct stp_port *, unsigned int speed);
 void stp_port_enable_change_detection(struct stp_port *);
 void stp_port_disable_change_detection(struct stp_port *);
index 97ad02bbc1b658929edbcbf9e3721b6646cd4ee5..9ded73b6e3b5cc3a8135f66a67da5c3831f9afbd 100644 (file)
@@ -54,7 +54,7 @@ struct stp_data {
     struct port_watcher *pw;
     struct rconn *local_rconn;
     struct rconn *remote_rconn;
-    long long int last_tick_256ths;
+    long long int last_tick;
     int n_txq;
 };
 
@@ -126,18 +126,12 @@ stp_local_packet_cb(struct relay *r, void *stp_)
     return true;
 }
 
-static long long int
-time_256ths(void)
-{
-    return time_msec() * 256 / 1000;
-}
-
 static void
 stp_periodic_cb(void *stp_)
 {
     struct stp_data *stp = stp_;
-    long long int now_256ths = time_256ths();
-    long long int elapsed_256ths = now_256ths - stp->last_tick_256ths;
+    long long int now = time_msec();
+    long long int elapsed = now - stp->last_tick;
     struct stp_port *p;
 
     if (!port_watcher_is_ready(stp->pw)) {
@@ -145,12 +139,12 @@ stp_periodic_cb(void *stp_)
          * disable STP. */
         return;
     }
-    if (elapsed_256ths <= 0) {
+    if (elapsed <= 0) {
         return;
     }
 
-    stp_tick(stp->stp, MIN(INT_MAX, elapsed_256ths));
-    stp->last_tick_256ths = now_256ths;
+    stp_tick(stp->stp, MIN(INT_MAX, elapsed));
+    stp->last_tick = now;
 
     while (stp_get_changed_port(stp->stp, &p)) {
         int port_no = stp_port_no(p);
@@ -202,39 +196,22 @@ stp_wait_cb(void *stp_ UNUSED)
 }
 
 static void
-send_bpdu(const void *bpdu, size_t bpdu_size, int port_no, void *stp_)
+send_bpdu(struct ofpbuf *pkt, int port_no, void *stp_)
 {
     struct stp_data *stp = stp_;
-    const uint8_t *port_mac;
-    struct eth_header *eth;
-    struct llc_header *llc;
-    struct ofpbuf pkt, *opo;
+    const uint8_t *port_mac = port_watcher_get_hwaddr(stp->pw, port_no);
+    if (port_mac) {
+        struct eth_header *eth = pkt->l2;
+        struct ofpbuf *opo;
+
+        memcpy(eth->eth_src, port_mac, ETH_ADDR_LEN);
+        opo = make_unbuffered_packet_out(pkt, OFPP_NONE, port_no);
 
-    port_mac = port_watcher_get_hwaddr(stp->pw, port_no);
-    if (!port_mac) {
+        rconn_send_with_limit(stp->local_rconn, opo, &stp->n_txq, OFPP_MAX);
+    } else {
         VLOG_WARN_RL(&rl, "cannot send BPDU on missing port %d", port_no);
-        return;
     }
-
-    /* Packet skeleton. */
-    ofpbuf_init(&pkt, ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size);
-    eth = ofpbuf_put_uninit(&pkt, sizeof *eth);
-    llc = ofpbuf_put_uninit(&pkt, sizeof *llc);
-    ofpbuf_put(&pkt, bpdu, bpdu_size);
-
-    /* 802.2 header. */
-    memcpy(eth->eth_dst, stp_eth_addr, ETH_ADDR_LEN);
-    memcpy(eth->eth_src, port_mac, ETH_ADDR_LEN);
-    eth->eth_type = htons(pkt.size - ETH_HEADER_LEN);
-
-    /* LLC header. */
-    llc->llc_dsap = STP_LLC_DSAP;
-    llc->llc_ssap = STP_LLC_SSAP;
-    llc->llc_cntl = STP_LLC_CNTL;
-
-    opo = make_unbuffered_packet_out(&pkt, OFPP_NONE, port_no);
-    ofpbuf_uninit(&pkt);
-    rconn_send_with_limit(stp->local_rconn, opo, &stp->n_txq, OFPP_MAX);
+    ofpbuf_delete(pkt);
 }
 
 static bool
@@ -308,7 +285,7 @@ stp_start(struct secchan *secchan, const struct settings *s,
     stp->pw = pw;
     stp->local_rconn = local;
     stp->remote_rconn = remote;
-    stp->last_tick_256ths = time_256ths();
+    stp->last_tick = time_msec();
 
     port_watcher_register_callback(pw, stp_port_changed_cb, stp);
     port_watcher_register_local_port_callback(pw, stp_local_port_changed_cb,
index 88aedb42f738787a7ba30804aa16c3acde1dc557..f1982a03e3a7ae4bf0cf29047b79b3e434ca4e6c 100644 (file)
@@ -4,7 +4,7 @@ bridge 1 0x97 = c:5 a d:5
 bridge 2 0x45 = b e
 bridge 3 0x57 = b:5 e:5
 bridge 4 0x83 = a:5 e:5
-run 256
+run 1000
 check 0 = root
 check 1 = F F:10 F
 check 2 = F:10 B
index 29b13ff833320dea05af9c0c896a7735758ec9bd..1f708630ade7c90dc9e89183ba0e5ca7275a9cdc 100644 (file)
@@ -7,7 +7,7 @@ bridge 4 0x555 = g i 0 0
 bridge 5 0x666 = h k 0 0
 bridge 6 0x777 = j m 0 0
 bridge 7 0x888 = l n 0 0
-run 256
+run 1000
 check 0 = root
 check 1 = F:10 B F F
 check 2 = F:10 B F F F F
@@ -20,7 +20,7 @@ check 7 = F:20 B F F
 # Now connect two ports of bridge 7 to the same LAN.
 bridge 7 = l n o o
 # Same results except for bridge 7:
-run 256
+run 1000
 check 0 = root
 check 1 = F:10 B F F
 check 2 = F:10 B F F F F
index 694d2383ff64feccd65be1661f48fd9488359e1e..6ed59177e64873b94026bc7ff34f9c6e98bcef28 100644 (file)
@@ -5,7 +5,7 @@ bridge 2 0x333 = d e f
 bridge 3 0x444 = f g h
 bridge 4 0x555 = j h i
 bridge 5 0x666 = l j k
-run 256
+run 1000
 check 0 = root
 check 1 = F:10 F F
 check 2 = F:20 F F
index 278655e28ea2564a0d9abbfdd58759eeb2367ea3..daa0cdf2f27072a67114f8ee281fe5d3a9cd650f 100644 (file)
@@ -2,7 +2,7 @@
 bridge 0 0xaa = b
 bridge 1 0x111 = a b d f h g e c
 bridge 2 0x222 = g h j l n m k i
-run 256
+run 1000
 check 0 = root
 check 1 = F F:10 F F F F F F
 check 2 = B F:20 F F F F F F
@@ -11,7 +11,7 @@ check 2 = B F:20 F F F F F F
 # but I don't understand what port priority change would cause
 # that change.
 bridge 2 = g X j l n m k i
-run 256
+run 1000
 check 0 = root
 check 1 = F F:10 F F F F F F
 check 2 = F:20 D F F F F F F
index 1b53fedba9fe3a05d536cb92a8ad72a837a30e5f..186d6c4cf914c7129a98e00f21050c226dc7c6e4 100644 (file)
@@ -4,22 +4,22 @@
 # STP.io.1.1: Link Failure
 bridge 0 0x111 = a b c
 bridge 1 0x222 = a b c
-run 256
+run 1000
 check 0 = root
 check 1 = F:10 B B
 bridge 1 = 0 _ _
-run 256
+run 1000
 check 0 = root
 check 1 = F F:10 B
 bridge 1 = X _ _
-run 256
+run 1000
 check 0 = root
 check 1 = D F:10 B
 bridge 1 = _ 0 _
-run 256
+run 1000
 check 0 = root
 check 1 = D F F:10
 bridge 1 = _ X _
-run 256
+run 1000
 check 0 = root
 check 1 = D D F:10
index a2ed48cb4aff40fda917d85742f620908db22efb..285bbd886afccc95e43abb3b3d65d166cc9d0b74 100644 (file)
@@ -4,11 +4,11 @@
 # STP.io.1.2: Repeated Network
 bridge 0 0x111 = a a
 bridge 1 0x222 = a a
-run 256
+run 1000
 check 0 = rootid:0x111 F B
 check 1 = rootid:0x111 F:10 B
 bridge 1 = a^0x90 _
-run 256
+run 1000
 check 0 = rootid:0x111 F B
 check 1 = rootid:0x111 B F:10
 
index f8b0b722a37fce671ded44cb56144614a6028058..0065aaf5c8f80d59a027f723cac3192bf4ffdaa5 100644 (file)
@@ -6,7 +6,7 @@ bridge 0 0x111 = a b c
 bridge 1 0x222 = b d e
 bridge 2 0x333 = a d f
 bridge 3 0x444 = c e f
-run 256
+run 1000
 check 0 = root
 check 1 = F:10 F F
 check 2 = F:10 B F
index c5f08b8ed02a42b32f38ba305ff0fde1990455ac..285d29deae492b1dce3f32f884a07a9721b9970e 100644 (file)
@@ -6,25 +6,25 @@ bridge 0 0x111 = a b d c
 bridge 1 0x222 = a b f e
 bridge 2 0x333 = c d g h
 bridge 3 0x444 = e f g h
-run 256
+run 1000
 check 0 = root
 check 1 = F:10 B F F
 check 2 = B F:10 F F
 check 3 = B F:20 B B
 bridge 1^0x7000
-run 256
+run 1000
 check 0 = F:10 B F F
 check 1 = root
 check 2 = B F:20 B B
 check 3 = B F:10 F F
 bridge 2^0x6000
-run 256
+run 1000
 check 0 = F F B F:10
 check 1 = F:20 B B B
 check 2 = root
 check 3 = F F F:10 B
 bridge 3^0x5000
-run 256
+run 1000
 check 0 = B B B F:20
 check 1 = F F B F:10
 check 2 = F F F:10 B
@@ -33,7 +33,7 @@ bridge 0^0x4000
 bridge 1^0x4001
 bridge 2^0x4002
 bridge 3^0x4003
-run 256
+run 1000
 check 0 = root
 check 1 = F:10 B F F
 check 2 = B F:10 F F
index 18c09b897c50f6a0fa29c7922253f1abafd9184a..6a1211647e2bdb54aad92bf45b1204ba70d7b5e6 100644 (file)
@@ -4,5 +4,5 @@
 # Test STP.op.1.4 ­ All Ports Initialized to Designated Ports
 bridge 0 0x123 = a b c d e f
 check 0 = Li Li Li Li Li Li
-run 256
+run 1000
 check 0 = F F F F F F
index 2e0a2f2cf2539466fc1704113b508b476408c0c1..3e1099cbb5de82fac2ccab67eef0052cb975d05f 100644 (file)
@@ -6,6 +6,6 @@ bridge 0 0x111 = a
 bridge 1 0x222 = a
 check 0 = rootid:0x111 Li
 check 1 = rootid:0x222 Li
-run 256
+run 1000
 check 0 = rootid:0x111 root
 check 1 = rootid:0x111 F:10
index 093c64edc22d3f3da8eabb798b3dcea9cb764224..2bcd45e1eb5c0afd341a367b00b7920a7bc72ffa 100644 (file)
@@ -5,7 +5,7 @@
 bridge 0 0x333^0x6000 = a
 bridge 1 0x222^0x7000 = b
 bridge 2 0x111 = a b
-run 256
+run 1000
 check 0 = rootid:0x333^0x6000 root
 check 1 = rootid:0x333^0x6000 F:20
 check 2 = rootid:0x333^0x6000 F:10 F
index 093c64edc22d3f3da8eabb798b3dcea9cb764224..2bcd45e1eb5c0afd341a367b00b7920a7bc72ffa 100644 (file)
@@ -5,7 +5,7 @@
 bridge 0 0x333^0x6000 = a
 bridge 1 0x222^0x7000 = b
 bridge 2 0x111 = a b
-run 256
+run 1000
 check 0 = rootid:0x333^0x6000 root
 check 1 = rootid:0x333^0x6000 F:20
 check 2 = rootid:0x333^0x6000 F:10 F
index 9b87c0e633096f7c965aee90c898bb0872a4b7a1..ddb7db7e00c6990c227187a6a2761caed5799c9c 100644 (file)
@@ -38,6 +38,7 @@
 #include <inttypes.h>
 #include <stdarg.h>
 #include <stdlib.h>
+#include "ofpbuf.h"
 #include "packets.h"
 
 struct bpdu {
@@ -97,28 +98,31 @@ new_test_case(void)
 }
 
 static void
-send_bpdu(const void *data, size_t size, int port_no, void *b_)
+send_bpdu(struct ofpbuf *pkt, int port_no, void *b_)
 {
     struct bridge *b = b_;
     struct lan *lan;
-    int i;
 
     assert(port_no < b->n_ports);
     lan = b->ports[port_no];
-    if (!lan) {
-        return;
-    }
-    for (i = 0; i < lan->n_conns; i++) {
-        struct lan_conn *conn = &lan->conns[i];
-        if (conn->bridge != b || conn->port_no != port_no) {
-            struct bridge *dst = conn->bridge;
-            struct bpdu *bpdu = &dst->rxq[dst->rxq_head++ % RXQ_SIZE];
-            assert(dst->rxq_head - dst->rxq_tail <= RXQ_SIZE);
-            bpdu->data = xmemdup(data, size);
-            bpdu->size = size;
-            bpdu->port_no = conn->port_no;
+    if (lan) {
+        const void *data = pkt->l3;
+        size_t size = (char *) ofpbuf_tail(pkt) - (char *) data;
+        int i;
+
+        for (i = 0; i < lan->n_conns; i++) {
+            struct lan_conn *conn = &lan->conns[i];
+            if (conn->bridge != b || conn->port_no != port_no) {
+                struct bridge *dst = conn->bridge;
+                struct bpdu *bpdu = &dst->rxq[dst->rxq_head++ % RXQ_SIZE];
+                assert(dst->rxq_head - dst->rxq_tail <= RXQ_SIZE);
+                bpdu->data = xmemdup(data, size);
+                bpdu->size = size;
+                bpdu->port_no = conn->port_no;
+            }
         }
     }
+    ofpbuf_delete(pkt);
 }
 
 static struct bridge *
@@ -299,7 +303,7 @@ simulate(struct test_case *tc, int granularity)
 {
     int time;
 
-    for (time = 0; time < 256 * 180; time += granularity) {
+    for (time = 0; time < 1000 * 180; time += granularity) {
         int round_trips;
         int i;