summaryrefslogtreecommitdiff
path: root/lib/learning-switch.c
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2010-08-11 17:24:13 -0700
committerBen Pfaff <blp@nicira.com>2010-08-13 09:47:27 -0700
commitba186119ca5f787486189c041d76d63dee629dc1 (patch)
tree5afa34bcffec89395a752d937c5e4c1b1a67f68f /lib/learning-switch.c
parent10df718e73122df2f3b04ed585e50e4b299a8cbd (diff)
downloadopenvswitch-ba186119ca5f787486189c041d76d63dee629dc1.tar.gz
Remove vestigial support for Spanning Tree Protocol.
Open vSwitch has never properly supported IEEE 802.1D Spanning Tree Protocol (STP), but it has various bits and pieces that claim to support it. This commit deletes them, to reduce the amount of dead code in the tree. We can always reintroduce it later if it proves to be a good idea. Bug #1175.
Diffstat (limited to 'lib/learning-switch.c')
-rw-r--r--lib/learning-switch.c328
1 files changed, 5 insertions, 323 deletions
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index aba3525fd..bca479ef2 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -33,7 +33,6 @@
#include "poll-loop.h"
#include "queue.h"
#include "rconn.h"
-#include "stp.h"
#include "timeval.h"
#include "vconn.h"
#include "vlog.h"
@@ -41,14 +40,6 @@
VLOG_DEFINE_THIS_MODULE(learning_switch)
-enum port_state {
- P_DISABLED = 1 << 0,
- P_LISTENING = 1 << 1,
- P_LEARNING = 1 << 2,
- P_FORWARDING = 1 << 3,
- P_BLOCKING = 1 << 4
-};
-
struct lswitch {
/* If nonnegative, the switch sets up flows that expire after the given
* number of seconds (or never expire, if the value is OFP_FLOW_PERMANENT).
@@ -56,7 +47,6 @@ struct lswitch {
int max_idle;
unsigned long long int datapath_id;
- uint32_t capabilities;
time_t last_features_request;
struct mac_learning *ml; /* NULL to act as hub instead of switch. */
uint32_t wildcards; /* Wildcards to apply to flows. */
@@ -65,18 +55,6 @@ struct lswitch {
/* Number of outgoing queued packets on the rconn. */
struct rconn_packet_counter *queued;
-
- /* Spanning tree protocol implementation.
- *
- * We implement STP states by, whenever a port's STP state changes,
- * querying all the flows on the switch and then deleting any of them that
- * are inappropriate for a port's STP state. */
- long long int next_query; /* Next time at which to query all flows. */
- long long int last_query; /* Last time we sent a query. */
- long long int last_reply; /* Last time we received a query reply. */
- unsigned int port_states[STP_MAX_PORTS];
- uint32_t query_xid; /* XID used for query. */
- int n_flows, n_no_recv, n_no_send;
};
/* The log messages here could actually be useful in debugging, so keep the
@@ -87,19 +65,11 @@ static void queue_tx(struct lswitch *, struct rconn *, struct ofpbuf *);
static void send_features_request(struct lswitch *, struct rconn *);
static void send_default_flows(struct lswitch *sw, struct rconn *rconn,
FILE *default_flows);
-static void schedule_query(struct lswitch *, long long int delay);
-static bool may_learn(const struct lswitch *, uint16_t port_no);
-static bool may_recv(const struct lswitch *, uint16_t port_no,
- bool any_actions);
-static bool may_send(const struct lswitch *, uint16_t port_no);
typedef void packet_handler_func(struct lswitch *, struct rconn *, void *);
static packet_handler_func process_switch_features;
static packet_handler_func process_packet_in;
static packet_handler_func process_echo_request;
-static packet_handler_func process_port_status;
-static packet_handler_func process_phy_port;
-static packet_handler_func process_stats_reply;
/* Creates and returns a new learning switch.
*
@@ -123,7 +93,6 @@ lswitch_create(struct rconn *rconn, bool learn_macs,
FILE *default_flows)
{
struct lswitch *sw;
- size_t i;
sw = xzalloc(sizeof *sw);
sw->max_idle = max_idle;
@@ -143,12 +112,6 @@ lswitch_create(struct rconn *rconn, bool learn_macs,
}
sw->queue = UINT32_MAX;
sw->queued = rconn_packet_counter_create();
- sw->next_query = LLONG_MIN;
- sw->last_query = LLONG_MIN;
- sw->last_reply = LLONG_MIN;
- for (i = 0; i < STP_MAX_PORTS; i++) {
- sw->port_states[i] = P_DISABLED;
- }
send_features_request(sw, rconn);
if (default_flows) {
send_default_flows(sw, rconn, default_flows);
@@ -179,82 +142,11 @@ lswitch_set_queue(struct lswitch *sw, uint32_t queue)
/* Takes care of necessary 'sw' activity, except for receiving packets (which
* the caller must do). */
void
-lswitch_run(struct lswitch *sw, struct rconn *rconn)
+lswitch_run(struct lswitch *sw)
{
- long long int now = time_msec();
-
if (sw->ml) {
mac_learning_run(sw->ml, NULL);
}
-
- /* If we're waiting for more replies, keeping waiting for up to 10 s. */
- if (sw->last_reply != LLONG_MIN) {
- if (now - sw->last_reply > 10000) {
- VLOG_ERR_RL(&rl, "%016llx: No more flow stat replies last 10 s",
- sw->datapath_id);
- sw->last_reply = LLONG_MIN;
- sw->last_query = LLONG_MIN;
- schedule_query(sw, 0);
- } else {
- return;
- }
- }
-
- /* If we're waiting for any reply at all, keep waiting for up to 10 s. */
- if (sw->last_query != LLONG_MIN) {
- if (now - sw->last_query > 10000) {
- VLOG_ERR_RL(&rl, "%016llx: No flow stat replies in last 10 s",
- sw->datapath_id);
- sw->last_query = LLONG_MIN;
- schedule_query(sw, 0);
- } else {
- return;
- }
- }
-
- /* If it's time to send another query, do so. */
- if (sw->next_query != LLONG_MIN && now >= sw->next_query) {
- sw->next_query = LLONG_MIN;
- if (!rconn_is_connected(rconn)) {
- schedule_query(sw, 1000);
- } else {
- struct ofp_stats_request *osr;
- struct ofp_flow_stats_request *ofsr;
- struct ofpbuf *b;
- int error;
-
- VLOG_DBG("%016llx: Sending flow stats request to implement STP",
- sw->datapath_id);
-
- sw->last_query = now;
- sw->query_xid = random_uint32();
- sw->n_flows = 0;
- sw->n_no_recv = 0;
- sw->n_no_send = 0;
- osr = make_openflow_xid(sizeof *osr + sizeof *ofsr,
- OFPT_STATS_REQUEST, sw->query_xid, &b);
- osr->type = htons(OFPST_FLOW);
- osr->flags = htons(0);
- ofsr = (struct ofp_flow_stats_request *) osr->body;
- ofsr->match.wildcards = htonl(OFPFW_ALL);
- ofsr->table_id = 0xff;
- ofsr->out_port = htons(OFPP_NONE);
-
- error = rconn_send(rconn, b, NULL);
- if (error) {
- VLOG_WARN_RL(&rl, "%016llx: sending flow stats request "
- "failed: %s", sw->datapath_id, strerror(error));
- ofpbuf_delete(b);
- schedule_query(sw, 1000);
- }
- }
- }
-}
-
-static void
-wait_timeout(long long int started)
-{
- poll_timer_wait_until(started + 10000);
}
void
@@ -263,12 +155,6 @@ lswitch_wait(struct lswitch *sw)
if (sw->ml) {
mac_learning_wait(sw->ml);
}
-
- if (sw->last_reply != LLONG_MIN) {
- wait_timeout(sw->last_reply);
- } else if (sw->last_query != LLONG_MIN) {
- wait_timeout(sw->last_query);
- }
}
/* Processes 'msg', which should be an OpenFlow received on 'rconn', according
@@ -301,16 +187,6 @@ lswitch_process_packet(struct lswitch *sw, struct rconn *rconn,
process_packet_in
},
{
- OFPT_PORT_STATUS,
- sizeof(struct ofp_port_status),
- process_port_status
- },
- {
- OFPT_STATS_REPLY,
- offsetof(struct ofp_stats_reply, body),
- process_stats_reply
- },
- {
OFPT_FLOW_REMOVED,
sizeof(struct ofp_flow_removed),
NULL
@@ -436,31 +312,12 @@ queue_tx(struct lswitch *sw, struct rconn *rconn, struct ofpbuf *b)
}
static void
-schedule_query(struct lswitch *sw, long long int delay)
-{
- long long int now = time_msec();
- if (sw->next_query == LLONG_MIN || sw->next_query > now + delay) {
- sw->next_query = now + delay;
- }
-}
-
-static void
-process_switch_features(struct lswitch *sw, struct rconn *rconn, void *osf_)
+process_switch_features(struct lswitch *sw, struct rconn *rconn OVS_UNUSED,
+ void *osf_)
{
struct ofp_switch_features *osf = osf_;
- size_t n_ports = ((ntohs(osf->header.length)
- - offsetof(struct ofp_switch_features, ports))
- / sizeof *osf->ports);
- size_t i;
sw->datapath_id = ntohll(osf->datapath_id);
- sw->capabilities = ntohl(osf->capabilities);
- for (i = 0; i < n_ports; i++) {
- process_phy_port(sw, rconn, &osf->ports[i]);
- }
- if (sw->capabilities & OFPC_STP) {
- schedule_query(sw, 1000);
- }
}
static uint16_t
@@ -469,7 +326,7 @@ lswitch_choose_destination(struct lswitch *sw, const flow_t *flow)
uint16_t out_port;
/* Learn the source MAC. */
- if (may_learn(sw, flow->in_port) && sw->ml) {
+ if (sw->ml) {
if (mac_learning_learn(sw->ml, flow->dl_src, 0, flow->in_port,
GRAT_ARP_LOCK_NONE)) {
VLOG_DBG_RL(&rl, "%016llx: learned that "ETH_ADDR_FMT" is on "
@@ -483,15 +340,10 @@ lswitch_choose_destination(struct lswitch *sw, const flow_t *flow)
return OFPP_NONE;
}
- if (!may_recv(sw, flow->in_port, false)) {
- /* STP prevents receiving anything on this port. */
- return OFPP_NONE;
- }
-
out_port = OFPP_FLOOD;
if (sw->ml) {
int learned_port = mac_learning_lookup(sw->ml, flow->dl_dst, 0, NULL);
- if (learned_port >= 0 && may_send(sw, learned_port)) {
+ if (learned_port >= 0) {
out_port = learned_port;
if (out_port == flow->in_port) {
/* Don't send a packet back out its input port. */
@@ -596,173 +448,3 @@ process_echo_request(struct lswitch *sw, struct rconn *rconn, void *rq_)
struct ofp_header *rq = rq_;
queue_tx(sw, rconn, make_echo_reply(rq));
}
-
-static void
-process_port_status(struct lswitch *sw, struct rconn *rconn, void *ops_)
-{
- struct ofp_port_status *ops = ops_;
- process_phy_port(sw, rconn, &ops->desc);
-}
-
-static void
-process_phy_port(struct lswitch *sw, struct rconn *rconn OVS_UNUSED,
- void *opp_)
-{
- const struct ofp_phy_port *opp = opp_;
- uint16_t port_no = ntohs(opp->port_no);
- if (sw->capabilities & OFPC_STP && port_no < STP_MAX_PORTS) {
- uint32_t config = ntohl(opp->config);
- uint32_t state = ntohl(opp->state);
- unsigned int *port_state = &sw->port_states[port_no];
- unsigned int new_port_state;
-
- if (!(config & (OFPPC_NO_STP | OFPPC_PORT_DOWN))
- && !(state & OFPPS_LINK_DOWN))
- {
- switch (state & OFPPS_STP_MASK) {
- case OFPPS_STP_LISTEN:
- new_port_state = P_LISTENING;
- break;
- case OFPPS_STP_LEARN:
- new_port_state = P_LEARNING;
- break;
- case OFPPS_STP_FORWARD:
- new_port_state = P_FORWARDING;
- break;
- case OFPPS_STP_BLOCK:
- new_port_state = P_BLOCKING;
- break;
- default:
- new_port_state = P_DISABLED;
- break;
- }
- } else {
- new_port_state = P_FORWARDING;
- }
- if (*port_state != new_port_state) {
- *port_state = new_port_state;
- schedule_query(sw, 1000);
- }
- }
-}
-
-static unsigned int
-get_port_state(const struct lswitch *sw, uint16_t port_no)
-{
- return (port_no >= STP_MAX_PORTS || !(sw->capabilities & OFPC_STP)
- ? P_FORWARDING
- : sw->port_states[port_no]);
-}
-
-static bool
-may_learn(const struct lswitch *sw, uint16_t port_no)
-{
- return get_port_state(sw, port_no) & (P_LEARNING | P_FORWARDING);
-}
-
-static bool
-may_recv(const struct lswitch *sw, uint16_t port_no, bool any_actions)
-{
- unsigned int state = get_port_state(sw, port_no);
- return !(any_actions
- ? state & (P_DISABLED | P_LISTENING | P_BLOCKING)
- : state & (P_DISABLED | P_LISTENING | P_BLOCKING | P_LEARNING));
-}
-
-static bool
-may_send(const struct lswitch *sw, uint16_t port_no)
-{
- return get_port_state(sw, port_no) & P_FORWARDING;
-}
-
-static void
-process_flow_stats(struct lswitch *sw, struct rconn *rconn,
- const struct ofp_flow_stats *ofs)
-{
- const char *end = (char *) ofs + ntohs(ofs->length);
- bool delete = false;
-
- /* Decide to delete the flow if it matches on an STP-disabled physical
- * port. But don't delete it if the flow just drops all received packets,
- * because that's a perfectly reasonable thing to do for disabled physical
- * ports. */
- if (!(ofs->match.wildcards & htonl(OFPFW_IN_PORT))) {
- if (!may_recv(sw, ntohs(ofs->match.in_port),
- end > (char *) ofs->actions)) {
- delete = true;
- sw->n_no_recv++;
- }
- }
-
- /* Decide to delete the flow if it forwards to an STP-disabled physical
- * port. */
- if (!delete) {
- const struct ofp_action_header *a;
- size_t len;
-
- for (a = ofs->actions; (char *) a < end; a += len / 8) {
- len = ntohs(a->len);
- if (len > end - (char *) a) {
- VLOG_DBG_RL(&rl, "%016llx: action exceeds available space "
- "(%zu > %td)",
- sw->datapath_id, len, end - (char *) a);
- break;
- } else if (len % 8) {
- VLOG_DBG_RL(&rl, "%016llx: action length (%zu) not multiple "
- "of 8 bytes", sw->datapath_id, len);
- break;
- }
-
- if (a->type == htons(OFPAT_OUTPUT)) {
- struct ofp_action_output *oao = (struct ofp_action_output *) a;
- if (!may_send(sw, ntohs(oao->port))) {
- delete = true;
- sw->n_no_send++;
- break;
- }
- }
- }
- }
-
- /* Delete the flow. */
- if (delete) {
- struct ofp_flow_mod *ofm;
- struct ofpbuf *b;
-
- ofm = make_openflow(offsetof(struct ofp_flow_mod, actions),
- OFPT_FLOW_MOD, &b);
- ofm->match = ofs->match;
- ofm->command = OFPFC_DELETE_STRICT;
- rconn_send(rconn, b, NULL);
- }
-}
-
-static void
-process_stats_reply(struct lswitch *sw, struct rconn *rconn, void *osr_)
-{
- struct ofp_stats_reply *osr = osr_;
- struct flow_stats_iterator i;
- const struct ofp_flow_stats *fs;
-
- if (sw->last_query == LLONG_MIN
- || osr->type != htons(OFPST_FLOW)
- || osr->header.xid != sw->query_xid) {
- return;
- }
- for (fs = flow_stats_first(&i, osr); fs; fs = flow_stats_next(&i)) {
- sw->n_flows++;
- process_flow_stats(sw, rconn, fs);
- }
- if (!(osr->flags & htons(OFPSF_REPLY_MORE))) {
- VLOG_DBG("%016llx: Deleted %d of %d received flows to "
- "implement STP, %d because of no-recv, %d because of "
- "no-send", sw->datapath_id,
- sw->n_no_recv + sw->n_no_send, sw->n_flows,
- sw->n_no_recv, sw->n_no_send);
- sw->last_query = LLONG_MIN;
- sw->last_reply = LLONG_MIN;
- } else {
- sw->last_reply = time_msec();
- }
-}
-