From ba186119ca5f787486189c041d76d63dee629dc1 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 11 Aug 2010 17:24:13 -0700 Subject: [PATCH] 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. --- extras/ezio/ovs-switchui.c | 19 - lib/automake.mk | 2 - lib/learning-switch.c | 328 +--------- lib/learning-switch.h | 2 +- lib/packets.h | 3 + lib/stp.c | 1233 ------------------------------------ lib/stp.h | 103 --- lib/vlog-modules.def | 1 - ofproto/ofproto.c | 15 +- ofproto/ofproto.h | 1 - tests/.gitignore | 1 - tests/automake.mk | 7 - tests/stp.at | 303 --------- tests/test-stp.c | 666 ------------------- tests/testsuite.at | 1 - utilities/ovs-controller.c | 2 +- utilities/ovs-openflowd.c | 20 - 17 files changed, 11 insertions(+), 2696 deletions(-) delete mode 100644 lib/stp.c delete mode 100644 lib/stp.h delete mode 100644 tests/stp.at delete mode 100644 tests/test-stp.c diff --git a/extras/ezio/ovs-switchui.c b/extras/ezio/ovs-switchui.c index 6f433a3f..d2520450 100644 --- a/extras/ezio/ovs-switchui.c +++ b/extras/ezio/ovs-switchui.c @@ -2536,7 +2536,6 @@ struct switch_config { uint32_t switch_mask; uint32_t switch_gw; enum { FAIL_DROP, FAIL_SWITCH } disconnected; - bool stp; int rate_limit; int inactivity_probe; int max_backoff; @@ -2577,7 +2576,6 @@ cmd_configure(const struct dict *dict OVS_UNUSED) "DISCONNECTED_MODE", ""), "switch") ? FAIL_SWITCH : FAIL_DROP); - config.stp = !strcmp(dict_get_string(&config_dict, "stp", ""), "yes"); config.rate_limit = dict_get_int(&config_dict, "RATE_LIMIT", -1); config.inactivity_probe = dict_get_int(&config_dict, "INACTIVITY_PROBE", -1); @@ -2613,7 +2611,6 @@ cmd_configure(const struct dict *dict OVS_UNUSED) MENU_CONTROLLER, MENU_DISCONNECTED_MODE, MENU_DATAPATH_ID, - MENU_STP, MENU_RATE_LIMIT, MENU_INACTIVITY_PROBE, MENU_MAX_BACKOFF, @@ -2681,13 +2678,6 @@ cmd_configure(const struct dict *dict OVS_UNUSED) item->id = MENU_DATAPATH_ID; item->enabled = strcmp(config.datapath_id, "DMI"); - /* Spanning tree protocol. */ - if (debug_mode) { - item = menu_add_item(&menu, "802.1D-1998 STP:\n%s", - config.stp ? "Enabled" : "Disabled"); - item->id = MENU_STP; - } - /* Rate-limiting. */ if (debug_mode) { if (config.rate_limit < 0) { @@ -2792,14 +2782,6 @@ cmd_configure(const struct dict *dict OVS_UNUSED) config.datapath_id = out; break; - case MENU_STP: - out = prompt("802.1D-1998 STP:", - config.stp ? "Enabled" : "Disabled", - "^(Enabled|Disabled)$"); - config.stp = !strcmp(out, "Enabled"); - free(out); - break; - case MENU_RATE_LIMIT: in = (config.rate_limit < 0 ? xstrdup("Disabled") @@ -2866,7 +2848,6 @@ cmd_configure(const struct dict *dict OVS_UNUSED) svec_add(&set, (config.disconnected == FAIL_DROP ? "DISCONNECTED_MODE=drop" : "DISCONNECTED_MODE=switch")); - svec_add_nocopy(&set, xasprintf("STP=%s", config.stp ? "yes" : "no")); if (config.rate_limit < 0) { svec_add(&set, "RATE_LIMIT="); } else { diff --git a/lib/automake.mk b/lib/automake.mk index eedb5721..f7a2422c 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -117,8 +117,6 @@ lib_libopenvswitch_a_SOURCES = \ lib/socket-util.h \ lib/sort.c \ lib/sort.h \ - lib/stp.c \ - lib/stp.h \ lib/stream-fd.c \ lib/stream-fd.h \ lib/stream-provider.h \ diff --git a/lib/learning-switch.c b/lib/learning-switch.c index aba3525f..bca479ef 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 @@ -300,16 +186,6 @@ lswitch_process_packet(struct lswitch *sw, struct rconn *rconn, offsetof(struct ofp_packet_in, data), 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), @@ -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(); - } -} - diff --git a/lib/learning-switch.h b/lib/learning-switch.h index 3b414a5b..e66001ac 100644 --- a/lib/learning-switch.h +++ b/lib/learning-switch.h @@ -28,7 +28,7 @@ struct lswitch *lswitch_create(struct rconn *, bool learn_macs, bool exact_flows, int max_idle, bool action_normal, FILE *default_flows); void lswitch_set_queue(struct lswitch *sw, uint32_t queue); -void lswitch_run(struct lswitch *, struct rconn *); +void lswitch_run(struct lswitch *); void lswitch_wait(struct lswitch *); void lswitch_destroy(struct lswitch *); void lswitch_process_packet(struct lswitch *, struct rconn *, diff --git a/lib/packets.h b/lib/packets.h index 7ea462bc..d8bd3853 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -33,6 +33,9 @@ bool dpid_from_string(const char *s, uint64_t *dpidp); static const uint8_t eth_addr_broadcast[ETH_ADDR_LEN] OVS_UNUSED = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +static const uint8_t eth_addr_stp[ETH_ADDR_LEN] OVS_UNUSED + = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 }; + static inline bool eth_addr_is_broadcast(const uint8_t ea[6]) { return (ea[0] & ea[1] & ea[2] & ea[3] & ea[4] & ea[5]) == 0xff; diff --git a/lib/stp.c b/lib/stp.c deleted file mode 100644 index c5c8b3ba..00000000 --- a/lib/stp.c +++ /dev/null @@ -1,1233 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010 Nicira Networks. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Based on sample implementation in 802.1D-1998. Above copyright and license - * applies to all modifications. */ - -#include - -#include "stp.h" -#include -#include -#include -#include -#include -#include -#include "ofpbuf.h" -#include "packets.h" -#include "util.h" -#include "vlog.h" -#include "xtoxll.h" - -VLOG_DEFINE_THIS_MODULE(stp) - -/* Ethernet address used as the destination for STP frames. */ -const uint8_t stp_eth_addr[ETH_ADDR_LEN] -= { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 }; - -#define STP_PROTOCOL_ID 0x0000 -#define STP_PROTOCOL_VERSION 0x00 -#define STP_TYPE_CONFIG 0x00 -#define STP_TYPE_TCN 0x80 - -struct stp_bpdu_header { - uint16_t protocol_id; /* STP_PROTOCOL_ID. */ - uint8_t protocol_version; /* STP_PROTOCOL_VERSION. */ - uint8_t bpdu_type; /* One of STP_TYPE_*. */ -} __attribute__((packed)); -BUILD_ASSERT_DECL(sizeof(struct stp_bpdu_header) == 4); - -enum stp_config_bpdu_flags { - STP_CONFIG_TOPOLOGY_CHANGE_ACK = 0x80, - STP_CONFIG_TOPOLOGY_CHANGE = 0x01 -}; - -struct stp_config_bpdu { - struct stp_bpdu_header header; /* Type STP_TYPE_CONFIG. */ - uint8_t flags; /* STP_CONFIG_* flags. */ - uint64_t root_id; /* 8.5.1.1: Bridge believed to be root. */ - uint32_t root_path_cost; /* 8.5.1.2: Cost of path to root. */ - uint64_t bridge_id; /* 8.5.1.3: ID of transmitting bridge. */ - uint16_t port_id; /* 8.5.1.4: Port transmitting the BPDU. */ - uint16_t message_age; /* 8.5.1.5: Age of BPDU at tx time. */ - uint16_t max_age; /* 8.5.1.6: Timeout for received data. */ - uint16_t hello_time; /* 8.5.1.7: Time between BPDU generation. */ - uint16_t forward_delay; /* 8.5.1.8: State progression delay. */ -} __attribute__((packed)); -BUILD_ASSERT_DECL(sizeof(struct stp_config_bpdu) == 35); - -struct stp_tcn_bpdu { - struct stp_bpdu_header header; /* Type STP_TYPE_TCN. */ -} __attribute__((packed)); -BUILD_ASSERT_DECL(sizeof(struct stp_tcn_bpdu) == 4); - -struct stp_timer { - bool active; /* Timer in use? */ - int value; /* Current value of timer, counting up. */ -}; - -struct stp_port { - struct stp *stp; - 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. */ - stp_identifier designated_root; /* 8.5.5.4. */ - int designated_cost; /* 8.5.5.5: Path cost to root on port. */ - stp_identifier designated_bridge; /* 8.5.5.6. */ - int designated_port; /* 8.5.5.7: Port to send config msgs on. */ - bool topology_change_ack; /* 8.5.5.8: Flag for next config BPDU. */ - bool config_pending; /* 8.5.5.9: Send BPDU when hold expires? */ - bool change_detection_enabled; /* 8.5.5.10: Detect topology changes? */ - - struct stp_timer message_age_timer; /* 8.5.6.1: Age of received info. */ - struct stp_timer forward_delay_timer; /* 8.5.6.2: State change timer. */ - struct stp_timer hold_timer; /* 8.5.6.3: BPDU rate limit timer. */ - - bool state_changed; -}; - -struct stp { - /* Static bridge data. */ - char *name; /* Human-readable name for log messages. */ - stp_identifier bridge_id; /* 8.5.3.7: This bridge. */ - int max_age; /* 8.5.3.4: Time to drop received data. */ - int hello_time; /* 8.5.3.5: Time between sending BPDUs. */ - int forward_delay; /* 8.5.3.6: Delay between state changes. */ - 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. */ - unsigned int root_path_cost; /* 8.5.3.2: Cost of path to root. */ - struct stp_port *root_port; /* 8.5.3.3: Lowest cost port to root. */ - bool topology_change_detected; /* 8.5.3.11: Detected a topology change? */ - bool topology_change; /* 8.5.3.12: Received topology change? */ - - /* Bridge timers. */ - struct stp_timer hello_timer; /* 8.5.4.1: Hello timer. */ - struct stp_timer tcn_timer; /* 8.5.4.2: Topology change timer. */ - struct stp_timer topology_change_timer; /* 8.5.4.3. */ - - /* Ports. */ - struct stp_port ports[STP_MAX_PORTS]; - - /* Interface to client. */ - struct stp_port *first_changed_port; - void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux); - void *aux; -}; - -#define FOR_EACH_ENABLED_PORT(PORT, STP) \ - for ((PORT) = stp_next_enabled_port((STP), (STP)->ports); \ - (PORT); \ - (PORT) = stp_next_enabled_port((STP), (PORT) + 1)) -static struct stp_port * -stp_next_enabled_port(const struct stp *stp, const struct stp_port *port) -{ - for (; port < &stp->ports[ARRAY_SIZE(stp->ports)]; port++) { - if (port->state != STP_DISABLED) { - return (struct stp_port *) port; - } - } - return NULL; -} - -#define MESSAGE_AGE_INCREMENT 1 - -static void stp_transmit_config(struct stp_port *); -static bool stp_supersedes_port_info(const struct stp_port *, - const struct stp_config_bpdu *); -static void stp_record_config_information(struct stp_port *, - const struct stp_config_bpdu *); -static void stp_record_config_timeout_values(struct stp *, - const struct stp_config_bpdu *); -static bool stp_is_designated_port(const struct stp_port *); -static void stp_config_bpdu_generation(struct stp *); -static void stp_transmit_tcn(struct stp *); -static void stp_configuration_update(struct stp *); -static bool stp_supersedes_root(const struct stp_port *root, - const struct stp_port *); -static void stp_root_selection(struct stp *); -static void stp_designated_port_selection(struct stp *); -static void stp_become_designated_port(struct stp_port *); -static void stp_port_state_selection(struct stp *); -static void stp_make_forwarding(struct stp_port *); -static void stp_make_blocking(struct stp_port *); -static void stp_set_port_state(struct stp_port *, enum stp_state); -static void stp_topology_change_detection(struct stp *); -static void stp_topology_change_acknowledged(struct stp *); -static void stp_acknowledge_topology_change(struct stp_port *); -static void stp_received_config_bpdu(struct stp *, struct stp_port *, - const struct stp_config_bpdu *); -static void stp_received_tcn_bpdu(struct stp *, struct stp_port *); -static void stp_hello_timer_expiry(struct stp *); -static void stp_message_age_timer_expiry(struct stp_port *); -static bool stp_is_designated_for_some_port(const struct stp *); -static void stp_forward_delay_timer_expiry(struct stp_port *); -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 *); -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); - -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, 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'. 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)(struct ofpbuf *bpdu, int port_no, void *aux), - void *aux) -{ - struct stp *stp; - struct stp_port *p; - - stp = xzalloc(sizeof *stp); - stp->name = xstrdup(name); - stp->bridge_id = bridge_id; - if (!(stp->bridge_id >> 48)) { - 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_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; - stp->root_port = NULL; - stp->topology_change_detected = false; - stp->topology_change = false; - - stp_stop_timer(&stp->tcn_timer); - stp_stop_timer(&stp->topology_change_timer); - stp_start_timer(&stp->hello_timer, 0); - - stp->send_bpdu = send_bpdu; - stp->aux = aux; - - 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) | (STP_DEFAULT_PORT_PRIORITY << 8); - p->path_cost = 19; /* Recommended default for 100 Mb/s link. */ - stp_initialize_port(p, STP_DISABLED); - } - return stp; -} - -/* Destroys 'stp'. */ -void -stp_destroy(struct stp *stp) -{ - if (stp) { - free(stp->name); - free(stp); - } -} - -/* Runs 'stp' given that 'ms' milliseconds have passed. */ -void -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); - } - if (stp_timer_expired(&stp->tcn_timer, elapsed, stp->bridge_hello_time)) { - stp_tcn_timer_expiry(stp); - } - if (stp_timer_expired(&stp->topology_change_timer, elapsed, - stp->max_age + stp->forward_delay)) { - stp_topology_change_timer_expiry(stp); - } - FOR_EACH_ENABLED_PORT (p, stp) { - if (stp_timer_expired(&p->message_age_timer, elapsed, stp->max_age)) { - stp_message_age_timer_expiry(p); - } - } - FOR_EACH_ENABLED_PORT (p, stp) { - if (stp_timer_expired(&p->forward_delay_timer, elapsed, - stp->forward_delay)) { - stp_forward_delay_timer_expiry(p); - } - if (stp_timer_expired(&p->hold_timer, elapsed, ms_to_timer(1000))) { - stp_hold_timer_expiry(p); - } - } -} - -static void -set_bridge_id(struct stp *stp, stp_identifier new_bridge_id) -{ - if (new_bridge_id != stp->bridge_id) { - bool root; - struct stp_port *p; - - root = stp_is_root_bridge(stp); - FOR_EACH_ENABLED_PORT (p, stp) { - if (stp_is_designated_port(p)) { - p->designated_bridge = new_bridge_id; - } - } - stp->bridge_id = new_bridge_id; - stp_configuration_update(stp); - stp_port_state_selection(stp); - if (stp_is_root_bridge(stp) && !root) { - stp_become_root_bridge(stp); - } - } -} - -void -stp_set_bridge_id(struct stp *stp, stp_identifier bridge_id) -{ - const uint64_t mac_bits = (UINT64_C(1) << 48) - 1; - const uint64_t pri_bits = ~mac_bits; - set_bridge_id(stp, (stp->bridge_id & pri_bits) | (bridge_id & mac_bits)); -} - -void -stp_set_bridge_priority(struct stp *stp, uint16_t new_priority) -{ - const uint64_t mac_bits = (UINT64_C(1) << 48) - 1; - set_bridge_id(stp, ((stp->bridge_id & mac_bits) - | ((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) -{ - return stp->name; -} - -/* Returns the bridge ID for 'stp'. */ -stp_identifier -stp_get_bridge_id(const struct stp *stp) -{ - return stp->bridge_id; -} - -/* Returns the bridge ID of the bridge currently believed to be the root. */ -stp_identifier -stp_get_designated_root(const struct stp *stp) -{ - return stp->designated_root; -} - -/* Returns true if 'stp' believes itself to the be root of the spanning tree, - * false otherwise. */ -bool -stp_is_root_bridge(const struct stp *stp) -{ - return stp->bridge_id == stp->designated_root; -} - -/* Returns the cost of the path from 'stp' to the root of the spanning tree. */ -int -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 * -stp_get_port(struct stp *stp, int port_no) -{ - assert(port_no >= 0 && port_no < ARRAY_SIZE(stp->ports)); - return &stp->ports[port_no]; -} - -/* Returns the port connecting 'stp' to the root bridge, or a null pointer if - * there is no such port. */ -struct stp_port * -stp_get_root_port(struct stp *stp) -{ - return stp->root_port; -} - -/* Finds a port whose state has changed. If successful, stores the port whose - * state changed in '*portp' and returns true. If no port has changed, stores - * NULL in '*portp' and returns false. */ -bool -stp_get_changed_port(struct stp *stp, struct stp_port **portp) -{ - struct stp_port *end = &stp->ports[ARRAY_SIZE(stp->ports)]; - struct stp_port *p; - - for (p = stp->first_changed_port; p < end; p++) { - if (p->state_changed) { - p->state_changed = false; - stp->first_changed_port = p + 1; - *portp = p; - return true; - } - } - stp->first_changed_port = end; - *portp = NULL; - return false; -} - -/* Returns the name for the given 'state' (for use in debugging and log - * messages). */ -const char * -stp_state_name(enum stp_state state) -{ - switch (state) { - case STP_DISABLED: - return "disabled"; - case STP_LISTENING: - return "listening"; - case STP_LEARNING: - return "learning"; - case STP_FORWARDING: - return "forwarding"; - case STP_BLOCKING: - return "blocking"; - default: - NOT_REACHED(); - } -} - -/* Returns true if 'state' is one in which packets received on a port should - * 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_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. - * - * 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_DISABLED | STP_LEARNING | STP_FORWARDING)) != 0; -} - -/* Notifies the STP entity that bridge protocol data unit 'bpdu', which is - * 'bpdu_size' bytes in length, was received on port 'p'. - * - * This function may call the 'send_bpdu' function provided to stp_create(). */ -void -stp_received_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size) -{ - struct stp *stp = p->stp; - const struct stp_bpdu_header *header; - - if (p->state == STP_DISABLED) { - return; - } - - if (bpdu_size < sizeof(struct stp_bpdu_header)) { - VLOG_WARN("%s: received runt %zu-byte BPDU", stp->name, bpdu_size); - return; - } - - header = bpdu; - if (header->protocol_id != htons(STP_PROTOCOL_ID)) { - VLOG_WARN("%s: received BPDU with unexpected protocol ID %"PRIu16, - stp->name, ntohs(header->protocol_id)); - return; - } - if (header->protocol_version != STP_PROTOCOL_VERSION) { - VLOG_DBG("%s: received BPDU with unexpected protocol version %"PRIu8, - stp->name, header->protocol_version); - } - - switch (header->bpdu_type) { - case STP_TYPE_CONFIG: - if (bpdu_size < sizeof(struct stp_config_bpdu)) { - VLOG_WARN("%s: received config BPDU with invalid size %zu", - stp->name, bpdu_size); - return; - } - stp_received_config_bpdu(stp, p, bpdu); - break; - - case STP_TYPE_TCN: - if (bpdu_size != sizeof(struct stp_tcn_bpdu)) { - VLOG_WARN("%s: received TCN BPDU with invalid size %zu", - stp->name, bpdu_size); - return; - } - stp_received_tcn_bpdu(stp, p); - break; - - default: - VLOG_WARN("%s: received BPDU of unexpected type %"PRIu8, - stp->name, header->bpdu_type); - return; - } -} - -/* Returns the STP entity in which 'p' is nested. */ -struct stp * -stp_port_get_stp(struct stp_port *p) -{ - return p->stp; -} - -/* Returns the index of port 'p' within its bridge. */ -int -stp_port_no(const struct stp_port *p) -{ - struct stp *stp = p->stp; - assert(p >= stp->ports && p < &stp->ports[ARRAY_SIZE(stp->ports)]); - return p - stp->ports; -} - -/* Returns the state of port 'p'. */ -enum stp_state -stp_port_get_state(const struct stp_port *p) -{ - return p->state; -} - -/* Disables STP on port 'p'. */ -void -stp_port_disable(struct stp_port *p) -{ - struct stp *stp = p->stp; - if (p->state != STP_DISABLED) { - bool root = stp_is_root_bridge(stp); - stp_become_designated_port(p); - stp_set_port_state(p, STP_DISABLED); - p->topology_change_ack = false; - p->config_pending = false; - stp_stop_timer(&p->message_age_timer); - stp_stop_timer(&p->forward_delay_timer); - stp_configuration_update(stp); - stp_port_state_selection(stp); - if (stp_is_root_bridge(stp) && !root) { - stp_become_root_bridge(stp); - } - } -} - -/* Enables STP on port 'p'. The port will initially be in "blocking" state. */ -void -stp_port_enable(struct stp_port *p) -{ - if (p->state == STP_DISABLED) { - stp_initialize_port(p, STP_BLOCKING); - stp_port_state_selection(p->stp); - } -} - -/* Sets the priority of port 'p' to 'new_priority'. Lower numerical values - * are interpreted as higher priorities. */ -void -stp_port_set_priority(struct stp_port *p, uint8_t new_priority) -{ - uint16_t new_port_id = (p->port_id & 0xff) | (new_priority << 8); - if (p->port_id != new_port_id) { - struct stp *stp = p->stp; - if (stp_is_designated_port(p)) { - p->designated_port = new_port_id; - } - p->port_id = new_port_id; - if (stp->bridge_id == p->designated_bridge - && p->port_id < p->designated_port) { - stp_become_designated_port(p); - stp_port_state_selection(stp); - } - } -} - -/* 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. */ -void -stp_port_set_path_cost(struct stp_port *p, uint16_t path_cost) -{ - if (p->path_cost != path_cost) { - struct stp *stp = p->stp; - p->path_cost = path_cost; - stp_configuration_update(stp); - stp_port_state_selection(stp); - } -} - -/* Sets the path cost of port 'p' based on 'speed' (measured in Mb/s). */ -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). */ -} - -/* Enables topology change detection on port 'p'. */ -void -stp_port_enable_change_detection(struct stp_port *p) -{ - p->change_detection_enabled = true; -} - -/* Disables topology change detection on port 'p'. */ -void -stp_port_disable_change_detection(struct stp_port *p) -{ - p->change_detection_enabled = false; -} - -static void -stp_transmit_config(struct stp_port *p) -{ - struct stp *stp = p->stp; - bool root = stp_is_root_bridge(stp); - if (!root && !stp->root_port) { - return; - } - if (p->hold_timer.active) { - p->config_pending = true; - } else { - struct stp_config_bpdu config; - memset(&config, 0, sizeof config); - config.header.protocol_id = htons(STP_PROTOCOL_ID); - config.header.protocol_version = STP_PROTOCOL_VERSION; - config.header.bpdu_type = STP_TYPE_CONFIG; - config.flags = 0; - if (p->topology_change_ack) { - config.flags |= htons(STP_CONFIG_TOPOLOGY_CHANGE_ACK); - } - if (stp->topology_change) { - config.flags |= htons(STP_CONFIG_TOPOLOGY_CHANGE); - } - config.root_id = htonll(stp->designated_root); - config.root_path_cost = htonl(stp->root_path_cost); - config.bridge_id = htonll(stp->bridge_id); - config.port_id = htons(p->port_id); - if (root) { - config.message_age = htons(0); - } else { - config.message_age = htons(stp->root_port->message_age_timer.value - + MESSAGE_AGE_INCREMENT); - } - config.max_age = htons(stp->max_age); - config.hello_time = htons(stp->hello_time); - config.forward_delay = htons(stp->forward_delay); - if (ntohs(config.message_age) < stp->max_age) { - p->topology_change_ack = false; - p->config_pending = false; - stp_send_bpdu(p, &config, sizeof config); - stp_start_timer(&p->hold_timer, 0); - } - } -} - -static bool -stp_supersedes_port_info(const struct stp_port *p, - const struct stp_config_bpdu *config) -{ - if (ntohll(config->root_id) != p->designated_root) { - return ntohll(config->root_id) < p->designated_root; - } else if (ntohl(config->root_path_cost) != p->designated_cost) { - return ntohl(config->root_path_cost) < p->designated_cost; - } else if (ntohll(config->bridge_id) != p->designated_bridge) { - return ntohll(config->bridge_id) < p->designated_bridge; - } else { - return (ntohll(config->bridge_id) != p->stp->bridge_id - || ntohs(config->port_id) <= p->designated_port); - } -} - -static void -stp_record_config_information(struct stp_port *p, - const struct stp_config_bpdu *config) -{ - p->designated_root = ntohll(config->root_id); - p->designated_cost = ntohl(config->root_path_cost); - p->designated_bridge = ntohll(config->bridge_id); - p->designated_port = ntohs(config->port_id); - stp_start_timer(&p->message_age_timer, ntohs(config->message_age)); -} - -static void -stp_record_config_timeout_values(struct stp *stp, - const struct stp_config_bpdu *config) -{ - 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); -} - -static bool -stp_is_designated_port(const struct stp_port *p) -{ - return (p->designated_bridge == p->stp->bridge_id - && p->designated_port == p->port_id); -} - -static void -stp_config_bpdu_generation(struct stp *stp) -{ - struct stp_port *p; - - FOR_EACH_ENABLED_PORT (p, stp) { - if (stp_is_designated_port(p)) { - stp_transmit_config(p); - } - } -} - -static void -stp_transmit_tcn(struct stp *stp) -{ - struct stp_port *p = stp->root_port; - struct stp_tcn_bpdu tcn_bpdu; - if (!p) { - return; - } - 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(p, &tcn_bpdu, sizeof tcn_bpdu); -} - -static void -stp_configuration_update(struct stp *stp) -{ - stp_root_selection(stp); - stp_designated_port_selection(stp); -} - -static bool -stp_supersedes_root(const struct stp_port *root, const struct stp_port *p) -{ - int p_cost = p->designated_cost + p->path_cost; - int root_cost = root->designated_cost + root->path_cost; - - if (p->designated_root != root->designated_root) { - return p->designated_root < root->designated_root; - } else if (p_cost != root_cost) { - return p_cost < root_cost; - } else if (p->designated_bridge != root->designated_bridge) { - return p->designated_bridge < root->designated_bridge; - } else if (p->designated_port != root->designated_port) { - return p->designated_port < root->designated_port; - } else { - return p->port_id < root->port_id; - } -} - -static void -stp_root_selection(struct stp *stp) -{ - struct stp_port *p, *root; - - root = NULL; - FOR_EACH_ENABLED_PORT (p, stp) { - if (stp_is_designated_port(p) - || p->designated_root >= stp->bridge_id) { - continue; - } - if (root && !stp_supersedes_root(root, p)) { - continue; - } - root = p; - } - stp->root_port = root; - if (!root) { - stp->designated_root = stp->bridge_id; - stp->root_path_cost = 0; - } else { - stp->designated_root = root->designated_root; - stp->root_path_cost = root->designated_cost + root->path_cost; - } -} - -static void -stp_designated_port_selection(struct stp *stp) -{ - struct stp_port *p; - - FOR_EACH_ENABLED_PORT (p, stp) { - if (stp_is_designated_port(p) - || p->designated_root != stp->designated_root - || stp->root_path_cost < p->designated_cost - || (stp->root_path_cost == p->designated_cost - && (stp->bridge_id < p->designated_bridge - || (stp->bridge_id == p->designated_bridge - && p->port_id <= p->designated_port)))) - { - stp_become_designated_port(p); - } - } -} - -static void -stp_become_designated_port(struct stp_port *p) -{ - struct stp *stp = p->stp; - p->designated_root = stp->designated_root; - p->designated_cost = stp->root_path_cost; - p->designated_bridge = stp->bridge_id; - p->designated_port = p->port_id; -} - -static void -stp_port_state_selection(struct stp *stp) -{ - struct stp_port *p; - - FOR_EACH_ENABLED_PORT (p, stp) { - if (p == stp->root_port) { - p->config_pending = false; - p->topology_change_ack = false; - stp_make_forwarding(p); - } else if (stp_is_designated_port(p)) { - stp_stop_timer(&p->message_age_timer); - stp_make_forwarding(p); - } else { - p->config_pending = false; - p->topology_change_ack = false; - stp_make_blocking(p); - } - } -} - -static void -stp_make_forwarding(struct stp_port *p) -{ - if (p->state == STP_BLOCKING) { - stp_set_port_state(p, STP_LISTENING); - stp_start_timer(&p->forward_delay_timer, 0); - } -} - -static void -stp_make_blocking(struct stp_port *p) -{ - if (!(p->state & (STP_DISABLED | STP_BLOCKING))) { - if (p->state & (STP_FORWARDING | STP_LEARNING)) { - if (p->change_detection_enabled) { - stp_topology_change_detection(p->stp); - } - } - stp_set_port_state(p, STP_BLOCKING); - stp_stop_timer(&p->forward_delay_timer); - } -} - -static void -stp_set_port_state(struct stp_port *p, enum stp_state state) -{ - if (state != p->state && !p->state_changed) { - p->state_changed = true; - if (p < p->stp->first_changed_port) { - p->stp->first_changed_port = p; - } - } - p->state = state; -} - -static void -stp_topology_change_detection(struct stp *stp) -{ - if (stp_is_root_bridge(stp)) { - stp->topology_change = true; - stp_start_timer(&stp->topology_change_timer, 0); - } else if (!stp->topology_change_detected) { - stp_transmit_tcn(stp); - stp_start_timer(&stp->tcn_timer, 0); - } - stp->topology_change_detected = true; -} - -static void -stp_topology_change_acknowledged(struct stp *stp) -{ - stp->topology_change_detected = false; - stp_stop_timer(&stp->tcn_timer); -} - -static void -stp_acknowledge_topology_change(struct stp_port *p) -{ - p->topology_change_ack = true; - stp_transmit_config(p); -} - -void -stp_received_config_bpdu(struct stp *stp, struct stp_port *p, - const struct stp_config_bpdu *config) -{ - if (ntohs(config->message_age) >= ntohs(config->max_age)) { - VLOG_WARN("%s: received config BPDU with message age (%u) greater " - "than max age (%u)", - stp->name, - ntohs(config->message_age), ntohs(config->max_age)); - return; - } - if (p->state != STP_DISABLED) { - bool root = stp_is_root_bridge(stp); - if (stp_supersedes_port_info(p, config)) { - stp_record_config_information(p, config); - stp_configuration_update(stp); - stp_port_state_selection(stp); - if (!stp_is_root_bridge(stp) && root) { - stp_stop_timer(&stp->hello_timer); - if (stp->topology_change_detected) { - stp_stop_timer(&stp->topology_change_timer); - stp_transmit_tcn(stp); - stp_start_timer(&stp->tcn_timer, 0); - } - } - 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)) { - stp_topology_change_acknowledged(stp); - } - } - } else if (stp_is_designated_port(p)) { - stp_transmit_config(p); - } - } -} - -void -stp_received_tcn_bpdu(struct stp *stp, struct stp_port *p) -{ - if (p->state != STP_DISABLED) { - if (stp_is_designated_port(p)) { - stp_topology_change_detection(stp); - stp_acknowledge_topology_change(p); - } - } -} - -static void -stp_hello_timer_expiry(struct stp *stp) -{ - stp_config_bpdu_generation(stp); - stp_start_timer(&stp->hello_timer, 0); -} - -static void -stp_message_age_timer_expiry(struct stp_port *p) -{ - struct stp *stp = p->stp; - bool root = stp_is_root_bridge(stp); - stp_become_designated_port(p); - stp_configuration_update(stp); - stp_port_state_selection(stp); - if (stp_is_root_bridge(stp) && !root) { - stp->max_age = stp->bridge_max_age; - stp->hello_time = stp->bridge_hello_time; - stp->forward_delay = stp->bridge_forward_delay; - stp_topology_change_detection(stp); - stp_stop_timer(&stp->tcn_timer); - stp_config_bpdu_generation(stp); - stp_start_timer(&stp->hello_timer, 0); - } -} - -static bool -stp_is_designated_for_some_port(const struct stp *stp) -{ - const struct stp_port *p; - - FOR_EACH_ENABLED_PORT (p, stp) { - if (p->designated_bridge == stp->bridge_id) { - return true; - } - } - return false; -} - -static void -stp_forward_delay_timer_expiry(struct stp_port *p) -{ - if (p->state == STP_LISTENING) { - stp_set_port_state(p, STP_LEARNING); - stp_start_timer(&p->forward_delay_timer, 0); - } else if (p->state == STP_LEARNING) { - stp_set_port_state(p, STP_FORWARDING); - if (stp_is_designated_for_some_port(p->stp)) { - if (p->change_detection_enabled) { - stp_topology_change_detection(p->stp); - } - } - } -} - -static void -stp_tcn_timer_expiry(struct stp *stp) -{ - stp_transmit_tcn(stp); - stp_start_timer(&stp->tcn_timer, 0); -} - -static void -stp_topology_change_timer_expiry(struct stp *stp) -{ - stp->topology_change_detected = false; - stp->topology_change = false; -} - -static void -stp_hold_timer_expiry(struct stp_port *p) -{ - if (p->config_pending) { - stp_transmit_config(p); - } -} - -static void -stp_initialize_port(struct stp_port *p, enum stp_state state) -{ - assert(state & (STP_DISABLED | STP_BLOCKING)); - stp_become_designated_port(p); - stp_set_port_state(p, state); - p->topology_change_ack = false; - p->config_pending = false; - p->change_detection_enabled = true; - stp_stop_timer(&p->message_age_timer); - stp_stop_timer(&p->forward_delay_timer); - stp_stop_timer(&p->hold_timer); -} - -static void -stp_become_root_bridge(struct stp *stp) -{ - stp->max_age = stp->bridge_max_age; - stp->hello_time = stp->bridge_hello_time; - stp->forward_delay = stp->bridge_forward_delay; - stp_topology_change_detection(stp); - stp_stop_timer(&stp->tcn_timer); - stp_config_bpdu_generation(stp); - stp_start_timer(&stp->hello_timer, 0); -} - -static void -stp_start_timer(struct stp_timer *timer, int value) -{ - timer->value = value; - timer->active = true; -} - -static void -stp_stop_timer(struct stp_timer *timer) -{ - timer->active = false; -} - -static bool -stp_timer_expired(struct stp_timer *timer, int elapsed, int timeout) -{ - if (timer->active) { - timer->value += elapsed; - if (timer->value >= timeout) { - timer->active = false; - return true; - } - } - 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); -} diff --git a/lib/stp.h b/lib/stp.h deleted file mode 100644 index 35c2caa5..00000000 --- a/lib/stp.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2008 Nicira Networks. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef STP_H -#define STP_H 1 - -/* This is an implementation of Spanning Tree Protocol as described in IEEE - * 802.1D-1998, clauses 8 and 9. Section numbers refer to this standard. */ - -#include -#include -#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]; - -/* LLC field values used for STP frames. */ -#define STP_LLC_SSAP 0x42 -#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; - -/* Basic STP functionality. */ -#define STP_MAX_PORTS 255 -struct stp *stp_create(const char *name, stp_identifier bridge_id, - void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, - void *aux), - void *aux); -void stp_destroy(struct stp *); -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 *); -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); -struct stp_port *stp_get_root_port(struct stp *); -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. */ -enum stp_state { - STP_DISABLED = 1 << 0, /* 8.4.5: Disabled by management. */ - 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. */ - STP_BLOCKING = 1 << 4 /* 8.4.1: Initial boot state. */ -}; -const char *stp_state_name(enum stp_state); -bool stp_forward_in_state(enum stp_state); -bool stp_learn_in_state(enum stp_state); - -void stp_received_bpdu(struct stp_port *, const void *bpdu, size_t bpdu_size); - -struct stp *stp_port_get_stp(struct stp_port *); -int stp_port_no(const struct stp_port *); -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 *, 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 *); - -#endif /* stp.h */ diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def index c3a5e4ad..b55472de 100644 --- a/lib/vlog-modules.def +++ b/lib/vlog-modules.def @@ -70,7 +70,6 @@ VLOG_MODULE(rconn) VLOG_MODULE(reconnect) VLOG_MODULE(rtnetlink) VLOG_MODULE(sflow) -VLOG_MODULE(stp) VLOG_MODULE(stream_fd) VLOG_MODULE(stream_ssl) VLOG_MODULE(stream_tcp) diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index a466c9ca..b6c83f86 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -50,7 +50,6 @@ #include "rconn.h" #include "shash.h" #include "status.h" -#include "stp.h" #include "stream-ssl.h" #include "svec.h" #include "tag.h" @@ -900,18 +899,6 @@ ofproto_set_sflow(struct ofproto *ofproto, } } -int -ofproto_set_stp(struct ofproto *ofproto OVS_UNUSED, bool enable_stp) -{ - /* XXX */ - if (enable_stp) { - VLOG_WARN("STP is not yet implemented"); - return EINVAL; - } else { - return 0; - } -} - uint64_t ofproto_get_datapath_id(const struct ofproto *ofproto) { @@ -2654,7 +2641,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, port = port_array_get(&ctx->ofproto->ports, ctx->flow.in_port); if (port && port->opp.config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) && - port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, stp_eth_addr) + port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, eth_addr_stp) ? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) { /* Drop this flow. */ return; diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h index 76f1cc67..22484519 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -115,7 +115,6 @@ int ofproto_set_snoops(struct ofproto *, const struct svec *snoops); int ofproto_set_netflow(struct ofproto *, const struct netflow_options *nf_options); void ofproto_set_sflow(struct ofproto *, const struct ofproto_sflow_options *); -int ofproto_set_stp(struct ofproto *, bool enable_stp); /* Configuration querying. */ uint64_t ofproto_get_datapath_id(const struct ofproto *); diff --git a/tests/.gitignore b/tests/.gitignore index c987014e..f79aff2b 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -21,7 +21,6 @@ /test-reconnect /test-timeval /test-sha1 -/test-stp /test-type-props /test-uuid /test-vconn diff --git a/tests/automake.mk b/tests/automake.mk index 48aa5aa1..9a248feb 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -38,7 +38,6 @@ TESTSUITE_AT = \ tests/ovsdb-server.at \ tests/ovsdb-monitor.at \ tests/ovsdb-idl.at \ - tests/stp.at \ tests/ovs-vsctl.at \ tests/interface-reconfigure.at TESTSUITE = $(srcdir)/tests/testsuite @@ -72,7 +71,6 @@ lcov_wrappers = \ tests/lcov/test-ovsdb \ tests/lcov/test-reconnect \ tests/lcov/test-sha1 \ - tests/lcov/test-stp \ tests/lcov/test-timeval \ tests/lcov/test-type-props \ tests/lcov/test-uuid \ @@ -121,7 +119,6 @@ valgrind_wrappers = \ tests/valgrind/test-ovsdb \ tests/valgrind/test-reconnect \ tests/valgrind/test-sha1 \ - tests/valgrind/test-stp \ tests/valgrind/test-timeval \ tests/valgrind/test-type-props \ tests/valgrind/test-uuid \ @@ -251,10 +248,6 @@ noinst_PROGRAMS += tests/test-dhcp-client tests_test_dhcp_client_SOURCES = tests/test-dhcp-client.c tests_test_dhcp_client_LDADD = lib/libopenvswitch.a -noinst_PROGRAMS += tests/test-stp -tests_test_stp_SOURCES = tests/test-stp.c -tests_test_stp_LDADD = lib/libopenvswitch.a - noinst_PROGRAMS += tests/test-uuid tests_test_uuid_SOURCES = tests/test-uuid.c tests_test_uuid_LDADD = lib/libopenvswitch.a diff --git a/tests/stp.at b/tests/stp.at deleted file mode 100644 index 4e25af72..00000000 --- a/tests/stp.at +++ /dev/null @@ -1,303 +0,0 @@ -AT_BANNER([Spanning Tree Protocol unit tests]) - -AT_SETUP([STP example from IEEE 802.1D-1998]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-ieee802.1d-1998], -[bridge 0 0x42 = a b -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 1000 -check 0 = root -check 1 = F F:10 F -check 2 = F:10 B -check 3 = F:5 F -check 4 = F:5 B -]) -AT_CHECK([test-stp test-stp-ieee802.1d-1998]) -AT_CLEANUP - -AT_SETUP([STP example from IEEE 802.1D-2004 figures 17.4 and 17.5]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-ieee802.1d-2004-fig17.4], -[bridge 0 0x111 = a b e c -bridge 1 0x222 = a b d f -bridge 2 0x333 = c d l j h g -bridge 3 0x444 = e f n m k i -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 1000 -check 0 = root -check 1 = F:10 B F F -check 2 = F:10 B F F F F -check 3 = F:10 B F F F F -check 4 = F:20 B F F -check 5 = F:20 B F F -check 6 = F:20 B F F -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 1000 -check 0 = root -check 1 = F:10 B F F -check 2 = F:10 B F F F F -check 3 = F:10 B F F F F -check 4 = F:20 B F F -check 5 = F:20 B F F -check 6 = F:20 B F F -check 7 = F:20 B F B -]) -AT_CHECK([test-stp test-stp-ieee802.1d-2004-fig17.4]) -AT_CLEANUP - -AT_SETUP([STP example from IEEE 802.1D-2004 figure 17.6]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-ieee802.1d-2004-fig17.6], -[bridge 0 0x111 = a b l -bridge 1 0x222 = b c d -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 1000 -check 0 = root -check 1 = F:10 F F -check 2 = F:20 F F -check 3 = F:30 F B -check 4 = F:20 F F -check 5 = F:10 F F -]) -AT_CHECK([test-stp test-stp-ieee802.1d-2004-fig17.6]) -AT_CLEANUP - -AT_SETUP([STP example from IEEE 802.1D-2004 figure 17.7]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-ieee802.1d-2004-fig17.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 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 - -# This is not the port priority change described in that figure, -# but I don't understand what port priority change would cause -# that change. -bridge 2 = g X j l n m k i -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 -]) -AT_CHECK([test-stp test-stp-ieee802.1d-2004-fig17.7]) -AT_CLEANUP - -AT_SETUP([STP.io.1.1: Link Failure]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-iol-io-1.1], -[# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# -# STP.io.1.1: Link Failure -bridge 0 0x111 = a b c -bridge 1 0x222 = a b c -run 1000 -check 0 = root -check 1 = F:10 B B -bridge 1 = 0 _ _ -run 1000 -check 0 = root -check 1 = F F:10 B -bridge 1 = X _ _ -run 1000 -check 0 = root -check 1 = D F:10 B -bridge 1 = _ 0 _ -run 1000 -check 0 = root -check 1 = D F F:10 -bridge 1 = _ X _ -run 1000 -check 0 = root -check 1 = D D F:10 -]) -AT_CHECK([test-stp test-stp-iol-io-1.1]) -AT_CLEANUP - -AT_SETUP([STP.io.1.2: Repeated Network]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-iol-io-1.2], -[# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# STP.io.1.2: Repeated Network -bridge 0 0x111 = a a -bridge 1 0x222 = a a -run 1000 -check 0 = rootid:0x111 F B -check 1 = rootid:0x111 F:10 B -bridge 1 = a^0x90 _ -run 1000 -check 0 = rootid:0x111 F B -check 1 = rootid:0x111 B F:10 -]) -AT_CHECK([test-stp test-stp-iol-io-1.2]) -AT_CLEANUP - -AT_SETUP([STP.io.1.4: Network Initialization]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-iol-io-1.4], -[# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# STP.io.1.4: Network Initialization -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 1000 -check 0 = root -check 1 = F:10 F F -check 2 = F:10 B F -check 3 = F:10 B B -]) -AT_CHECK([test-stp test-stp-iol-io-1.4]) -AT_CLEANUP - -AT_SETUP([STP.io.1.5: Topology Change]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-iol-io-1.5], -[# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# STP.io.1.5: Topology Change -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 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 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 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 1000 -check 0 = B B B F:20 -check 1 = F F B F:10 -check 2 = F F F:10 B -check 3 = root -bridge 0^0x4000 -bridge 1^0x4001 -bridge 2^0x4002 -bridge 3^0x4003 -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 -]) -AT_CHECK([test-stp test-stp-iol-io-1.5]) -AT_CLEANUP - -AT_SETUP([STP.op.1.1 and STP.op.1.2]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-iol-op-1.1], -[# This test file approximates the following tests from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.1.1: Root ID Initialized to Bridge ID -# Test STP.op.1.2: Root Path Cost Initialized to Zero -bridge 0 0x123 = -check 0 = root -]) -AT_CHECK([test-stp test-stp-iol-op-1.1]) -AT_CLEANUP - -AT_SETUP([STP.op.1.4: All Ports Initialized to Designated Ports]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-iol-op-1.4], -[# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# 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 1000 -check 0 = F F F F F F -]) -AT_CHECK([test-stp test-stp-iol-op-1.4]) -AT_CLEANUP - -AT_SETUP([STP.op.3.1: Root Bridge Selection: Root ID Values]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-iol-op-3.1], -[# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.3.1: Root Bridge Selection: Root ID Values -bridge 0 0x111 = a -bridge 1 0x222 = a -check 0 = rootid:0x111 Li -check 1 = rootid:0x222 Li -run 1000 -check 0 = rootid:0x111 root -check 1 = rootid:0x111 F:10 -]) -AT_CHECK([test-stp test-stp-iol-op-3.1]) -AT_CLEANUP - -AT_SETUP([STP.op.3.3: Root Bridge Selection: Bridge ID Values]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-iol-op-3.3], -[# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.3.3: Root Bridge Selection: Bridge ID Values -bridge 0 0x333^0x6000 = a -bridge 1 0x222^0x7000 = b -bridge 2 0x111 = a b -run 1000 -check 0 = rootid:0x333^0x6000 root -check 1 = rootid:0x333^0x6000 F:20 -check 2 = rootid:0x333^0x6000 F:10 F -]) -AT_CHECK([test-stp test-stp-iol-op-3.3]) -AT_CLEANUP - -AT_SETUP([STP.op.3.3: Root Bridge Selection: Bridge ID Values]) -AT_KEYWORDS([STP]) -AT_DATA([test-stp-iol-op-3.4], -[# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.3.3: Root Bridge Selection: Bridge ID Values -bridge 0 0x333^0x6000 = a -bridge 1 0x222^0x7000 = b -bridge 2 0x111 = a b -run 1000 -check 0 = rootid:0x333^0x6000 root -check 1 = rootid:0x333^0x6000 F:20 -check 2 = rootid:0x333^0x6000 F:10 F -]) -AT_CHECK([test-stp test-stp-iol-op-3.4]) -AT_CLEANUP - diff --git a/tests/test-stp.c b/tests/test-stp.c deleted file mode 100644 index 83d571de..00000000 --- a/tests/test-stp.c +++ /dev/null @@ -1,666 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010 Nicira Networks. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "stp.h" -#include -#include -#include -#include -#include -#include -#include "ofpbuf.h" -#include "packets.h" - -struct bpdu { - int port_no; - void *data; - size_t size; -}; - -struct bridge { - struct test_case *tc; - int id; - bool reached; - - struct stp *stp; - - struct lan *ports[STP_MAX_PORTS]; - int n_ports; - -#define RXQ_SIZE 16 - struct bpdu rxq[RXQ_SIZE]; - int rxq_head, rxq_tail; -}; - -struct lan_conn { - struct bridge *bridge; - int port_no; -}; - -struct lan { - struct test_case *tc; - const char *name; - bool reached; - struct lan_conn conns[16]; - int n_conns; -}; - -struct test_case { - struct bridge *bridges[16]; - int n_bridges; - struct lan *lans[26]; - int n_lans; -}; - -static const char *file_name; -static int line_number; -static char line[128]; -static char *pos, *token; -static int n_warnings; - -static struct test_case * -new_test_case(void) -{ - struct test_case *tc = xmalloc(sizeof *tc); - tc->n_bridges = 0; - tc->n_lans = 0; - return tc; -} - -static void -send_bpdu(struct ofpbuf *pkt, int port_no, void *b_) -{ - struct bridge *b = b_; - struct lan *lan; - - assert(port_no < b->n_ports); - lan = b->ports[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 * -new_bridge(struct test_case *tc, int id) -{ - struct bridge *b = xmalloc(sizeof *b); - char name[16]; - b->tc = tc; - b->id = id; - snprintf(name, sizeof name, "stp%x", id); - b->stp = stp_create(name, id, send_bpdu, b); - assert(tc->n_bridges < ARRAY_SIZE(tc->bridges)); - b->n_ports = 0; - b->rxq_head = b->rxq_tail = 0; - tc->bridges[tc->n_bridges++] = b; - return b; -} - -static struct lan * -new_lan(struct test_case *tc, const char *name) -{ - struct lan *lan = xmalloc(sizeof *lan); - lan->tc = tc; - lan->name = xstrdup(name); - lan->n_conns = 0; - assert(tc->n_lans < ARRAY_SIZE(tc->lans)); - tc->lans[tc->n_lans++] = lan; - return lan; -} - -static void -reconnect_port(struct bridge *b, int port_no, struct lan *new_lan) -{ - struct lan *old_lan; - int j; - - assert(port_no < b->n_ports); - old_lan = b->ports[port_no]; - if (old_lan == new_lan) { - return; - } - - /* Disconnect from old_lan. */ - if (old_lan) { - for (j = 0; j < old_lan->n_conns; j++) { - struct lan_conn *c = &old_lan->conns[j]; - if (c->bridge == b && c->port_no == port_no) { - memmove(c, c + 1, sizeof *c * (old_lan->n_conns - j - 1)); - old_lan->n_conns--; - break; - } - } - } - - /* Connect to new_lan. */ - b->ports[port_no] = new_lan; - if (new_lan) { - int conn_no = new_lan->n_conns++; - assert(conn_no < ARRAY_SIZE(new_lan->conns)); - new_lan->conns[conn_no].bridge = b; - new_lan->conns[conn_no].port_no = port_no; - } -} - -static void -new_port(struct bridge *b, struct lan *lan, int path_cost) -{ - int port_no = b->n_ports++; - struct stp_port *p = stp_get_port(b->stp, port_no); - assert(port_no < ARRAY_SIZE(b->ports)); - b->ports[port_no] = NULL; - stp_port_set_path_cost(p, path_cost); - stp_port_enable(p); - reconnect_port(b, port_no, lan); -} - -static void -dump(struct test_case *tc) -{ - int i; - - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - struct stp *stp = b->stp; - int j; - - printf("%s:", stp_get_name(stp)); - if (stp_is_root_bridge(stp)) { - printf(" root"); - } - printf("\n"); - for (j = 0; j < b->n_ports; j++) { - struct stp_port *p = stp_get_port(stp, j); - enum stp_state state = stp_port_get_state(p); - - printf("\tport %d", j); - if (b->ports[j]) { - printf(" (lan %s)", b->ports[j]->name); - } else { - printf(" (disconnected)"); - } - printf(": %s", stp_state_name(state)); - if (p == stp_get_root_port(stp)) { - printf(" (root port, root_path_cost=%u)", stp_get_root_path_cost(stp)); - } - printf("\n"); - } - } -} - -static void dump_lan_tree(struct test_case *, struct lan *, int level); - -static void -dump_bridge_tree(struct test_case *tc, struct bridge *b, int level) -{ - int i; - - if (b->reached) { - return; - } - b->reached = true; - for (i = 0; i < level; i++) { - printf("\t"); - } - printf("%s\n", stp_get_name(b->stp)); - for (i = 0; i < b->n_ports; i++) { - struct lan *lan = b->ports[i]; - struct stp_port *p = stp_get_port(b->stp, i); - if (stp_port_get_state(p) == STP_FORWARDING && lan) { - dump_lan_tree(tc, lan, level + 1); - } - } -} - -static void -dump_lan_tree(struct test_case *tc, struct lan *lan, int level) -{ - int i; - - if (lan->reached) { - return; - } - lan->reached = true; - for (i = 0; i < level; i++) { - printf("\t"); - } - printf("%s\n", lan->name); - for (i = 0; i < lan->n_conns; i++) { - struct bridge *b = lan->conns[i].bridge; - dump_bridge_tree(tc, b, level + 1); - } -} - -static void -tree(struct test_case *tc) -{ - int i; - - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - b->reached = false; - } - for (i = 0; i < tc->n_lans; i++) { - struct lan *lan = tc->lans[i]; - lan->reached = false; - } - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - struct stp *stp = b->stp; - if (stp_is_root_bridge(stp)) { - dump_bridge_tree(tc, b, 0); - } - } -} - -static void -simulate(struct test_case *tc, int granularity) -{ - int time; - - for (time = 0; time < 1000 * 180; time += granularity) { - int round_trips; - int i; - - for (i = 0; i < tc->n_bridges; i++) { - stp_tick(tc->bridges[i]->stp, granularity); - } - for (round_trips = 0; round_trips < granularity; round_trips++) { - bool any = false; - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - for (; b->rxq_tail != b->rxq_head; b->rxq_tail++) { - struct bpdu *bpdu = &b->rxq[b->rxq_tail % RXQ_SIZE]; - stp_received_bpdu(stp_get_port(b->stp, bpdu->port_no), - bpdu->data, bpdu->size); - free(bpdu->data); - any = true; - } - } - if (!any) { - break; - } - } - } -} - -static void -err(const char *message, ...) - PRINTF_FORMAT(1, 2) - NO_RETURN; - -static void -err(const char *message, ...) -{ - va_list args; - - fprintf(stderr, "%s:%d:%td: ", file_name, line_number, pos - line); - va_start(args, message); - vfprintf(stderr, message, args); - va_end(args); - putc('\n', stderr); - - exit(EXIT_FAILURE); -} - -static void -warn(const char *message, ...) - PRINTF_FORMAT(1, 2); - -static void -warn(const char *message, ...) -{ - va_list args; - - fprintf(stderr, "%s:%d: ", file_name, line_number); - va_start(args, message); - vfprintf(stderr, message, args); - va_end(args); - putc('\n', stderr); - - n_warnings++; -} - -static bool -get_token(void) -{ - char *start; - - while (isspace((unsigned char) *pos)) { - pos++; - } - if (*pos == '\0') { - free(token); - token = NULL; - return false; - } - - start = pos; - if (isalpha((unsigned char) *pos)) { - while (isalpha((unsigned char) *++pos)) { - continue; - } - } else if (isdigit((unsigned char) *pos)) { - if (*pos == '0' && (pos[1] == 'x' || pos[1] == 'X')) { - pos += 2; - while (isxdigit((unsigned char) *pos)) { - pos++; - } - } else { - while (isdigit((unsigned char) *++pos)) { - continue; - } - } - } else { - pos++; - } - - free(token); - token = xmemdup0(start, pos - start); - return true; -} - -static bool -get_int(int *intp) -{ - char *save_pos = pos; - if (token && isdigit((unsigned char) *token)) { - *intp = strtol(token, NULL, 0); - get_token(); - return true; - } else { - pos = save_pos; - return false; - } -} - -static bool -match(const char *want) -{ - if (token && !strcmp(want, token)) { - get_token(); - return true; - } else { - return false; - } -} - -static int -must_get_int(void) -{ - int x; - if (!get_int(&x)) { - err("expected integer"); - } - return x; -} - -static void -must_match(const char *want) -{ - if (!match(want)) { - err("expected \"%s\"", want); - } -} - -int -main(int argc, char *argv[]) -{ - struct test_case *tc; - FILE *input_file; - int i; - - if (argc != 2) { - ovs_fatal(0, "usage: test-stp INPUT.STP\n"); - } - file_name = argv[1]; - - input_file = fopen(file_name, "r"); - if (!input_file) { - ovs_fatal(errno, "error opening \"%s\"", file_name); - } - - tc = new_test_case(); - for (i = 0; i < 26; i++) { - char name[2]; - name[0] = 'a' + i; - name[1] = '\0'; - new_lan(tc, name); - } - - for (line_number = 1; fgets(line, sizeof line, input_file); - line_number++) - { - char *newline, *hash; - - newline = strchr(line, '\n'); - if (newline) { - *newline = '\0'; - } - hash = strchr(line, '#'); - if (hash) { - *hash = '\0'; - } - - pos = line; - if (!get_token()) { - continue; - } - if (match("bridge")) { - struct bridge *bridge; - int bridge_no, port_no; - - bridge_no = must_get_int(); - if (bridge_no < tc->n_bridges) { - bridge = tc->bridges[bridge_no]; - } else if (bridge_no == tc->n_bridges) { - bridge = new_bridge(tc, must_get_int()); - } else { - err("bridges must be numbered consecutively from 0"); - } - if (match("^")) { - stp_set_bridge_priority(bridge->stp, must_get_int()); - } - - if (match("=")) { - for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) { - struct stp_port *p = stp_get_port(bridge->stp, port_no); - if (!token || match("X")) { - stp_port_disable(p); - } else if (match("_")) { - /* Nothing to do. */ - } else { - struct lan *lan; - int path_cost; - - if (!strcmp(token, "0")) { - lan = NULL; - } else if (strlen(token) == 1 - && islower((unsigned char)*token)) { - lan = tc->lans[*token - 'a']; - } else { - err("%s is not a valid LAN name " - "(0 or a lowercase letter)", token); - } - get_token(); - - path_cost = match(":") ? must_get_int() : 10; - if (port_no < bridge->n_ports) { - stp_port_set_path_cost(p, path_cost); - stp_port_enable(p); - reconnect_port(bridge, port_no, lan); - } else if (port_no == bridge->n_ports) { - new_port(bridge, lan, path_cost); - } else { - err("ports must be numbered consecutively"); - } - if (match("^")) { - stp_port_set_priority(p, must_get_int()); - } - } - } - } - } else if (match("run")) { - simulate(tc, must_get_int()); - } else if (match("dump")) { - dump(tc); - } else if (match("tree")) { - tree(tc); - } else if (match("check")) { - struct bridge *b; - struct stp *stp; - int bridge_no, port_no; - - bridge_no = must_get_int(); - if (bridge_no >= tc->n_bridges) { - err("no bridge numbered %d", bridge_no); - } - b = tc->bridges[bridge_no]; - stp = b->stp; - - must_match("="); - - if (match("rootid")) { - uint64_t rootid; - must_match(":"); - rootid = must_get_int(); - if (match("^")) { - rootid |= (uint64_t) must_get_int() << 48; - } else { - rootid |= UINT64_C(0x8000) << 48; - } - if (stp_get_designated_root(stp) != rootid) { - warn("%s: root %"PRIx64", not %"PRIx64, - stp_get_name(stp), stp_get_designated_root(stp), - rootid); - } - } - - if (match("root")) { - if (stp_get_root_path_cost(stp)) { - warn("%s: root path cost of root is %u but should be 0", - stp_get_name(stp), stp_get_root_path_cost(stp)); - } - if (!stp_is_root_bridge(stp)) { - warn("%s: root is %"PRIx64", not %"PRIx64, - stp_get_name(stp), - stp_get_designated_root(stp), stp_get_bridge_id(stp)); - } - for (port_no = 0; port_no < b->n_ports; port_no++) { - struct stp_port *p = stp_get_port(stp, port_no); - enum stp_state state = stp_port_get_state(p); - if (!(state & (STP_DISABLED | STP_FORWARDING))) { - warn("%s: root port %d in state %s", - stp_get_name(b->stp), port_no, - stp_state_name(state)); - } - } - } else { - for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) { - struct stp_port *p = stp_get_port(stp, port_no); - enum stp_state state; - if (token == NULL || match("D")) { - state = STP_DISABLED; - } else if (match("B")) { - state = STP_BLOCKING; - } else if (match("Li")) { - state = STP_LISTENING; - } else if (match("Le")) { - state = STP_LEARNING; - } else if (match("F")) { - state = STP_FORWARDING; - } else if (match("_")) { - continue; - } else { - err("unknown port state %s", token); - } - if (stp_port_get_state(p) != state) { - warn("%s port %d: state is %s but should be %s", - stp_get_name(stp), port_no, - stp_state_name(stp_port_get_state(p)), - stp_state_name(state)); - } - if (state == STP_FORWARDING) { - struct stp_port *root_port = stp_get_root_port(stp); - if (match(":")) { - int root_path_cost = must_get_int(); - if (p != root_port) { - warn("%s: port %d is not the root port", - stp_get_name(stp), port_no); - if (!root_port) { - warn("%s: (there is no root port)", - stp_get_name(stp)); - } else { - warn("%s: (port %d is the root port)", - stp_get_name(stp), - stp_port_no(root_port)); - } - } else if (root_path_cost - != stp_get_root_path_cost(stp)) { - warn("%s: root path cost is %u, should be %d", - stp_get_name(stp), - stp_get_root_path_cost(stp), - root_path_cost); - } - } else if (p == root_port) { - warn("%s: port %d is the root port but " - "not expected to be", - stp_get_name(stp), port_no); - } - } - } - } - if (n_warnings) { - exit(EXIT_FAILURE); - } - } - if (get_token()) { - err("trailing garbage on line"); - } - } - free(token); - - for (i = 0; i < tc->n_lans; i++) { - struct lan *lan = tc->lans[i]; - free((char *) lan->name); - free(lan); - } - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *bridge = tc->bridges[i]; - stp_destroy(bridge->stp); - free(bridge); - } - free(tc); - - return 0; -} diff --git a/tests/testsuite.at b/tests/testsuite.at index 5699e3c9..2eab5814 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -51,6 +51,5 @@ m4_include([tests/timeval.at]) m4_include([tests/lockfile.at]) m4_include([tests/reconnect.at]) m4_include([tests/ovsdb.at]) -m4_include([tests/stp.at]) m4_include([tests/ovs-vsctl.at]) m4_include([tests/interface-reconfigure.at]) diff --git a/utilities/ovs-controller.c b/utilities/ovs-controller.c index 42431bb0..3288e6f3 100644 --- a/utilities/ovs-controller.c +++ b/utilities/ovs-controller.c @@ -189,7 +189,7 @@ main(int argc, char *argv[]) } for (i = 0; i < n_switches; i++) { struct switch_ *this = &switches[i]; - lswitch_run(this->lswitch, this->rconn); + lswitch_run(this->lswitch); } unixctl_server_run(unixctl); diff --git a/utilities/ovs-openflowd.c b/utilities/ovs-openflowd.c index d3b7ff56..8cb50e4b 100644 --- a/utilities/ovs-openflowd.c +++ b/utilities/ovs-openflowd.c @@ -74,9 +74,6 @@ struct ofsettings { /* Failure behavior. */ int max_idle; /* Idle time for flows in fail-open mode. */ - /* Spanning tree protocol. */ - bool enable_stp; - /* NetFlow. */ struct svec netflow; /* NetFlow targets. */ }; @@ -150,10 +147,6 @@ main(int argc, char *argv[]) if (error) { ovs_fatal(error, "failed to configure NetFlow collectors"); } - error = ofproto_set_stp(ofproto, s.enable_stp); - if (error) { - ovs_fatal(error, "failed to configure STP"); - } ofproto_set_controllers(ofproto, s.controllers, s.n_controllers); ofproto_set_fail_mode(ofproto, s.fail_mode); @@ -203,8 +196,6 @@ parse_options(int argc, char *argv[], struct ofsettings *s) OPT_RATE_LIMIT, OPT_BURST_LIMIT, OPT_BOOTSTRAP_CA_CERT, - OPT_STP, - OPT_NO_STP, OPT_OUT_OF_BAND, OPT_IN_BAND, OPT_NETFLOW, @@ -231,8 +222,6 @@ parse_options(int argc, char *argv[], struct ofsettings *s) {"snoop", required_argument, 0, OPT_SNOOP}, {"rate-limit", optional_argument, 0, OPT_RATE_LIMIT}, {"burst-limit", required_argument, 0, OPT_BURST_LIMIT}, - {"stp", no_argument, 0, OPT_STP}, - {"no-stp", no_argument, 0, OPT_NO_STP}, {"out-of-band", no_argument, 0, OPT_OUT_OF_BAND}, {"in-band", no_argument, 0, OPT_IN_BAND}, {"netflow", required_argument, 0, OPT_NETFLOW}, @@ -273,7 +262,6 @@ parse_options(int argc, char *argv[], struct ofsettings *s) svec_init(&controllers); svec_init(&s->snoops); s->max_idle = 0; - s->enable_stp = false; svec_init(&s->netflow); svec_init(&s->ports); for (;;) { @@ -378,14 +366,6 @@ parse_options(int argc, char *argv[], struct ofsettings *s) } break; - case OPT_STP: - s->enable_stp = true; - break; - - case OPT_NO_STP: - s->enable_stp = false; - break; - case OPT_OUT_OF_BAND: controller_opts.band = OFPROTO_OUT_OF_BAND; break; -- 2.30.2