/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <inttypes.h>
#include <stdlib.h>
#include "byte-order.h"
+#include "connectivity.h"
#include "ofpbuf.h"
#include "packets.h"
+#include "seq.h"
#include "unixctl.h"
#include "util.h"
#include "vlog.h"
void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux);
void *aux;
- atomic_int ref_cnt;
+ struct ovs_refcount ref_cnt;
};
static struct ovs_mutex mutex;
static struct list all_stps__ = LIST_INITIALIZER(&all_stps__);
-static struct list *const all_stps OVS_GUARDED_BY(&mutex) = &all_stps__;
+static struct list *const all_stps OVS_GUARDED_BY(mutex) = &all_stps__;
#define FOR_EACH_ENABLED_PORT(PORT, STP) \
for ((PORT) = stp_next_enabled_port((STP), (STP)->ports); \
(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)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
for (; port < &stp->ports[ARRAY_SIZE(stp->ports)]; port++) {
if (port->state != STP_DISABLED) {
#define MESSAGE_AGE_INCREMENT 1
-static void stp_transmit_config(struct stp_port *) OVS_REQ_WRLOCK(mutex);
+static void stp_transmit_config(struct stp_port *) OVS_REQUIRES(mutex);
static bool stp_supersedes_port_info(const struct stp_port *,
const struct stp_config_bpdu *)
- OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
static void stp_record_config_information(struct stp_port *,
const struct stp_config_bpdu *)
- OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
static void stp_record_config_timeout_values(struct stp *,
const struct stp_config_bpdu *)
- OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
static bool stp_is_designated_port(const struct stp_port *)
- OVS_REQ_WRLOCK(mutex);
-static void stp_config_bpdu_generation(struct stp *) OVS_REQ_WRLOCK(mutex);
-static void stp_transmit_tcn(struct stp *) OVS_REQ_WRLOCK(mutex);
-static void stp_configuration_update(struct stp *) OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
+static void stp_config_bpdu_generation(struct stp *) OVS_REQUIRES(mutex);
+static void stp_transmit_tcn(struct stp *) OVS_REQUIRES(mutex);
+static void stp_configuration_update(struct stp *) OVS_REQUIRES(mutex);
static bool stp_supersedes_root(const struct stp_port *root,
- const struct stp_port *) OVS_REQ_WRLOCK(mutex);
-static void stp_root_selection(struct stp *) OVS_REQ_WRLOCK(mutex);
-static void stp_designated_port_selection(struct stp *) OVS_REQ_WRLOCK(mutex);
+ const struct stp_port *) OVS_REQUIRES(mutex);
+static void stp_root_selection(struct stp *) OVS_REQUIRES(mutex);
+static void stp_designated_port_selection(struct stp *) OVS_REQUIRES(mutex);
static void stp_become_designated_port(struct stp_port *)
- OVS_REQ_WRLOCK(mutex);
-static void stp_port_state_selection(struct stp *) OVS_REQ_WRLOCK(mutex);
-static void stp_make_forwarding(struct stp_port *) OVS_REQ_WRLOCK(mutex);
-static void stp_make_blocking(struct stp_port *) OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
+static void stp_port_state_selection(struct stp *) OVS_REQUIRES(mutex);
+static void stp_make_forwarding(struct stp_port *) OVS_REQUIRES(mutex);
+static void stp_make_blocking(struct stp_port *) OVS_REQUIRES(mutex);
static void stp_set_port_state(struct stp_port *, enum stp_state)
- OVS_REQ_WRLOCK(mutex);
-static void stp_topology_change_detection(struct stp *) OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
+static void stp_topology_change_detection(struct stp *) OVS_REQUIRES(mutex);
static void stp_topology_change_acknowledged(struct stp *)
- OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
static void stp_acknowledge_topology_change(struct stp_port *)
- OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
static void stp_received_config_bpdu(struct stp *, struct stp_port *,
const struct stp_config_bpdu *)
- OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
static void stp_received_tcn_bpdu(struct stp *, struct stp_port *)
- OVS_REQ_WRLOCK(mutex);
-static void stp_hello_timer_expiry(struct stp *) OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
+static void stp_hello_timer_expiry(struct stp *) OVS_REQUIRES(mutex);
static void stp_message_age_timer_expiry(struct stp_port *)
- OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
static bool stp_is_designated_for_some_port(const struct stp *)
- OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
static void stp_forward_delay_timer_expiry(struct stp_port *)
- OVS_REQ_WRLOCK(mutex);
-static void stp_tcn_timer_expiry(struct stp *) OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
+static void stp_tcn_timer_expiry(struct stp *) OVS_REQUIRES(mutex);
static void stp_topology_change_timer_expiry(struct stp *)
- OVS_REQ_WRLOCK(mutex);
-static void stp_hold_timer_expiry(struct stp_port *) OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
+static void stp_hold_timer_expiry(struct stp_port *) OVS_REQUIRES(mutex);
static void stp_initialize_port(struct stp_port *, enum stp_state)
- OVS_REQ_WRLOCK(mutex);
-static void stp_become_root_bridge(struct stp *) OVS_REQ_WRLOCK(mutex);
-static void stp_update_bridge_timers(struct stp *) OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
+static void stp_become_root_bridge(struct stp *) OVS_REQUIRES(mutex);
+static void stp_update_bridge_timers(struct stp *) OVS_REQUIRES(mutex);
static int clamp(int x, int min, int max);
static int ms_to_timer(int ms);
static bool stp_timer_expired(struct stp_timer *, int elapsed, int timeout);
static void stp_send_bpdu(struct stp_port *, const void *, size_t)
- OVS_REQ_WRLOCK(mutex);
+ OVS_REQUIRES(mutex);
static void stp_unixctl_tcn(struct unixctl_conn *, int argc,
const char *argv[], void *aux);
* into the stp module through a patch port. This happens
* intentionally as part of the unit tests. Ideally we'd ditch
* the call back function, but for now this is what we have. */
- ovs_mutex_init(&mutex, PTHREAD_MUTEX_RECURSIVE);
+ ovs_mutex_init_recursive(&mutex);
ovsthread_once_done(&once);
}
p->path_cost = 19; /* Recommended default for 100 Mb/s link. */
stp_initialize_port(p, STP_DISABLED);
}
- atomic_init(&stp->ref_cnt, 1);
+ ovs_refcount_init(&stp->ref_cnt);
list_push_back(all_stps, &stp->node);
ovs_mutex_unlock(&mutex);
{
struct stp *stp = CONST_CAST(struct stp *, stp_);
if (stp) {
- int orig;
- atomic_add(&stp->ref_cnt, 1, &orig);
- ovs_assert(orig > 0);
+ ovs_refcount_ref(&stp->ref_cnt);
}
return stp;
}
void
stp_unref(struct stp *stp)
{
- int orig;
-
- if (!stp) {
- return;
- }
-
- atomic_sub(&stp->ref_cnt, 1, &orig);
- ovs_assert(orig > 0);
- if (orig == 1) {
+ if (stp && ovs_refcount_unref(&stp->ref_cnt) == 1) {
ovs_mutex_lock(&mutex);
list_remove(&stp->node);
ovs_mutex_unlock(&mutex);
free(stp->name);
+ ovs_refcount_destroy(&stp->ref_cnt);
free(stp);
}
}
static void
set_bridge_id(struct stp *stp, stp_identifier new_bridge_id)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
if (new_bridge_id != stp->bridge_id) {
bool root;
case STP_BLOCKING:
return "blocking";
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
}
case STP_ROLE_DISABLED:
return "disabled";
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
}
}
if (bpdu_size < sizeof(struct stp_bpdu_header)) {
- VLOG_WARN("%s: received runt %zu-byte BPDU", stp->name, bpdu_size);
+ VLOG_WARN("%s: received runt %"PRIuSIZE"-byte BPDU", stp->name, bpdu_size);
p->error_count++;
goto out;
}
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",
+ VLOG_WARN("%s: received config BPDU with invalid size %"PRIuSIZE,
stp->name, bpdu_size);
p->error_count++;
goto out;
case STP_TYPE_TCN:
if (bpdu_size != sizeof(struct stp_tcn_bpdu)) {
- VLOG_WARN("%s: received TCN BPDU with invalid size %zu",
+ VLOG_WARN("%s: received TCN BPDU with invalid size %"PRIuSIZE,
stp->name, bpdu_size);
p->error_count++;
goto out;
}
\f
static void
-stp_transmit_config(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_transmit_config(struct stp_port *p) OVS_REQUIRES(mutex)
{
struct stp *stp = p->stp;
bool root = stp_is_root_bridge(stp);
static bool
stp_supersedes_port_info(const struct stp_port *p,
const struct stp_config_bpdu *config)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
if (ntohll(config->root_id) != p->designated_root) {
return ntohll(config->root_id) < p->designated_root;
static void
stp_record_config_information(struct stp_port *p,
const struct stp_config_bpdu *config)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
p->designated_root = ntohll(config->root_id);
p->designated_cost = ntohl(config->root_path_cost);
static void
stp_record_config_timeout_values(struct stp *stp,
const struct stp_config_bpdu *config)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
stp->max_age = ntohs(config->max_age);
stp->hello_time = ntohs(config->hello_time);
}
static bool
-stp_is_designated_port(const struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_is_designated_port(const struct stp_port *p) OVS_REQUIRES(mutex)
{
return (p->designated_bridge == p->stp->bridge_id
&& p->designated_port == p->port_id);
}
static void
-stp_config_bpdu_generation(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_config_bpdu_generation(struct stp *stp) OVS_REQUIRES(mutex)
{
struct stp_port *p;
}
static void
-stp_transmit_tcn(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_transmit_tcn(struct stp *stp) OVS_REQUIRES(mutex)
{
struct stp_port *p = stp->root_port;
struct stp_tcn_bpdu tcn_bpdu;
}
static void
-stp_configuration_update(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_configuration_update(struct stp *stp) OVS_REQUIRES(mutex)
{
stp_root_selection(stp);
stp_designated_port_selection(stp);
+ seq_change(connectivity_seq_get());
}
static bool
stp_supersedes_root(const struct stp_port *root, const struct stp_port *p)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
int p_cost = p->designated_cost + p->path_cost;
int root_cost = root->designated_cost + root->path_cost;
}
static void
-stp_root_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_root_selection(struct stp *stp) OVS_REQUIRES(mutex)
{
struct stp_port *p, *root;
}
static void
-stp_designated_port_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_designated_port_selection(struct stp *stp) OVS_REQUIRES(mutex)
{
struct stp_port *p;
}
static void
-stp_become_designated_port(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_become_designated_port(struct stp_port *p) OVS_REQUIRES(mutex)
{
struct stp *stp = p->stp;
p->designated_root = stp->designated_root;
}
static void
-stp_port_state_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_port_state_selection(struct stp *stp) OVS_REQUIRES(mutex)
{
struct stp_port *p;
}
static void
-stp_make_forwarding(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_make_forwarding(struct stp_port *p) OVS_REQUIRES(mutex)
{
if (p->state == STP_BLOCKING) {
stp_set_port_state(p, STP_LISTENING);
}
static void
-stp_make_blocking(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_make_blocking(struct stp_port *p) OVS_REQUIRES(mutex)
{
if (!(p->state & (STP_DISABLED | STP_BLOCKING))) {
if (p->state & (STP_FORWARDING | STP_LEARNING)) {
static void
stp_set_port_state(struct stp_port *p, enum stp_state state)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
if (state != p->state && !p->state_changed) {
p->state_changed = true;
if (p < p->stp->first_changed_port) {
p->stp->first_changed_port = p;
}
+ seq_change(connectivity_seq_get());
}
p->state = state;
}
static void
-stp_topology_change_detection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_topology_change_detection(struct stp *stp) OVS_REQUIRES(mutex)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
}
stp->fdb_needs_flush = true;
stp->topology_change_detected = true;
+ seq_change(connectivity_seq_get());
VLOG_INFO_RL(&rl, "%s: detected topology change.", stp->name);
}
static void
-stp_topology_change_acknowledged(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_topology_change_acknowledged(struct stp *stp) OVS_REQUIRES(mutex)
{
stp->topology_change_detected = false;
stp_stop_timer(&stp->tcn_timer);
}
static void
-stp_acknowledge_topology_change(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_acknowledge_topology_change(struct stp_port *p) OVS_REQUIRES(mutex)
{
p->topology_change_ack = true;
stp_transmit_config(p);
static void
stp_received_config_bpdu(struct stp *stp, struct stp_port *p,
const struct stp_config_bpdu *config)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
if (ntohs(config->message_age) >= ntohs(config->max_age)) {
VLOG_WARN("%s: received config BPDU with message age (%u) greater "
static void
stp_received_tcn_bpdu(struct stp *stp, struct stp_port *p)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
if (p->state != STP_DISABLED) {
if (stp_is_designated_port(p)) {
}
static void
-stp_hello_timer_expiry(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_hello_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
{
stp_config_bpdu_generation(stp);
stp_start_timer(&stp->hello_timer, 0);
}
static void
-stp_message_age_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_message_age_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
{
struct stp *stp = p->stp;
bool root = stp_is_root_bridge(stp);
}
static bool
-stp_is_designated_for_some_port(const struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_is_designated_for_some_port(const struct stp *stp) OVS_REQUIRES(mutex)
{
const struct stp_port *p;
}
static void
-stp_forward_delay_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_forward_delay_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
{
if (p->state == STP_LISTENING) {
stp_set_port_state(p, STP_LEARNING);
}
static void
-stp_tcn_timer_expiry(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_tcn_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
{
stp_transmit_tcn(stp);
stp_start_timer(&stp->tcn_timer, 0);
}
static void
-stp_topology_change_timer_expiry(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_topology_change_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
{
stp->topology_change_detected = false;
stp->topology_change = false;
}
static void
-stp_hold_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_hold_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
{
if (p->config_pending) {
stp_transmit_config(p);
static void
stp_initialize_port(struct stp_port *p, enum stp_state state)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
ovs_assert(state & (STP_DISABLED | STP_BLOCKING));
stp_become_designated_port(p);
}
static void
-stp_become_root_bridge(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_become_root_bridge(struct stp *stp) OVS_REQUIRES(mutex)
{
stp->max_age = stp->bridge_max_age;
stp->hello_time = stp->bridge_hello_time;
}
static void
-stp_start_timer(struct stp_timer *timer, int value) OVS_REQ_WRLOCK(mutex)
+stp_start_timer(struct stp_timer *timer, int value) OVS_REQUIRES(mutex)
{
timer->value = value;
timer->active = true;
}
static void
-stp_stop_timer(struct stp_timer *timer) OVS_REQ_WRLOCK(mutex)
+stp_stop_timer(struct stp_timer *timer) OVS_REQUIRES(mutex)
{
timer->active = false;
}
static bool
stp_timer_expired(struct stp_timer *timer, int elapsed, int timeout)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
if (timer->active) {
timer->value += elapsed;
}
static void
-stp_update_bridge_timers(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_update_bridge_timers(struct stp *stp) OVS_REQUIRES(mutex)
{
int ht, ma, fd;
static void
stp_send_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size)
- OVS_REQ_WRLOCK(mutex)
+ OVS_REQUIRES(mutex)
{
struct eth_header *eth;
struct llc_header *llc;
/* Unixctl. */
static struct stp *
-stp_find(const char *name) OVS_REQ_WRLOCK(mutex)
+stp_find(const char *name) OVS_REQUIRES(mutex)
{
struct stp *stp;