summaryrefslogtreecommitdiff
path: root/drivers/net/bonding
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r--drivers/net/bonding/bond_3ad.c188
-rw-r--r--drivers/net/bonding/bond_main.c1
-rw-r--r--drivers/net/bonding/bond_netlink.c67
-rw-r--r--drivers/net/bonding/bond_options.c2
4 files changed, 207 insertions, 51 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 7c46d9f4fefd..9274dcc6e9b0 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -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,9 @@ static int ad_lacpdu_send(struct port *port)
if (!skb)
return -ENOMEM;
+ atomic64_inc(&SLAVE_AD_INFO(slave)->stats.lacpdu_tx);
+ atomic64_inc(&BOND_AD_INFO(slave->bond).stats.lacpdu_tx);
+
skb->dev = slave->dev;
skb_reset_mac_header(skb);
skb->network_header = skb->mac_header + ETH_HLEN;
@@ -892,6 +896,17 @@ 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);
+ atomic64_inc(&BOND_AD_INFO(slave->bond).stats.marker_tx);
+ break;
+ case AD_MARKER_RESPONSE_SUBTYPE:
+ atomic64_inc(&SLAVE_AD_INFO(slave)->stats.marker_resp_tx);
+ atomic64_inc(&BOND_AD_INFO(slave->bond).stats.marker_resp_tx);
+ break;
+ }
+
skb_reserve(skb, 16);
skb->dev = slave->dev;
@@ -1086,6 +1101,10 @@ 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);
+ atomic64_inc(&BOND_AD_INFO(port->slave->bond).stats.lacpdu_rx);
+ }
/* check if state machine should change state */
/* first, check if port was reinitialized */
@@ -1922,6 +1941,9 @@ 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);
+ atomic64_inc(&BOND_AD_INFO(port->slave->bond).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 +1968,9 @@ 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);
+ atomic64_inc(&BOND_AD_INFO(port->slave->bond).stats.marker_resp_rx);
+
/* DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW */
}
@@ -2348,66 +2373,68 @@ re_arm:
* 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;
+ struct bonding *bond = slave->bond;
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);
+ stat = &BOND_AD_INFO(bond).stats.marker_unknown_rx;
+ atomic64_inc(stat);
}
+ break;
+ default:
+ atomic64_inc(&SLAVE_AD_INFO(slave)->stats.lacpdu_unknown_rx);
+ atomic64_inc(&BOND_AD_INFO(bond).stats.lacpdu_unknown_rx);
}
+
return ret;
}
@@ -2643,10 +2670,13 @@ 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);
+ atomic64_inc(&BOND_AD_INFO(bond).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 +2708,61 @@ void bond_3ad_update_lacp_rate(struct bonding *bond)
}
spin_unlock_bh(&bond->mode_lock);
}
+
+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;
+}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 537c90c8eb0a..b59708c35faf 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -77,7 +77,6 @@
#include <net/pkt_sched.h>
#include <linux/rculist.h>
#include <net/flow_dissector.h>
-#include <net/switchdev.h>
#include <net/bonding.h>
#include <net/bond_3ad.h>
#include <net/bond_alb.h>
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 6b9ad8673218..b286f591242e 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -675,6 +675,71 @@ nla_put_failure:
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;
+
+ if (slave)
+ stats = &SLAVE_AD_INFO(slave)->stats;
+ else
+ stats = &BOND_AD_INFO(bond).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 +754,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,
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 4d5d01cb8141..da1fc17295d9 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -1375,6 +1375,7 @@ static int bond_option_slaves_set(struct bonding *bond,
sscanf(newval->string, "%16s", command); /* IFNAMSIZ*/
ifname = command + 1;
if ((strlen(command) <= 1) ||
+ (command[0] != '+' && command[0] != '-') ||
!dev_valid_name(ifname))
goto err_no_cmd;
@@ -1398,6 +1399,7 @@ static int bond_option_slaves_set(struct bonding *bond,
break;
default:
+ /* should not run here. */
goto err_no_cmd;
}