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 --- lib/stp.c | 21 +++++++++++++++++++++ lib/stp.h | 2 ++ ofproto/ofproto-dpif.c | 1 + ofproto/ofproto.h | 3 +++ vswitchd/bridge.c | 35 ++++++++++++++++++++++++++--------- vswitchd/vswitch.ovsschema | 7 +++++-- vswitchd/vswitch.xml | 20 ++++++++++++++++++++ 7 files changed, 78 insertions(+), 11 deletions(-) diff --git a/lib/stp.c b/lib/stp.c index 94b9a4b..62c2ea8 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 54f7f5b..ec29d9a 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 d525d4e..4cc7206 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 4b37bd7..eed4e50 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 5100b78..6a25b95 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 3a9c51f..19c5922 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 80d9cdc..9945eeb 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -986,6 +986,26 @@ </column> </group> + <group title="Port Statistics"> + <p> + Key-value pairs that report port statistics. + </p> + <group title="Statistics: STP transmit and receive counters"> + <column name="statistics" key="stp_tx_count"> + Number of STP BPDUs sent on this interface by the spanning + tree library. + </column> + <column name="statistics" key="stp_rx_count"> + Number of STP BPDUs received on this interface and accepted by + the spanning tree library. + </column> + <column name="statistics" key="stp_error_count"> + Number of bad STP BPDUs received on this interface. Bad BPDUs + include runt packets and those with an unexpected protocol ID. + </column> + </group> + </group> + <group title="Common Columns"> The overall purpose of these columns is described under <code>Common Columns</code> at the beginning of this document. -- 1.7.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev