Skip to content

Commit

Permalink
Merge branch 'bonding-add-3ad-stats-and-export-them-via-xstats'
Browse files Browse the repository at this point in the history
Nikolay Aleksandrov says:

====================
bonding: add 3ad stats and export them via xstats

This set adds support for counting some 3ad-specific packet types and
exports the new stats via the xstats API. atomic64 counters are used
since these are not fastpaths and we can avoid the per-cpu allocations.
Each 3ad counter is exported as a separate attribute to be easily
extensible since we plan to add more later. The stats are per-slave and
when the master stats are requested the slaves' stats are summed up.
Patches 01 and 02 do minor cleanups in preparation for the new stats
API. Patch 03 adds the new stats and patch 04 adds xstats support to
export them.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jan 22, 2019
2 parents 1435d99 + a258aea commit cc648f8
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 50 deletions.
201 changes: 151 additions & 50 deletions drivers/net/bonding/bond_3ad.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <net/net_namespace.h>
#include <net/bonding.h>
#include <net/bond_3ad.h>
#include <net/netlink.h>

/* General definitions */
#define AD_SHORT_TIMEOUT 1
Expand Down Expand Up @@ -851,6 +852,8 @@ static int ad_lacpdu_send(struct port *port)
if (!skb)
return -ENOMEM;

atomic64_inc(&SLAVE_AD_INFO(slave)->stats.lacpdu_tx);

skb->dev = slave->dev;
skb_reset_mac_header(skb);
skb->network_header = skb->mac_header + ETH_HLEN;
Expand Down Expand Up @@ -892,6 +895,15 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker)
if (!skb)
return -ENOMEM;

switch (marker->tlv_type) {
case AD_MARKER_INFORMATION_SUBTYPE:
atomic64_inc(&SLAVE_AD_INFO(slave)->stats.marker_tx);
break;
case AD_MARKER_RESPONSE_SUBTYPE:
atomic64_inc(&SLAVE_AD_INFO(slave)->stats.marker_resp_tx);
break;
}

skb_reserve(skb, 16);

skb->dev = slave->dev;
Expand Down Expand Up @@ -1086,6 +1098,9 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
*/
last_state = port->sm_rx_state;

if (lacpdu)
atomic64_inc(&SLAVE_AD_INFO(port->slave)->stats.lacpdu_rx);

/* check if state machine should change state */

/* first, check if port was reinitialized */
Expand Down Expand Up @@ -1922,6 +1937,8 @@ static void ad_marker_info_received(struct bond_marker *marker_info,
{
struct bond_marker marker;

atomic64_inc(&SLAVE_AD_INFO(port->slave)->stats.marker_rx);

/* copy the received marker data to the response marker */
memcpy(&marker, marker_info, sizeof(struct bond_marker));
/* change the marker subtype to marker response */
Expand All @@ -1946,6 +1963,8 @@ static void ad_marker_info_received(struct bond_marker *marker_info,
static void ad_marker_response_received(struct bond_marker *marker,
struct port *port)
{
atomic64_inc(&SLAVE_AD_INFO(port->slave)->stats.marker_resp_rx);

/* DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW */
}

Expand Down Expand Up @@ -2348,66 +2367,64 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
* bond_3ad_rx_indication - handle a received frame
* @lacpdu: received lacpdu
* @slave: slave struct to work on
* @length: length of the data received
*
* It is assumed that frames that were sent on this NIC don't returned as new
* received frames (loopback). Since only the payload is given to this
* function, it check for loopback.
*/
static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave,
u16 length)
static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave)
{
struct port *port;
int ret = RX_HANDLER_ANOTHER;
struct bond_marker *marker;
struct port *port;
atomic64_t *stat;

if (length >= sizeof(struct lacpdu)) {

port = &(SLAVE_AD_INFO(slave)->port);

if (!port->slave) {
net_warn_ratelimited("%s: Warning: port of slave %s is uninitialized\n",
slave->dev->name, slave->bond->dev->name);
return ret;
}
port = &(SLAVE_AD_INFO(slave)->port);
if (!port->slave) {
net_warn_ratelimited("%s: Warning: port of slave %s is uninitialized\n",
slave->dev->name, slave->bond->dev->name);
return ret;
}

switch (lacpdu->subtype) {
case AD_TYPE_LACPDU:
ret = RX_HANDLER_CONSUMED;
netdev_dbg(slave->bond->dev,
"Received LACPDU on port %d slave %s\n",
port->actor_port_number,
slave->dev->name);
/* Protect against concurrent state machines */
spin_lock(&slave->bond->mode_lock);
ad_rx_machine(lacpdu, port);
spin_unlock(&slave->bond->mode_lock);
switch (lacpdu->subtype) {
case AD_TYPE_LACPDU:
ret = RX_HANDLER_CONSUMED;
netdev_dbg(slave->bond->dev,
"Received LACPDU on port %d slave %s\n",
port->actor_port_number, slave->dev->name);
/* Protect against concurrent state machines */
spin_lock(&slave->bond->mode_lock);
ad_rx_machine(lacpdu, port);
spin_unlock(&slave->bond->mode_lock);
break;
case AD_TYPE_MARKER:
ret = RX_HANDLER_CONSUMED;
/* No need to convert fields to Little Endian since we
* don't use the marker's fields.
*/
marker = (struct bond_marker *)lacpdu;
switch (marker->tlv_type) {
case AD_MARKER_INFORMATION_SUBTYPE:
netdev_dbg(slave->bond->dev, "Received Marker Information on port %d\n",
port->actor_port_number);
ad_marker_info_received(marker, port);
break;

case AD_TYPE_MARKER:
ret = RX_HANDLER_CONSUMED;
/* No need to convert fields to Little Endian since we
* don't use the marker's fields.
*/

switch (((struct bond_marker *)lacpdu)->tlv_type) {
case AD_MARKER_INFORMATION_SUBTYPE:
netdev_dbg(slave->bond->dev, "Received Marker Information on port %d\n",
port->actor_port_number);
ad_marker_info_received((struct bond_marker *)lacpdu, port);
break;

case AD_MARKER_RESPONSE_SUBTYPE:
netdev_dbg(slave->bond->dev, "Received Marker Response on port %d\n",
port->actor_port_number);
ad_marker_response_received((struct bond_marker *)lacpdu, port);
break;

default:
netdev_dbg(slave->bond->dev, "Received an unknown Marker subtype on slot %d\n",
port->actor_port_number);
}
case AD_MARKER_RESPONSE_SUBTYPE:
netdev_dbg(slave->bond->dev, "Received Marker Response on port %d\n",
port->actor_port_number);
ad_marker_response_received(marker, port);
break;
default:
netdev_dbg(slave->bond->dev, "Received an unknown Marker subtype on slot %d\n",
port->actor_port_number);
stat = &SLAVE_AD_INFO(slave)->stats.marker_unknown_rx;
atomic64_inc(stat);
}
break;
default:
atomic64_inc(&SLAVE_AD_INFO(slave)->stats.lacpdu_unknown_rx);
}

return ret;
}

Expand Down Expand Up @@ -2643,10 +2660,12 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
return RX_HANDLER_ANOTHER;

lacpdu = skb_header_pointer(skb, 0, sizeof(_lacpdu), &_lacpdu);
if (!lacpdu)
if (!lacpdu) {
atomic64_inc(&SLAVE_AD_INFO(slave)->stats.lacpdu_illegal_rx);
return RX_HANDLER_ANOTHER;
}

return bond_3ad_rx_indication(lacpdu, slave, skb->len);
return bond_3ad_rx_indication(lacpdu, slave);
}

/**
Expand Down Expand Up @@ -2678,3 +2697,85 @@ void bond_3ad_update_lacp_rate(struct bonding *bond)
}
spin_unlock_bh(&bond->mode_lock);
}

void bond_3ad_stats_add(struct slave *slave, struct bond_3ad_stats *stats)
{
struct bond_3ad_stats *rstats = &SLAVE_AD_INFO(slave)->stats;
u64 stat;

atomic64_add(atomic64_read(&rstats->lacpdu_rx), &stats->lacpdu_rx);
atomic64_add(atomic64_read(&rstats->lacpdu_tx), &stats->lacpdu_tx);

stat = atomic64_read(&rstats->lacpdu_unknown_rx);
atomic64_add(stat, &stats->lacpdu_unknown_rx);
stat = atomic64_read(&rstats->lacpdu_illegal_rx);
atomic64_add(stat, &stats->lacpdu_illegal_rx);

atomic64_add(atomic64_read(&rstats->marker_rx), &stats->marker_rx);
atomic64_add(atomic64_read(&rstats->marker_tx), &stats->marker_tx);

stat = atomic64_read(&rstats->marker_resp_rx);
atomic64_add(stat, &stats->marker_resp_rx);
stat = atomic64_read(&rstats->marker_resp_tx);
atomic64_add(stat, &stats->marker_resp_tx);
stat = atomic64_read(&rstats->marker_unknown_rx);
atomic64_add(stat, &stats->marker_unknown_rx);
}

size_t bond_3ad_stats_size(void)
{
return nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_LACPDU_RX */
nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_LACPDU_TX */
nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_LACPDU_UNKNOWN_RX */
nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_LACPDU_ILLEGAL_RX */
nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_MARKER_RX */
nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_MARKER_TX */
nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_MARKER_RESP_RX */
nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_MARKER_RESP_TX */
nla_total_size_64bit(sizeof(u64)); /* BOND_3AD_STAT_MARKER_UNKNOWN_RX */
}

int bond_3ad_stats_fill(struct sk_buff *skb, struct bond_3ad_stats *stats)
{
u64 val;

val = atomic64_read(&stats->lacpdu_rx);
if (nla_put_u64_64bit(skb, BOND_3AD_STAT_LACPDU_RX, val,
BOND_3AD_STAT_PAD))
return -EMSGSIZE;
val = atomic64_read(&stats->lacpdu_tx);
if (nla_put_u64_64bit(skb, BOND_3AD_STAT_LACPDU_TX, val,
BOND_3AD_STAT_PAD))
return -EMSGSIZE;
val = atomic64_read(&stats->lacpdu_unknown_rx);
if (nla_put_u64_64bit(skb, BOND_3AD_STAT_LACPDU_UNKNOWN_RX, val,
BOND_3AD_STAT_PAD))
return -EMSGSIZE;
val = atomic64_read(&stats->lacpdu_illegal_rx);
if (nla_put_u64_64bit(skb, BOND_3AD_STAT_LACPDU_ILLEGAL_RX, val,
BOND_3AD_STAT_PAD))
return -EMSGSIZE;

val = atomic64_read(&stats->marker_rx);
if (nla_put_u64_64bit(skb, BOND_3AD_STAT_MARKER_RX, val,
BOND_3AD_STAT_PAD))
return -EMSGSIZE;
val = atomic64_read(&stats->marker_tx);
if (nla_put_u64_64bit(skb, BOND_3AD_STAT_MARKER_TX, val,
BOND_3AD_STAT_PAD))
return -EMSGSIZE;
val = atomic64_read(&stats->marker_resp_rx);
if (nla_put_u64_64bit(skb, BOND_3AD_STAT_MARKER_RESP_RX, val,
BOND_3AD_STAT_PAD))
return -EMSGSIZE;
val = atomic64_read(&stats->marker_resp_tx);
if (nla_put_u64_64bit(skb, BOND_3AD_STAT_MARKER_RESP_TX, val,
BOND_3AD_STAT_PAD))
return -EMSGSIZE;
val = atomic64_read(&stats->marker_unknown_rx);
if (nla_put_u64_64bit(skb, BOND_3AD_STAT_MARKER_UNKNOWN_RX, val,
BOND_3AD_STAT_PAD))
return -EMSGSIZE;

return 0;
}
71 changes: 71 additions & 0 deletions drivers/net/bonding/bond_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,75 @@ static int bond_fill_info(struct sk_buff *skb,
return -EMSGSIZE;
}

static size_t bond_get_linkxstats_size(const struct net_device *dev, int attr)
{
switch (attr) {
case IFLA_STATS_LINK_XSTATS:
case IFLA_STATS_LINK_XSTATS_SLAVE:
break;
default:
return 0;
}

return bond_3ad_stats_size() + nla_total_size(0);
}

static int bond_fill_linkxstats(struct sk_buff *skb,
const struct net_device *dev,
int *prividx, int attr)
{
struct nlattr *nla __maybe_unused;
struct slave *slave = NULL;
struct nlattr *nest, *nest2;
struct bonding *bond;

switch (attr) {
case IFLA_STATS_LINK_XSTATS:
bond = netdev_priv(dev);
break;
case IFLA_STATS_LINK_XSTATS_SLAVE:
slave = bond_slave_get_rtnl(dev);
if (!slave)
return 0;
bond = slave->bond;
break;
default:
return -EINVAL;
}

nest = nla_nest_start(skb, LINK_XSTATS_TYPE_BOND);
if (!nest)
return -EMSGSIZE;
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct bond_3ad_stats stats;
struct list_head *iter;

memset(&stats, 0, sizeof(stats));
if (slave) {
bond_3ad_stats_add(slave, &stats);
} else {
bond_for_each_slave(bond, slave, iter)
bond_3ad_stats_add(slave, &stats);
}

nest2 = nla_nest_start(skb, BOND_XSTATS_3AD);
if (!nest2) {
nla_nest_end(skb, nest);
return -EMSGSIZE;
}

if (bond_3ad_stats_fill(skb, &stats)) {
nla_nest_cancel(skb, nest2);
nla_nest_end(skb, nest);
return -EMSGSIZE;
}
nla_nest_end(skb, nest2);
}
nla_nest_end(skb, nest);

return 0;
}

struct rtnl_link_ops bond_link_ops __read_mostly = {
.kind = "bond",
.priv_size = sizeof(struct bonding),
Expand All @@ -689,6 +758,8 @@ struct rtnl_link_ops bond_link_ops __read_mostly = {
.get_num_tx_queues = bond_get_num_tx_queues,
.get_num_rx_queues = bond_get_num_tx_queues, /* Use the same number
as for TX queues */
.fill_linkxstats = bond_fill_linkxstats,
.get_linkxstats_size = bond_get_linkxstats_size,
.slave_maxtype = IFLA_BOND_SLAVE_MAX,
.slave_policy = bond_slave_policy,
.slave_changelink = bond_slave_changelink,
Expand Down
17 changes: 17 additions & 0 deletions include/net/bond_3ad.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,19 @@ struct port;
#pragma pack(8)
#endif

struct bond_3ad_stats {
atomic64_t lacpdu_rx;
atomic64_t lacpdu_tx;
atomic64_t lacpdu_unknown_rx;
atomic64_t lacpdu_illegal_rx;

atomic64_t marker_rx;
atomic64_t marker_tx;
atomic64_t marker_resp_rx;
atomic64_t marker_resp_tx;
atomic64_t marker_unknown_rx;
};

/* aggregator structure(43.4.5 in the 802.3ad standard) */
typedef struct aggregator {
struct mac_addr aggregator_mac_address;
Expand Down Expand Up @@ -272,6 +285,7 @@ struct ad_bond_info {
struct ad_slave_info {
struct aggregator aggregator; /* 802.3ad aggregator structure */
struct port port; /* 802.3ad port structure */
struct bond_3ad_stats stats;
u16 id;
};

Expand Down Expand Up @@ -307,5 +321,8 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
int bond_3ad_set_carrier(struct bonding *bond);
void bond_3ad_update_lacp_rate(struct bonding *bond);
void bond_3ad_update_ad_actor_settings(struct bonding *bond);
void bond_3ad_stats_add(struct slave *slave, struct bond_3ad_stats *stats);
int bond_3ad_stats_fill(struct sk_buff *skb, struct bond_3ad_stats *stats);
size_t bond_3ad_stats_size(void);
#endif /* _NET_BOND_3AD_H */

Loading

0 comments on commit cc648f8

Please sign in to comment.