@@ -12,6 +12,8 @@ Post-v2.9.0
default it always accepts names and in interactive use it displays them;
use --names or --no-names to override. See ovs-ofctl(8) for details.
- ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface".
+ - ovs-appctl:
+ * New command "lacp/show-stats"
- OpenFlow:
* OFPT_ROLE_STATUS is now available in OpenFlow 1.3.
- Linux kernel 4.14
@@ -127,9 +127,12 @@ struct slave {
struct timer tx; /* Next message transmission timer. */
struct timer rx; /* Expected message receive timer. */
- uint32_t count_rx_pdus; /* dot3adAggPortStatsLACPDUsRx */
- uint32_t count_rx_pdus_bad; /* dot3adAggPortStatsIllegalRx */
- uint32_t count_tx_pdus; /* dot3adAggPortStatsLACPDUsTx */
+ uint32_t count_rx_pdus; /* dot3adAggPortStatsLACPDUsRx */
+ uint32_t count_rx_pdus_bad; /* dot3adAggPortStatsIllegalRx */
+ uint32_t count_tx_pdus; /* dot3adAggPortStatsLACPDUsTx */
+ uint32_t count_link_expired; /* Num of times link expired */
+ uint32_t count_link_defaulted; /* Num of times link defaulted */
+ uint32_t count_carrier_changed; /* Num of times link status changed */
};
static struct ovs_mutex mutex;
@@ -153,6 +156,7 @@ static bool info_tx_equal(struct lacp_info *, struct lacp_info *)
OVS_REQUIRES(mutex);
static unixctl_cb_func lacp_unixctl_show;
+static unixctl_cb_func lacp_unixctl_show_stats;
/* Populates 'pdu' with a LACP PDU comprised of 'actor' and 'partner'. */
static void
@@ -206,6 +210,8 @@ lacp_init(void)
{
unixctl_command_register("lacp/show", "[port]", 0, 1,
lacp_unixctl_show, NULL);
+ unixctl_command_register("lacp/show-stats", "[port]", 0, 1,
+ lacp_unixctl_show_stats, NULL);
}
static void
@@ -459,6 +465,7 @@ lacp_slave_carrier_changed(const struct lacp *lacp, const void *slave_)
if (slave->status == LACP_CURRENT || slave->lacp->active) {
slave_set_expired(slave);
}
+ slave->count_carrier_changed++;
out:
lacp_unlock();
@@ -525,8 +532,10 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex)
if (slave->status == LACP_CURRENT) {
slave_set_expired(slave);
+ slave->count_link_expired++;
} else if (slave->status == LACP_EXPIRED) {
slave_set_defaulted(slave);
+ slave->count_link_defaulted++;
}
if (slave->status != old_status) {
seq_change(connectivity_seq_get());
@@ -994,6 +1003,40 @@ lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
}
static void
+lacp_print_stats(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
+{
+ struct shash slave_shash = SHASH_INITIALIZER(&slave_shash);
+ const struct shash_node **sorted_slaves = NULL;
+
+ struct slave *slave;
+ int i;
+
+ ds_put_format(ds, "---- %s statistics ----\n", lacp->name);
+
+ HMAP_FOR_EACH (slave, node, &lacp->slaves) {
+ shash_add(&slave_shash, slave->name, slave);
+ }
+ sorted_slaves = shash_sort(&slave_shash);
+
+ for (i = 0; i < shash_count(&slave_shash); i++) {
+ slave = sorted_slaves[i]->data;
+ ds_put_format(ds, "\nslave: %s:\n", slave->name);
+ ds_put_format(ds, "\tRX PDUs: %u\n", slave->count_rx_pdus);
+ ds_put_format(ds, "\tRX Bad PDUs: %u\n", slave->count_rx_pdus_bad);
+ ds_put_format(ds, "\tTX PDUs: %u\n", slave->count_tx_pdus);
+ ds_put_format(ds, "\tLink Expired: %u\n",
+ slave->count_link_expired);
+ ds_put_format(ds, "\tLink Defaulted: %u\n",
+ slave->count_link_defaulted);
+ ds_put_format(ds, "\tCarrier Status Changed: %u\n",
+ slave->count_carrier_changed);
+ }
+
+ shash_destroy(&slave_shash);
+ free(sorted_slaves);
+}
+
+static void
lacp_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[],
void *aux OVS_UNUSED) OVS_EXCLUDED(mutex)
{
@@ -1021,6 +1064,36 @@ out:
lacp_unlock();
}
+static void
+lacp_unixctl_show_stats(struct unixctl_conn *conn,
+ int argc,
+ const char *argv[],
+ void *aux OVS_UNUSED) OVS_EXCLUDED(mutex)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ struct lacp *lacp;
+
+ lacp_lock();
+ if (argc > 1) {
+ lacp = lacp_find(argv[1]);
+ if (!lacp) {
+ unixctl_command_reply_error(conn, "no such lacp object");
+ goto out;
+ }
+ lacp_print_stats(&ds, lacp);
+ } else {
+ LIST_FOR_EACH (lacp, node, all_lacps) {
+ lacp_print_stats(&ds, lacp);
+ }
+ }
+
+ unixctl_command_reply(conn, ds_cstr(&ds));
+ ds_destroy(&ds);
+
+out:
+ lacp_unlock();
+}
+
/* Extract a snapshot of the current state and counters for a slave port.
Return false if the slave is not active. */
bool
@@ -240,6 +240,12 @@ whether it is attached or detached, port id and priority, actor
information, and partner information. If \fIport\fR is not specified,
then displays detailed information about all interfaces with CFM
enabled.
+.
+.IP "\fBlacp/stats-show\fR [\fIport\fR]"
+Lists various stats about LACP PDUs (number of RX/TX PDUs, bad PDUs received)
+and slave state (number of time slave's state expired/defaulted and carrier
+status changed) for the given \fIport\fR. If \fIport\fR is not specified,
+then displays stats of all interfaces with LACP enabled.
.SS "DPCTL DATAPATH DEBUGGING COMMANDS"
The primary way to configure \fBovs\-vswitchd\fR is through the Open
vSwitch database, e.g. using \fBovs\-vsctl\fR(8). These commands
Currently OVS does not provide any command to display stats for LACP without which it is difficult to debug LACP issues. Here we propose to display various statistics about LACP PDUs and slave state change. Sample output: ovs_lacp # ovs-appctl lacp/stats-show ---- bond-prv statistics ---- slave: dpdk0: RX PDUs: 128 RX Bad PDUs: 0 TX PDUs: 5 Link Expired: 2 Link Defaulted: 1 Carrier Status Changed: 0 Signed-off-by: Nitin Katiyar <nitin.katiyar@ericsson.com> --- NEWS | 2 ++ lib/lacp.c | 79 ++++++++++++++++++++++++++++++++++++++++++++-- vswitchd/ovs-vswitchd.8.in | 6 ++++ 3 files changed, 84 insertions(+), 3 deletions(-)