mirror of
https://github.com/openvswitch/ovs
synced 2025-09-05 00:35:33 +00:00
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.
This commit is contained in:
@@ -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 {
|
||||
|
@@ -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 \
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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 *,
|
||||
|
@@ -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;
|
||||
|
103
lib/stp.h
103
lib/stp.h
@@ -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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#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 */
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
@@ -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 *);
|
||||
|
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@@ -21,7 +21,6 @@
|
||||
/test-reconnect
|
||||
/test-timeval
|
||||
/test-sha1
|
||||
/test-stp
|
||||
/test-type-props
|
||||
/test-uuid
|
||||
/test-vconn
|
||||
|
@@ -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
|
||||
|
303
tests/stp.at
303
tests/stp.at
@@ -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
|
||||
|
666
tests/test-stp.c
666
tests/test-stp.c
@@ -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 <config.h>
|
||||
|
||||
#include "stp.h"
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
}
|
@@ -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])
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user