diff options
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_3ad.c | 188 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 1 | ||||
-rw-r--r-- | drivers/net/bonding/bond_netlink.c | 67 | ||||
-rw-r--r-- | drivers/net/bonding/bond_options.c | 2 |
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; } |