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;
};
if (bpdu_size < sizeof(struct stp_bpdu_header)) {
VLOG_WARN("%s: received runt %zu-byte BPDU", stp->name, bpdu_size);
+ p->error_count++;
return;
}
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) {
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);
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);
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. */
}
}
+/* 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)
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
llc->llc_cntl = STP_LLC_CNTL;
p->stp->send_bpdu(pkt, stp_port_no(p), p->stp->aux);
+ p->tx_count++;
}
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);
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;
}
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. */
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);
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)) {
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
{"name": "Open_vSwitch",
- "version": "6.2.0",
- "cksum": "145151998 15203",
+ "version": "6.3.0",
+ "cksum": "1659474737 15341",
"tables": {
"Open_vSwitch": {
"columns": {
"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": {
</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 port by the spanning
+ tree library.
+ </column>
+ <column name="statistics" key="stp_rx_count">
+ Number of STP BPDUs received on this port and accepted by the
+ spanning tree library.
+ </column>
+ <column name="statistics" key="stp_error_count">
+ Number of bad STP BPDUs received on this port. 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.