From: Justin Pettit Date: Mon, 14 Nov 2011 23:04:14 +0000 (-0800) Subject: stp: Track BPDU tx and rx counts. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=80740385d2700b1a03d28a02338d02509fd0b697;p=openvswitch stp: Track BPDU tx and rx counts. When debugging spanning tree, it's useful to have counters about how many BPDUs have been sent and received. This commit keeps track of these counters and stores them in a new "statistics" column of the Port table. Feature #8103 --- diff --git a/lib/stp.c b/lib/stp.c index 94b9a4b5..62c2ea8a 100644 --- a/lib/stp.c +++ b/lib/stp.c @@ -93,6 +93,10 @@ struct stp_port { 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. */ + int tx_count; /* Number of BPDUs transmitted. */ + int rx_count; /* Number of valid BPDUs received. */ + int error_count; /* Number of bad BPDUs received. */ + bool state_changed; }; @@ -562,6 +566,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); + p->error_count++; return; } @@ -569,6 +574,7 @@ stp_received_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size) if (header->protocol_id != htons(STP_PROTOCOL_ID)) { VLOG_WARN("%s: received BPDU with unexpected protocol ID %"PRIu16, stp->name, ntohs(header->protocol_id)); + p->error_count++; return; } if (header->protocol_version != STP_PROTOCOL_VERSION) { @@ -581,6 +587,7 @@ stp_received_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size) if (bpdu_size < sizeof(struct stp_config_bpdu)) { VLOG_WARN("%s: received config BPDU with invalid size %zu", stp->name, bpdu_size); + p->error_count++; return; } stp_received_config_bpdu(stp, p, bpdu); @@ -590,6 +597,7 @@ stp_received_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size) if (bpdu_size != sizeof(struct stp_tcn_bpdu)) { VLOG_WARN("%s: received TCN BPDU with invalid size %zu", stp->name, bpdu_size); + p->error_count++; return; } stp_received_tcn_bpdu(stp, p); @@ -598,8 +606,10 @@ stp_received_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size) default: VLOG_WARN("%s: received BPDU of unexpected type %"PRIu8, stp->name, header->bpdu_type); + p->error_count++; return; } + p->rx_count++; } /* Returns the STP entity in which 'p' is nested. */ @@ -667,6 +677,15 @@ stp_port_get_role(const struct stp_port *p) } } +/* Retrieves BPDU transmit and receive counts for 'p'. */ +void stp_port_get_counts(const struct stp_port *p, + int *tx_count, int *rx_count, int *error_count) +{ + *tx_count = p->tx_count; + *rx_count = p->rx_count; + *error_count = p->error_count; +} + /* Disables STP on port 'p'. */ void stp_port_disable(struct stp_port *p) @@ -1185,6 +1204,7 @@ stp_initialize_port(struct stp_port *p, enum stp_state state) stp_stop_timer(&p->message_age_timer); stp_stop_timer(&p->forward_delay_timer); stp_stop_timer(&p->hold_timer); + p->tx_count = p->rx_count = p->error_count = 0; } static void @@ -1299,4 +1319,5 @@ stp_send_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size) llc->llc_cntl = STP_LLC_CNTL; p->stp->send_bpdu(pkt, stp_port_no(p), p->stp->aux); + p->tx_count++; } diff --git a/lib/stp.h b/lib/stp.h index 54f7f5b4..ec29d9a7 100644 --- a/lib/stp.h +++ b/lib/stp.h @@ -136,6 +136,8 @@ int stp_port_no(const struct stp_port *); int stp_port_get_id(const struct stp_port *); enum stp_state stp_port_get_state(const struct stp_port *); enum stp_role stp_port_get_role(const struct stp_port *); +void stp_port_get_counts(const struct stp_port *, + int *tx_count, int *rx_count, int *error_count); 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); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index d525d4e7..4cc72066 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1105,6 +1105,7 @@ get_stp_port_status(struct ofport *ofport_, s->state = stp_port_get_state(sp); s->sec_in_state = (time_msec() - ofport->stp_state_entered) / 1000; s->role = stp_port_get_role(sp); + stp_port_get_counts(sp, &s->tx_count, &s->rx_count, &s->error_count); return 0; } diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h index 4b37bd78..eed4e508 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -94,6 +94,9 @@ struct ofproto_port_stp_status { enum stp_state state; unsigned int sec_in_state; enum stp_role role; + int tx_count; /* Number of BPDUs transmitted. */ + int rx_count; /* Number of valid BPDUs received. */ + int error_count; /* Number of bad BPDUs received. */ }; /* How the switch should act if the controller cannot be contacted. */ diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 5100b787..6a25b959 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -240,6 +240,7 @@ bridge_init(const char *remote) ovsdb_idl_omit(idl, &ovsrec_bridge_col_external_ids); ovsdb_idl_omit_alert(idl, &ovsrec_port_col_status); + ovsdb_idl_omit_alert(idl, &ovsrec_port_col_statistics); ovsdb_idl_omit(idl, &ovsrec_port_col_external_ids); ovsdb_idl_omit(idl, &ovsrec_port_col_fake_bridge); @@ -1598,7 +1599,9 @@ port_refresh_stp_status(struct port *port) struct ofproto *ofproto = port->bridge->ofproto; struct iface *iface; struct ofproto_port_stp_status status; - char *keys[4], *values[4]; + char *keys[4]; + char *str_values[4]; + int64_t int_values[3]; size_t i; if (port_is_synthetic(port)) { @@ -1619,23 +1622,37 @@ port_refresh_stp_status(struct port *port) if (!status.enabled) { ovsrec_port_set_status(port->cfg, NULL, NULL, 0); + ovsrec_port_set_statistics(port->cfg, NULL, NULL, 0); return; } - keys[0] = "stp_port_id"; - values[0] = xasprintf(STP_PORT_ID_FMT, status.port_id); + /* Set Status column. */ + keys[0] = "stp_port_id"; + str_values[0] = xasprintf(STP_PORT_ID_FMT, status.port_id); keys[1] = "stp_state"; - values[1] = xstrdup(stp_state_name(status.state)); + str_values[1] = xstrdup(stp_state_name(status.state)); keys[2] = "stp_sec_in_state"; - values[2] = xasprintf("%u", status.sec_in_state); + str_values[2] = xasprintf("%u", status.sec_in_state); keys[3] = "stp_role"; - values[3] = xstrdup(stp_role_name(status.role)); + str_values[3] = xstrdup(stp_role_name(status.role)); - ovsrec_port_set_status(port->cfg, keys, values, ARRAY_SIZE(values)); + ovsrec_port_set_status(port->cfg, keys, str_values, + ARRAY_SIZE(str_values)); - for (i = 0; i < ARRAY_SIZE(values); i++) { - free(values[i]); + for (i = 0; i < ARRAY_SIZE(str_values); i++) { + free(str_values[i]); } + + /* Set Statistics column. */ + keys[0] = "stp_tx_count"; + int_values[0] = status.tx_count; + keys[1] = "stp_rx_count"; + int_values[1] = status.rx_count; + keys[2] = "stp_error_count"; + int_values[2] = status.error_count; + + ovsrec_port_set_statistics(port->cfg, keys, int_values, + ARRAY_SIZE(int_values)); } static bool diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema index 3a9c51fb..19c59227 100644 --- a/vswitchd/vswitch.ovsschema +++ b/vswitchd/vswitch.ovsschema @@ -1,6 +1,6 @@ {"name": "Open_vSwitch", - "version": "6.2.0", - "cksum": "145151998 15203", + "version": "6.3.0", + "cksum": "1659474737 15341", "tables": { "Open_vSwitch": { "columns": { @@ -150,6 +150,9 @@ "status": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}, "ephemeral": true}, + "statistics": { + "type": {"key": "string", "value": "integer", "min": 0, "max": "unlimited"}, + "ephemeral": true}, "other_config": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}, "external_ids": { diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 80d9cdcc..7d2a72a7 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -986,6 +986,26 @@ + +

+ Key-value pairs that report port statistics. +

+ + + Number of STP BPDUs sent on this port by the spanning + tree library. + + + Number of STP BPDUs received on this port and accepted by the + spanning tree library. + + + Number of bad STP BPDUs received on this port. Bad BPDUs + include runt packets and those with an unexpected protocol ID. + + +
+ The overall purpose of these columns is described under Common Columns at the beginning of this document.