/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "byte-order.h"
#include "ofpbuf.h"
#include "packets.h"
+#include "unixctl.h"
#include "util.h"
#include "vlog.h"
};
struct stp {
+ struct list node; /* Node in all_stps list. */
+
/* Static bridge data. */
char *name; /* Human-readable name for log messages. */
stp_identifier bridge_id; /* 8.5.3.7: This bridge. */
void *aux;
};
+static struct list all_stps = LIST_INITIALIZER(&all_stps);
+
#define FOR_EACH_ENABLED_PORT(PORT, STP) \
for ((PORT) = stp_next_enabled_port((STP), (STP)->ports); \
(PORT); \
{
for (; port < &stp->ports[ARRAY_SIZE(stp->ports)]; port++) {
if (port->state != STP_DISABLED) {
- return (struct stp_port *) port;
+ return CONST_CAST(struct stp_port *, port);
}
}
return NULL;
static bool stp_timer_expired(struct stp_timer *, int elapsed, int timeout);
static void stp_send_bpdu(struct stp_port *, const void *, size_t);
+static void stp_unixctl_tcn(struct unixctl_conn *, int argc,
+ const char *argv[], void *aux);
+
+void
+stp_init(void)
+{
+ unixctl_command_register("stp/tcn", "[bridge]", 0, 1, stp_unixctl_tcn,
+ NULL);
+}
/* Creates and returns a new STP instance that initially has no ports enabled.
*
p->path_cost = 19; /* Recommended default for 100 Mb/s link. */
stp_initialize_port(p, STP_DISABLED);
}
+ list_push_back(&all_stps, &stp->node);
return stp;
}
stp_destroy(struct stp *stp)
{
if (stp) {
+ list_remove(&stp->node);
free(stp->name);
free(stp);
}
static void
stp_topology_change_detection(struct stp *stp)
{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
if (stp_is_root_bridge(stp)) {
stp->topology_change = true;
stp_start_timer(&stp->topology_change_timer, 0);
}
stp->fdb_needs_flush = true;
stp->topology_change_detected = true;
+ VLOG_INFO_RL(&rl, "%s: detected topology change.", stp->name);
}
static void
p->stp->send_bpdu(pkt, stp_port_no(p), p->stp->aux);
p->tx_count++;
}
+\f
+/* Unixctl. */
+
+static struct stp *
+stp_find(const char *name)
+{
+ struct stp *stp;
+
+ LIST_FOR_EACH (stp, node, &all_stps) {
+ if (!strcmp(stp->name, name)) {
+ return stp;
+ }
+ }
+ return NULL;
+}
+
+static void
+stp_unixctl_tcn(struct unixctl_conn *conn, int argc,
+ const char *argv[], void *aux OVS_UNUSED)
+{
+ if (argc > 1) {
+ struct stp *stp = stp_find(argv[1]);
+
+ if (!stp) {
+ unixctl_command_reply_error(conn, "no such stp object");
+ return;
+ }
+ stp_topology_change_detection(stp);
+ } else {
+ struct stp *stp;
+
+ LIST_FOR_EACH (stp, node, &all_stps) {
+ stp_topology_change_detection(stp);
+ }
+ }
+
+ unixctl_command_reply(conn, "OK");
+}