- Don't apply endian conversions to flags, which are 8 bits.
- Use #defines for default times for use outside library.
- Clarify our behavior when in STP_DISABLED state.
- Add "aux" member to STP port struct to be able to refer back to
the owning port.
- Define macros to print STP bridge and port ids.
- New helper function to get port id.
- New helper function to convert speed to cost.
- New functions to describe current role of port.
---
lib/stp.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------
lib/stp.h | 41 +++++++++++++++++++++++++-
2 files changed, 120 insertions(+), 16 deletions(-)
diff --git a/lib/stp.c b/lib/stp.c
index f58d640..d67cd0e 100644
--- a/lib/stp.c
+++ b/lib/stp.c
@@ -77,6 +77,7 @@ struct stp_timer {
struct stp_port {
struct stp *stp;
+ void *aux; /* Auxiliary data the user may retrieve. */
int port_id; /* 8.5.5.1: Unique port identifier. */
enum stp_state state; /* 8.5.5.2: Current state. */
int path_cost; /* 8.5.5.3: Cost of tx/rx on this port. */
@@ -223,9 +224,9 @@ stp_create(const char *name, stp_identifier bridge_id,
stp->bridge_id |= (uint64_t) STP_DEFAULT_BRIDGE_PRIORITY << 48;
}
- stp->rq_max_age = 6000;
- stp->rq_hello_time = 2000;
- stp->rq_forward_delay = 4000;
+ stp->rq_max_age = STP_DEFAULT_MAX_AGE;
+ stp->rq_hello_time = STP_DEFAULT_HELLO_TIME;
+ stp->rq_forward_delay = STP_DEFAULT_FWD_DELAY;
stp_update_bridge_timers(stp);
stp->max_age = stp->bridge_max_age;
stp->hello_time = stp->bridge_hello_time;
@@ -526,6 +527,23 @@ stp_learn_in_state(enum stp_state state)
return (state & (STP_DISABLED | STP_LEARNING | STP_FORWARDING)) != 0;
}
+/* Returns the name for the given 'role' (for use in debugging and log
+ * messages). */
+const char *
+stp_role_name(enum stp_role role)
+{
+ switch (role) {
+ case STP_ROLE_ROOT:
+ return "root";
+ case STP_ROLE_DESIGNATED:
+ return "designated";
+ case STP_ROLE_ALTERNATE:
+ return "alternate";
+ default:
+ NOT_REACHED();
+ }
+}
+
/* Notifies the STP entity that bridge protocol data unit 'bpdu', which is
* 'bpdu_size' bytes in length, was received on port 'p'.
*
@@ -589,6 +607,24 @@ stp_port_get_stp(struct stp_port *p)
return p->stp;
}
+/* Sets the 'aux' member of 'p'.
+ *
+ * The 'aux' member will be reset to NULL when stp_port_disable() is
+ * called or stp_port_enable() is called when the port is in a Disabled
+ * state. */
+void
+stp_port_set_aux(struct stp_port *p, void *aux)
+{
+ p->aux = aux;
+}
+
+/* Returns the 'aux' member of 'p'. */
+void *
+stp_port_get_aux(struct stp_port *p)
+{
+ return p->aux;
+}
+
/* Returns the index of port 'p' within its bridge. */
int
stp_port_no(const struct stp_port *p)
@@ -598,6 +634,13 @@ stp_port_no(const struct stp_port *p)
return p - stp->ports;
}
+/* Returns the port ID for 'p'. */
+int
+stp_port_get_id(const struct stp_port *p)
+{
+ return p->port_id;
+}
+
/* Returns the state of port 'p'. */
enum stp_state
stp_port_get_state(const struct stp_port *p)
@@ -605,6 +648,21 @@ stp_port_get_state(const struct stp_port *p)
return p->state;
}
+/* Returns the role of port 'p'. */
+enum stp_role
+stp_port_get_role(const struct stp_port *p)
+{
+ struct stp_port *root_port = stp_get_root_port(p->stp);
+
+ if (root_port && root_port->port_id == p->port_id) {
+ return STP_ROLE_ROOT;
+ } else if (stp_is_designated_port(p)) {
+ return STP_ROLE_DESIGNATED;
+ } else {
+ return STP_ROLE_ALTERNATE;
+ }
+}
+
/* Disables STP on port 'p'. */
void
stp_port_disable(struct stp_port *p)
@@ -623,6 +681,7 @@ stp_port_disable(struct stp_port *p)
if (stp_is_root_bridge(stp) && !root) {
stp_become_root_bridge(stp);
}
+ p->aux = NULL;
}
}
@@ -656,6 +715,19 @@ stp_port_set_priority(struct stp_port *p, uint8_t
new_priority)
}
}
+/* Convert 'speed' (measured in Mb/s) into the path cost. */
+uint16_t
+stp_convert_speed_to_cost(unsigned int speed)
+{
+ return speed >= 10000 ? 2 /* 10 Gb/s. */
+ : speed >= 1000 ? 4 /* 1 Gb/s. */
+ : speed >= 100 ? 19 /* 100 Mb/s. */
+ : speed >= 16 ? 62 /* 16 Mb/s. */
+ : speed >= 10 ? 100 /* 10 Mb/s. */
+ : speed >= 4 ? 250 /* 4 Mb/s. */
+ : 19; /* 100 Mb/s (guess). */
+}
+
/* Sets the path cost of port 'p' to 'path_cost'. Lower values are generally
* used to indicate faster links. Use stp_port_set_speed() to automatically
* generate a default path cost from a link speed. */
@@ -674,13 +746,7 @@ stp_port_set_path_cost(struct stp_port *p, uint16_t
path_cost)
void
stp_port_set_speed(struct stp_port *p, unsigned int speed)
{
- stp_port_set_path_cost(p, (speed >= 10000 ? 2 /* 10 Gb/s. */
- : speed >= 1000 ? 4 /* 1 Gb/s. */
- : speed >= 100 ? 19 /* 100 Mb/s. */
- : speed >= 16 ? 62 /* 16 Mb/s. */
- : speed >= 10 ? 100 /* 10 Mb/s. */
- : speed >= 4 ? 250 /* 4 Mb/s. */
- : 19)); /* 100 Mb/s (guess). */
+ stp_port_set_path_cost(p, stp_convert_speed_to_cost(speed));
}
/* Enables topology change detection on port 'p'. */
@@ -715,10 +781,10 @@ stp_transmit_config(struct stp_port *p)
config.header.bpdu_type = STP_TYPE_CONFIG;
config.flags = 0;
if (p->topology_change_ack) {
- config.flags |= htons(STP_CONFIG_TOPOLOGY_CHANGE_ACK);
+ config.flags |= STP_CONFIG_TOPOLOGY_CHANGE_ACK;
}
if (stp->topology_change) {
- config.flags |= htons(STP_CONFIG_TOPOLOGY_CHANGE);
+ config.flags |= STP_CONFIG_TOPOLOGY_CHANGE;
}
config.root_id = htonll(stp->designated_root);
config.root_path_cost = htonl(stp->root_path_cost);
@@ -776,7 +842,7 @@ stp_record_config_timeout_values(struct stp *stp,
stp->max_age = ntohs(config->max_age);
stp->hello_time = ntohs(config->hello_time);
stp->forward_delay = ntohs(config->forward_delay);
- stp->topology_change = config->flags & htons(STP_CONFIG_TOPOLOGY_CHANGE);
+ stp->topology_change = config->flags & STP_CONFIG_TOPOLOGY_CHANGE;
}
static bool
@@ -1004,7 +1070,7 @@ stp_received_config_bpdu(struct stp *stp, struct stp_port
*p,
if (p == stp->root_port) {
stp_record_config_timeout_values(stp, config);
stp_config_bpdu_generation(stp);
- if (config->flags & htons(STP_CONFIG_TOPOLOGY_CHANGE_ACK)) {
+ if (config->flags & STP_CONFIG_TOPOLOGY_CHANGE_ACK) {
stp_topology_change_acknowledged(stp);
}
}
@@ -1111,6 +1177,7 @@ stp_initialize_port(struct stp_port *p, enum stp_state
state)
p->topology_change_ack = false;
p->config_pending = false;
p->change_detection_enabled = true;
+ p->aux = NULL;
stp_stop_timer(&p->message_age_timer);
stp_stop_timer(&p->forward_delay_timer);
stp_stop_timer(&p->hold_timer);
diff --git a/lib/stp.h b/lib/stp.h
index 3ea1e1c..8dbe41f 100644
--- a/lib/stp.h
+++ b/lib/stp.h
@@ -36,10 +36,28 @@ struct ofpbuf;
#define STP_DEFAULT_BRIDGE_PRIORITY 32768
#define STP_DEFAULT_PORT_PRIORITY 128
+/* Default time values. */
+#define STP_DEFAULT_MAX_AGE 20000
+#define STP_DEFAULT_HELLO_TIME 2000
+#define STP_DEFAULT_FWD_DELAY 15000
+
/* 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;
+
+#define STP_ID_FMT \
+
"%02"PRIx8"%02"PRIx8".%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8
+#define STP_ID_ARGS(stp_id) \
+ (uint8_t)(stp_id >> 56), (uint8_t)(stp_id >> 48), \
+ (uint8_t)(stp_id >> 40), (uint8_t)(stp_id >> 32), \
+ (uint8_t)(stp_id >> 24), (uint8_t)(stp_id >> 16), \
+ (uint8_t)(stp_id >> 8), (uint8_t)(stp_id)
+
+#define STP_PORT_ID_FMT "%02"PRIx8"%02"PRIx8
+#define STP_PORT_ID_ARGS(stp_port_id) \
+ (uint8_t)(stp_port_id >> 8), (uint8_t)(stp_port_id)
+
/* Basic STP functionality. */
#define STP_MAX_PORTS 255
struct stp *stp_create(const char *name, stp_identifier bridge_id,
@@ -72,9 +90,16 @@ bool stp_get_changed_port(struct stp *, struct stp_port
**portp);
/* State of an STP port.
*
* A port is in exactly one state at any given time, but distinct bits are used
- * for states to allow testing for more than one state with a bit mask. */
+ * for states to allow testing for more than one state with a bit mask.
+ *
+ * The STP_DISABLED state means that the port is disabled by management.
+ * In our implementation, this state means that the port does not
+ * participate in the spanning tree, but it still forwards traffic as if
+ * it were in the STP_FORWARDING state. This may be different from
+ * other implementations.
+ */
enum stp_state {
- STP_DISABLED = 1 << 0, /* 8.4.5: Disabled by management. */
+ STP_DISABLED = 1 << 0, /* 8.4.5: See note above. */
STP_LISTENING = 1 << 1, /* 8.4.2: Not learning or relaying frames. */
STP_LEARNING = 1 << 2, /* 8.4.3: Learning but not relaying frames. */
STP_FORWARDING = 1 << 3, /* 8.4.4: Learning and relaying frames. */
@@ -84,14 +109,26 @@ const char *stp_state_name(enum stp_state);
bool stp_forward_in_state(enum stp_state);
bool stp_learn_in_state(enum stp_state);
+enum stp_role {
+ STP_ROLE_ROOT,
+ STP_ROLE_DESIGNATED,
+ STP_ROLE_ALTERNATE
+};
+const char *stp_role_name(enum stp_role);
+
void stp_received_bpdu(struct stp_port *, const void *bpdu, size_t bpdu_size);
struct stp *stp_port_get_stp(struct stp_port *);
+void stp_port_set_aux(struct stp_port *, void *);
+void *stp_port_get_aux(struct stp_port *);
int stp_port_no(const struct stp_port *);
+int stp_port_get_id(const struct stp_port *);
enum stp_state stp_port_get_state(const struct stp_port *);
+enum stp_role stp_port_get_role(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);
+uint16_t stp_convert_speed_to_cost(unsigned int speed);
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 *);
--
1.7.1
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev