testsuite: Add timeout to add_of_br() command.
[cascardo/ovs.git] / lib / rstp-state-machines.c
index ab3443e..9768e46 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2014 M3S, Srl - Italy
+ * Copyright (c) 2011-2015 M3S, Srl - Italy
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
  * Authors:
  *         Martino Fornasa <mf@fornasa.it>
  *         Daniele Venturino <daniele.venturino@m3s.it>
+ *         Carlo Andreotti <c.andreotti@m3s.it>
  *
  * References to IEEE 802.1D-2004 standard are enclosed in square brackets.
  * E.g. [17.3], [Table 17-1], etc.
 #include "byte-order.h"
 #include "connectivity.h"
 #include "ofpbuf.h"
+#include "dp-packet.h"
 #include "packets.h"
 #include "seq.h"
 #include "unixctl.h"
 #include "util.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(rstp_sm);
 
@@ -689,19 +691,19 @@ rstp_send_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size)
 {
     struct eth_header *eth;
     struct llc_header *llc;
-    struct ofpbuf *pkt;
+    struct dp_packet *pkt;
 
     /* Skeleton. */
-    pkt = ofpbuf_new(ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size);
-    eth = ofpbuf_put_zeros(pkt, sizeof *eth);
-    llc = ofpbuf_put_zeros(pkt, sizeof *llc);
-    ofpbuf_set_frame(pkt, eth);
-    ofpbuf_set_l3(pkt, ofpbuf_put(pkt, bpdu, bpdu_size));
+    pkt = dp_packet_new(ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size);
+    eth = dp_packet_put_zeros(pkt, sizeof *eth);
+    llc = dp_packet_put_zeros(pkt, sizeof *llc);
+    dp_packet_reset_offsets(pkt);
+    dp_packet_set_l3(pkt, dp_packet_put(pkt, bpdu, bpdu_size));
 
     /* 802.2 header. */
-    memcpy(eth->eth_dst, eth_addr_stp, ETH_ADDR_LEN);
+    eth->eth_dst = eth_addr_stp;
     /* p->rstp->send_bpdu() must fill in source address. */
-    eth->eth_type = htons(ofpbuf_size(pkt) - ETH_HEADER_LEN);
+    eth->eth_type = htons(dp_packet_size(pkt) - ETH_HEADER_LEN);
 
     /* LLC header. */
     llc->llc_dsap = STP_LLC_DSAP;
@@ -755,8 +757,11 @@ record_dispute(struct rstp_port *p)
     OVS_REQUIRES(rstp_mutex)
 {
     if ((p->received_bpdu_buffer.flags & BPDU_FLAG_LEARNING) != 0) {
-        p->agreed = true;
-        p->proposing = false;
+        /* 802.1D-2004 says to set the agreed flag and to clear the proposing
+         * flag. 802.1q-2008 instead says to set the disputed variable and to
+         * clear the agreed variable. */
+        p->disputed = true;
+        p->agreed = false;
     }
 }
 
@@ -1134,6 +1139,7 @@ port_information_sm(struct rstp_port *p)
 {
     enum port_information_state_machine old_state;
     struct rstp *r;
+    struct rstp_port *p1;
 
     old_state = p->port_information_sm_state;
     r = p->rstp;
@@ -1233,6 +1239,19 @@ port_information_sm(struct rstp_port *p)
         } else {
             switch (p->rcvd_info) {
             case SUPERIOR_DESIGNATED_INFO:
+                /* 802.1q-2008 has a checkBPDUConsistency() function, called on
+                 * a BPDU reception.  checkBPDUConsistency() clears the agreed
+                 * variable if the received message priority vector is superior
+                 * to the port priority vector, the BPDU is an ST BPDU or an
+                 * RST BPDU, its port role is Designated and its Learning flag
+                 * is set. */
+                if (p->received_bpdu_buffer.flags & BPDU_FLAG_LEARNING) {
+                    HMAP_FOR_EACH (p1, node, &r->ports) {
+                        if (p1->port_number != p->port_number) {
+                            p1->agreed = false;
+                        }
+                    }
+                }
                 p->port_information_sm_state =
                     PORT_INFORMATION_SM_SUPERIOR_DESIGNATED_EXEC;
                 break;
@@ -1299,6 +1318,9 @@ port_information_sm(struct rstp_port *p)
     case PORT_INFORMATION_SM_REPEATED_DESIGNATED_EXEC:
         record_proposal(p);
         set_tc_flags(p);
+        /* This record_agreement() is missing in 802.1D-2004, but it's present
+         * in 802.1q-2008. */
+        record_agreement(p);
         updt_rcvd_info_while(p);
         p->rcvd_msg = false;
         p->port_information_sm_state = PORT_INFORMATION_SM_REPEATED_DESIGNATED;
@@ -1317,6 +1339,10 @@ port_information_sm(struct rstp_port *p)
         set_tc_flags(p);
         /* RECEIVED is not specified in Standard 802.1D-2004. */
         p->agree = p->agree && better_or_same_info(p, RECEIVED);
+        /* This record_agreement() and the synced assignment are  missing in
+         * 802.1D-2004, but they're present in 802.1q-2008. */
+        record_agreement(p);
+        p->synced = p->synced && p->agreed;
         record_priority(p);
         record_times(p);
         updt_rcvd_info_while(p);
@@ -1833,7 +1859,6 @@ port_role_transition_sm(struct rstp_port *p)
                  p->port_role_transition_sm_state);
     }
     if (last_role != p->role) {
-        last_role = p->role;
         VLOG_DBG("%s, port %u, port role ["RSTP_PORT_ID_FMT"] = %s",
                  p->rstp->name, p->port_number, p->port_id,
                  rstp_port_role_name(p->role));