Commit cc648f85 authored by David S. Miller's avatar David S. Miller

Merge branch 'bonding-add-3ad-stats-and-export-them-via-xstats'

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 1435d997 a258aeac
......@@ -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
......@@ -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;
......@@ -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;
......@@ -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 */
......@@ -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 */
......@@ -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 */
}
......@@ -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;
}
......@@ -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);
}
/**
......@@ -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;
}
......@@ -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),
......@@ -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,
......
......@@ -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;
......@@ -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;
};
......@@ -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 */
......@@ -117,6 +117,30 @@ struct ad_info {
__u8 partner_system[ETH_ALEN];
};
/* Embedded inside LINK_XSTATS_TYPE_BOND */
enum {
BOND_XSTATS_UNSPEC,
BOND_XSTATS_3AD,
__BOND_XSTATS_MAX
};
#define BOND_XSTATS_MAX (__BOND_XSTATS_MAX - 1)
/* Embedded inside BOND_XSTATS_3AD */
enum {
BOND_3AD_STAT_LACPDU_RX,
BOND_3AD_STAT_LACPDU_TX,
BOND_3AD_STAT_LACPDU_UNKNOWN_RX,
BOND_3AD_STAT_LACPDU_ILLEGAL_RX,
BOND_3AD_STAT_MARKER_RX,
BOND_3AD_STAT_MARKER_TX,
BOND_3AD_STAT_MARKER_RESP_RX,
BOND_3AD_STAT_MARKER_RESP_TX,
BOND_3AD_STAT_MARKER_UNKNOWN_RX,
BOND_3AD_STAT_PAD,
__BOND_3AD_STAT_MAX
};
#define BOND_3AD_STAT_MAX (__BOND_3AD_STAT_MAX - 1)
#endif /* _LINUX_IF_BONDING_H */
/*
......
......@@ -925,6 +925,7 @@ enum {
enum {
LINK_XSTATS_TYPE_UNSPEC,
LINK_XSTATS_TYPE_BRIDGE,
LINK_XSTATS_TYPE_BOND,
__LINK_XSTATS_TYPE_MAX
};
#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment