X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fstp.c;h=467b0ba329d111152e979a96821ee8ddd61a4ee2;hb=d0a46cb4608e632f5028034762f0adde2ce947a0;hp=6e1efd07a952c7d67164188be7237507366eba32;hpb=834d6cafe4797861b7547966b4dcc95b374331be;p=cascardo%2Fovs.git diff --git a/lib/stp.c b/lib/stp.c index 6e1efd07a..467b0ba32 100644 --- a/lib/stp.c +++ b/lib/stp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,14 +26,20 @@ #include #include #include "byte-order.h" +#include "connectivity.h" #include "ofpbuf.h" +#include "ovs-atomic.h" +#include "dp-packet.h" #include "packets.h" +#include "seq.h" #include "unixctl.h" #include "util.h" -#include "vlog.h" +#include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(stp); +static struct vlog_rate_limit stp_rl = VLOG_RATE_LIMIT_INIT(60, 60); + #define STP_PROTOCOL_ID 0x0000 #define STP_PROTOCOL_VERSION 0x00 #define STP_TYPE_CONFIG 0x00 @@ -80,6 +86,7 @@ struct stp_timer { struct stp_port { struct stp *stp; + char *port_name; /* Human-readable name for log messages. */ void *aux; /* Auxiliary data the user may retrieve. */ int port_id; /* 8.5.5.1: Unique port identifier. */ enum stp_state state; /* 8.5.5.2: Current state. */ @@ -104,7 +111,7 @@ struct stp_port { }; struct stp { - struct list node; /* Node in all_stps list. */ + struct ovs_list node; /* Node in all_stps list. */ /* Static bridge data. */ char *name; /* Human-readable name for log messages. */ @@ -138,15 +145,15 @@ struct stp { /* Interface to client. */ bool fdb_needs_flush; /* MAC learning tables needs flushing. */ struct stp_port *first_changed_port; - void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux); + void (*send_bpdu)(struct dp_packet *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 ovs_list all_stps__ = OVS_LIST_INITIALIZER(&all_stps__); +static struct ovs_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); \ @@ -252,7 +259,7 @@ stp_init(void) */ struct stp * stp_create(const char *name, stp_identifier bridge_id, - void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux), + void (*send_bpdu)(struct dp_packet *bpdu, int port_no, void *aux), void *aux) { static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; @@ -304,7 +311,7 @@ stp_create(const char *name, stp_identifier bridge_id, 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); @@ -316,9 +323,7 @@ stp_ref(const struct stp *stp_) { 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; } @@ -327,19 +332,17 @@ stp_ref(const struct stp *stp_) void stp_unref(struct stp *stp) { - int orig; - - if (!stp) { - return; - } + if (stp && ovs_refcount_unref_relaxed(&stp->ref_cnt) == 1) { + size_t i; - atomic_sub(&stp->ref_cnt, 1, &orig); - ovs_assert(orig > 0); - if (orig == 1) { ovs_mutex_lock(&mutex); list_remove(&stp->node); ovs_mutex_unlock(&mutex); free(stp->name); + + for (i = 0; i < STP_MAX_PORTS; i++) { + free(stp->ports[i].port_name); + } free(stp); } } @@ -666,30 +669,40 @@ stp_state_name(enum stp_state state) case STP_BLOCKING: return "blocking"; default: - NOT_REACHED(); + OVS_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; + return (state & 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; + return (state & (STP_LEARNING | STP_FORWARDING)) != 0; +} + +/* Returns true if 'state' is one in which bpdus should be forwarded on a + * port, false otherwise. + * + * Returns true if 'state' is STP_DISABLED, since in that case the port does + * not generate the bpdu and should just forward it (e.g. patch port on pif + * bridge). */ +bool +stp_should_forward_bpdu(enum stp_state state) +{ + return (state & + ( STP_DISABLED | STP_LISTENING | STP_LEARNING + | STP_FORWARDING)) != 0; } /* Returns the name for the given 'role' (for use in debugging and log @@ -707,7 +720,7 @@ stp_role_name(enum stp_role role) case STP_ROLE_DISABLED: return "disabled"; default: - NOT_REACHED(); + OVS_NOT_REACHED(); } } @@ -727,7 +740,7 @@ stp_received_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size) } 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; } @@ -747,7 +760,7 @@ stp_received_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size) 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; @@ -757,7 +770,7 @@ stp_received_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size) 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; @@ -789,6 +802,18 @@ stp_port_get_stp(struct stp_port *p) return stp; } +void +stp_port_set_name(struct stp_port *p, const char *name) +{ + char *old; + + ovs_mutex_lock(&mutex); + old = p->port_name; + p->port_name = xstrdup(name); + free(old); + ovs_mutex_unlock(&mutex); +} + /* Sets the 'aux' member of 'p'. * * The 'aux' member will be reset to NULL when stp_port_disable() is @@ -1013,6 +1038,8 @@ stp_transmit_config(struct stp_port *p) OVS_REQUIRES(mutex) return; } if (p->hold_timer.active) { + VLOG_DBG_RL(&stp_rl, "bridge: %s, port: %s, transmit config bpdu pending", + stp->name, p->port_name); p->config_pending = true; } else { struct stp_config_bpdu config; @@ -1043,6 +1070,8 @@ stp_transmit_config(struct stp_port *p) OVS_REQUIRES(mutex) if (ntohs(config.message_age) < stp->max_age) { p->topology_change_ack = false; p->config_pending = false; + VLOG_DBG_RL(&stp_rl, "bridge: %s, port: %s, transmit config bpdu", + stp->name, p->port_name); stp_send_bpdu(p, &config, sizeof config); stp_start_timer(&p->hold_timer, 0); } @@ -1113,9 +1142,12 @@ stp_transmit_tcn(struct stp *stp) OVS_REQUIRES(mutex) { struct stp_port *p = stp->root_port; struct stp_tcn_bpdu tcn_bpdu; + if (!p) { return; } + VLOG_DBG_RL(&stp_rl, "bridge: %s, root port: %s, transmit tcn", stp->name, + p->port_name); 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; @@ -1127,6 +1159,7 @@ 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 @@ -1257,6 +1290,7 @@ stp_set_port_state(struct stp_port *p, enum stp_state state) if (p < p->stp->first_changed_port) { p->stp->first_changed_port = p; } + seq_change(connectivity_seq_get()); } p->state = state; } @@ -1275,6 +1309,7 @@ stp_topology_change_detection(struct stp *stp) OVS_REQUIRES(mutex) } 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); } @@ -1358,6 +1393,9 @@ stp_message_age_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex) { struct stp *stp = p->stp; bool root = stp_is_root_bridge(stp); + + VLOG_DBG_RL(&stp_rl, "bridge: %s, port: %s, message age timer expired", + stp->name, p->port_name); stp_become_designated_port(p); stp_configuration_update(stp); stp_port_state_selection(stp); @@ -1429,7 +1467,12 @@ stp_initialize_port(struct stp_port *p, enum stp_state state) { ovs_assert(state & (STP_DISABLED | STP_BLOCKING)); stp_become_designated_port(p); - stp_set_port_state(p, state); + + if (!p->state && state == STP_DISABLED) { + p->state = state; /* Do not trigger state change when initializing. */ + } else { + stp_set_port_state(p, state); + } p->topology_change_ack = false; p->config_pending = false; p->change_detection_enabled = true; @@ -1527,18 +1570,19 @@ 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; + struct dp_packet *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); + pkt = dp_packet_new(ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size); + eth = dp_packet_put_zeros(pkt, sizeof *eth); + llc = dp_packet_put_zeros(pkt, sizeof *llc); + dp_packet_reset_offsets(pkt); + dp_packet_set_l3(pkt, dp_packet_put(pkt, bpdu, bpdu_size)); /* 802.2 header. */ - memcpy(eth->eth_dst, eth_addr_stp, ETH_ADDR_LEN); + eth->eth_dst = eth_addr_stp; /* p->stp->send_bpdu() must fill in source address. */ - eth->eth_type = htons(pkt->size - ETH_HEADER_LEN); + eth->eth_type = htons(dp_packet_size(pkt) - ETH_HEADER_LEN); /* LLC header. */ llc->llc_dsap = STP_LLC_DSAP;