aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/failsafe
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/failsafe')
-rw-r--r--drivers/net/failsafe/Makefile3
-rw-r--r--drivers/net/failsafe/failsafe.c2
-rw-r--r--drivers/net/failsafe/failsafe_args.c32
-rw-r--r--drivers/net/failsafe/failsafe_eal.c28
-rw-r--r--drivers/net/failsafe/failsafe_ether.c55
-rw-r--r--drivers/net/failsafe/failsafe_ops.c149
-rw-r--r--drivers/net/failsafe/failsafe_private.h55
-rw-r--r--drivers/net/failsafe/failsafe_rxtx.c3
8 files changed, 153 insertions, 174 deletions
diff --git a/drivers/net/failsafe/Makefile b/drivers/net/failsafe/Makefile
index d516d362..ea2a8fe4 100644
--- a/drivers/net/failsafe/Makefile
+++ b/drivers/net/failsafe/Makefile
@@ -58,5 +58,8 @@ CFLAGS += -D_XOPEN_SOURCE=700
CFLAGS += $(WERROR_FLAGS)
CFLAGS += -Wno-strict-prototypes
CFLAGS += -pedantic
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
+LDLIBS += -lrte_bus_vdev
include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/failsafe/failsafe.c b/drivers/net/failsafe/failsafe.c
index 6006bef8..6bc5abac 100644
--- a/drivers/net/failsafe/failsafe.c
+++ b/drivers/net/failsafe/failsafe.c
@@ -37,7 +37,7 @@
#include <rte_ethdev_vdev.h>
#include <rte_devargs.h>
#include <rte_kvargs.h>
-#include <rte_vdev.h>
+#include <rte_bus_vdev.h>
#include "failsafe_private.h"
diff --git a/drivers/net/failsafe/failsafe_args.c b/drivers/net/failsafe/failsafe_args.c
index 1f22416f..cfc83e36 100644
--- a/drivers/net/failsafe/failsafe_args.c
+++ b/drivers/net/failsafe/failsafe_args.c
@@ -115,8 +115,7 @@ fs_execute_cmd(struct sub_device *sdev, char *cmdline)
/* store possible newline as well */
char output[DEVARGS_MAXLEN + 1];
size_t len;
- int old_err;
- int ret, pclose_ret;
+ int ret;
RTE_ASSERT(cmdline != NULL || sdev->cmdline != NULL);
if (sdev->cmdline == NULL) {
@@ -135,12 +134,10 @@ fs_execute_cmd(struct sub_device *sdev, char *cmdline)
sdev->cmdline[i] = ' ';
}
DEBUG("'%s'", sdev->cmdline);
- old_err = errno;
fp = popen(sdev->cmdline, "r");
if (fp == NULL) {
- ret = errno;
+ ret = -errno;
ERROR("popen: %s", strerror(errno));
- errno = old_err;
return ret;
}
/* We only read one line */
@@ -155,18 +152,11 @@ fs_execute_cmd(struct sub_device *sdev, char *cmdline)
goto ret_pclose;
}
ret = fs_parse_device(sdev, output);
- if (ret) {
+ if (ret)
ERROR("Parsing device '%s' failed", output);
- goto ret_pclose;
- }
ret_pclose:
- pclose_ret = pclose(fp);
- if (pclose_ret) {
- pclose_ret = errno;
+ if (pclose(fp) == -1)
ERROR("pclose: %s", strerror(errno));
- errno = old_err;
- return pclose_ret;
- }
return ret;
}
@@ -286,10 +276,17 @@ fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
ERROR("Invalid parameter");
return -EINVAL;
}
- if (params[b] == ',' || params[b] == '\0')
- i += snprintf(&buffer[i], b - a + 1, "%s", &params[a]);
- if (params[b] == '(') {
+ if (params[b] == ',' || params[b] == '\0') {
+ size_t len = b - a;
+
+ if (i > 0)
+ len += 1;
+ snprintf(&buffer[i], len + 1, "%s%s",
+ i ? "," : "", &params[a]);
+ i += len;
+ } else if (params[b] == '(') {
size_t start = b;
+
b += closing_paren(&params[b]);
if (b == start)
return -EINVAL;
@@ -393,6 +390,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
&dev->data->mac_addrs[0]);
if (ret < 0)
goto free_kvlist;
+
mac_from_arg = 1;
}
}
diff --git a/drivers/net/failsafe/failsafe_eal.c b/drivers/net/failsafe/failsafe_eal.c
index c8f4318e..19d26f53 100644
--- a/drivers/net/failsafe/failsafe_eal.c
+++ b/drivers/net/failsafe/failsafe_eal.c
@@ -41,6 +41,7 @@ fs_bus_init(struct rte_eth_dev *dev)
struct sub_device *sdev;
struct rte_devargs *da;
uint8_t i;
+ uint16_t j;
int ret;
FOREACH_SUBDEV(sdev, i, dev) {
@@ -57,7 +58,13 @@ fs_bus_init(struct rte_eth_dev *dev)
rte_errno ? ")" : "");
continue;
}
- ETH(sdev) = rte_eth_dev_allocated(da->name);
+ RTE_ETH_FOREACH_DEV(j) {
+ if (strcmp(rte_eth_devices[j].device->name,
+ da->name) == 0) {
+ ETH(sdev) = &rte_eth_devices[j];
+ break;
+ }
+ }
if (ETH(sdev) == NULL) {
ERROR("sub_device %d init went wrong", i);
return -ENODEV;
@@ -90,19 +97,20 @@ fs_bus_uninit(struct rte_eth_dev *dev)
{
struct sub_device *sdev = NULL;
uint8_t i;
- int ret;
+ int sdev_ret;
+ int ret = 0;
FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
- ret = rte_eal_hotplug_remove(sdev->bus->name,
- sdev->dev->name);
- if (ret) {
- ERROR("Failed to remove requested device %s",
- sdev->dev->name);
+ sdev_ret = rte_eal_hotplug_remove(sdev->bus->name,
+ sdev->dev->name);
+ if (sdev_ret) {
+ ERROR("Failed to remove requested device %s (err: %d)",
+ sdev->dev->name, sdev_ret);
continue;
}
sdev->state = DEV_PROBED - 1;
}
- return 0;
+ return ret;
}
int
@@ -111,8 +119,6 @@ failsafe_eal_uninit(struct rte_eth_dev *dev)
int ret;
ret = fs_bus_uninit(dev);
- if (ret)
- return ret;
PRIV(dev)->state = DEV_PROBED - 1;
- return 0;
+ return ret;
}
diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index a3a8cce9..21392e5a 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -35,6 +35,7 @@
#include <rte_flow.h>
#include <rte_flow_driver.h>
+#include <rte_cycles.h>
#include "failsafe_private.h"
@@ -203,6 +204,7 @@ fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
ether_format_addr(ea_fmt, ETHER_ADDR_FMT_SIZE, ea);
ERROR("Adding MAC address %s failed", ea_fmt);
+ return ret;
}
}
/* VLAN filter */
@@ -308,6 +310,28 @@ fs_dev_remove(struct sub_device *sdev)
failsafe_hotplug_alarm_install(sdev->fs_dev);
}
+static void
+fs_dev_stats_save(struct sub_device *sdev)
+{
+ struct rte_eth_stats stats;
+ int err;
+
+ /* Attempt to read current stats. */
+ err = rte_eth_stats_get(PORT_ID(sdev), &stats);
+ if (err) {
+ uint64_t timestamp = sdev->stats_snapshot.timestamp;
+
+ WARN("Could not access latest statistics from sub-device %d.\n",
+ SUB_ID(sdev));
+ if (timestamp != 0)
+ WARN("Using latest snapshot taken before %"PRIu64" seconds.\n",
+ (rte_rdtsc() - timestamp) / rte_get_tsc_hz());
+ }
+ failsafe_stats_increment(&PRIV(sdev->fs_dev)->stats_accumulator,
+ err ? &sdev->stats_snapshot.stats : &stats);
+ memset(&sdev->stats_snapshot, 0, sizeof(sdev->stats_snapshot));
+}
+
static inline int
fs_rxtx_clean(struct sub_device *sdev)
{
@@ -329,8 +353,10 @@ failsafe_dev_remove(struct rte_eth_dev *dev)
uint8_t i;
FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
- if (sdev->remove && fs_rxtx_clean(sdev))
+ if (sdev->remove && fs_rxtx_clean(sdev)) {
+ fs_dev_stats_save(sdev);
fs_dev_remove(sdev);
+ }
}
int
@@ -399,8 +425,31 @@ err_remove:
return ret;
}
+void
+failsafe_stats_increment(struct rte_eth_stats *to, struct rte_eth_stats *from)
+{
+ uint32_t i;
+
+ RTE_ASSERT(to != NULL && from != NULL);
+ to->ipackets += from->ipackets;
+ to->opackets += from->opackets;
+ to->ibytes += from->ibytes;
+ to->obytes += from->obytes;
+ to->imissed += from->imissed;
+ to->ierrors += from->ierrors;
+ to->oerrors += from->oerrors;
+ to->rx_nombuf += from->rx_nombuf;
+ for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) {
+ to->q_ipackets[i] += from->q_ipackets[i];
+ to->q_opackets[i] += from->q_opackets[i];
+ to->q_ibytes[i] += from->q_ibytes[i];
+ to->q_obytes[i] += from->q_obytes[i];
+ to->q_errors[i] += from->q_errors[i];
+ }
+}
+
int
-failsafe_eth_rmv_event_callback(uint8_t port_id __rte_unused,
+failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused,
enum rte_eth_event_type event __rte_unused,
void *cb_arg, void *out __rte_unused)
{
@@ -419,7 +468,7 @@ failsafe_eth_rmv_event_callback(uint8_t port_id __rte_unused,
}
int
-failsafe_eth_lsc_event_callback(uint8_t port_id __rte_unused,
+failsafe_eth_lsc_event_callback(uint16_t port_id __rte_unused,
enum rte_eth_event_type event __rte_unused,
void *cb_arg, void *out __rte_unused)
{
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index ff9ad155..e16a5903 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -38,6 +38,7 @@
#include <rte_ethdev.h>
#include <rte_malloc.h>
#include <rte_flow.h>
+#include <rte_cycles.h>
#include "failsafe_private.h"
@@ -79,132 +80,14 @@ static struct rte_eth_dev_info default_infos = {
.flow_type_rss_offloads = 0x0,
};
-/**
- * Check whether a specific offloading capability
- * is supported by a sub_device.
- *
- * @return
- * 0: all requested capabilities are supported by the sub_device
- * positive value: This flag at least is not supported by the sub_device
- */
-static int
-fs_port_offload_validate(struct rte_eth_dev *dev,
- struct sub_device *sdev)
-{
- struct rte_eth_dev_info infos = {0};
- struct rte_eth_conf *cf;
- uint32_t cap;
-
- cf = &dev->data->dev_conf;
- SUBOPS(sdev, dev_infos_get)(ETH(sdev), &infos);
- /* RX capabilities */
- cap = infos.rx_offload_capa;
- if (cf->rxmode.hw_vlan_strip &&
- ((cap & DEV_RX_OFFLOAD_VLAN_STRIP) == 0)) {
- WARN("VLAN stripping offload requested but not supported by sub_device %d",
- SUB_ID(sdev));
- return DEV_RX_OFFLOAD_VLAN_STRIP;
- }
- if (cf->rxmode.hw_ip_checksum &&
- ((cap & (DEV_RX_OFFLOAD_IPV4_CKSUM |
- DEV_RX_OFFLOAD_UDP_CKSUM |
- DEV_RX_OFFLOAD_TCP_CKSUM)) !=
- (DEV_RX_OFFLOAD_IPV4_CKSUM |
- DEV_RX_OFFLOAD_UDP_CKSUM |
- DEV_RX_OFFLOAD_TCP_CKSUM))) {
- WARN("IP checksum offload requested but not supported by sub_device %d",
- SUB_ID(sdev));
- return DEV_RX_OFFLOAD_IPV4_CKSUM |
- DEV_RX_OFFLOAD_UDP_CKSUM |
- DEV_RX_OFFLOAD_TCP_CKSUM;
- }
- if (cf->rxmode.enable_lro &&
- ((cap & DEV_RX_OFFLOAD_TCP_LRO) == 0)) {
- WARN("TCP LRO offload requested but not supported by sub_device %d",
- SUB_ID(sdev));
- return DEV_RX_OFFLOAD_TCP_LRO;
- }
- if (cf->rxmode.hw_vlan_extend &&
- ((cap & DEV_RX_OFFLOAD_QINQ_STRIP) == 0)) {
- WARN("Stacked VLAN stripping offload requested but not supported by sub_device %d",
- SUB_ID(sdev));
- return DEV_RX_OFFLOAD_QINQ_STRIP;
- }
- /* TX capabilities */
- /* Nothing to do, no tx capa supported */
- return 0;
-}
-
-/*
- * Disable the dev_conf flag related to an offload capability flag
- * within an ethdev configuration.
- */
-static int
-fs_port_disable_offload(struct rte_eth_conf *cf,
- uint32_t ol_cap)
-{
- switch (ol_cap) {
- case DEV_RX_OFFLOAD_VLAN_STRIP:
- INFO("Disabling VLAN stripping offload");
- cf->rxmode.hw_vlan_strip = 0;
- break;
- case DEV_RX_OFFLOAD_IPV4_CKSUM:
- case DEV_RX_OFFLOAD_UDP_CKSUM:
- case DEV_RX_OFFLOAD_TCP_CKSUM:
- case (DEV_RX_OFFLOAD_IPV4_CKSUM |
- DEV_RX_OFFLOAD_UDP_CKSUM |
- DEV_RX_OFFLOAD_TCP_CKSUM):
- INFO("Disabling IP checksum offload");
- cf->rxmode.hw_ip_checksum = 0;
- break;
- case DEV_RX_OFFLOAD_TCP_LRO:
- INFO("Disabling TCP LRO offload");
- cf->rxmode.enable_lro = 0;
- break;
- case DEV_RX_OFFLOAD_QINQ_STRIP:
- INFO("Disabling stacked VLAN stripping offload");
- cf->rxmode.hw_vlan_extend = 0;
- break;
- default:
- DEBUG("Unable to disable offload capability: %" PRIx32,
- ol_cap);
- return -1;
- }
- return 0;
-}
-
static int
fs_dev_configure(struct rte_eth_dev *dev)
{
struct sub_device *sdev;
uint8_t i;
- int capa_flag;
int ret;
FOREACH_SUBDEV(sdev, i, dev) {
- if (sdev->state != DEV_PROBED)
- continue;
- DEBUG("Checking capabilities for sub_device %d", i);
- while ((capa_flag = fs_port_offload_validate(dev, sdev))) {
- /*
- * Refuse to change configuration if multiple devices
- * are present and we already have configured at least
- * some of them.
- */
- if (PRIV(dev)->state >= DEV_ACTIVE &&
- PRIV(dev)->subs_tail > 1) {
- ERROR("device already configured, cannot fix live configuration");
- return -1;
- }
- ret = fs_port_disable_offload(&dev->data->dev_conf,
- capa_flag);
- if (ret) {
- ERROR("Unable to disable offload capability");
- return ret;
- }
- }
- }
- FOREACH_SUBDEV(sdev, i, dev) {
int rmv_interrupt = 0;
int lsc_interrupt = 0;
int lsc_enabled;
@@ -582,13 +465,30 @@ fs_link_update(struct rte_eth_dev *dev,
return -1;
}
-static void
+static int
fs_stats_get(struct rte_eth_dev *dev,
struct rte_eth_stats *stats)
{
- if (TX_SUBDEV(dev) == NULL)
- return;
- rte_eth_stats_get(PORT_ID(TX_SUBDEV(dev)), stats);
+ struct sub_device *sdev;
+ uint8_t i;
+ int ret;
+
+ rte_memcpy(stats, &PRIV(dev)->stats_accumulator, sizeof(*stats));
+ FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
+ struct rte_eth_stats *snapshot = &sdev->stats_snapshot.stats;
+ uint64_t *timestamp = &sdev->stats_snapshot.timestamp;
+
+ ret = rte_eth_stats_get(PORT_ID(sdev), snapshot);
+ if (ret) {
+ ERROR("Operation rte_eth_stats_get failed for sub_device %d with error %d",
+ i, ret);
+ *timestamp = 0;
+ return ret;
+ }
+ *timestamp = rte_rdtsc();
+ failsafe_stats_increment(stats, snapshot);
+ }
+ return 0;
}
static void
@@ -597,8 +497,11 @@ fs_stats_reset(struct rte_eth_dev *dev)
struct sub_device *sdev;
uint8_t i;
- FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
+ FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
rte_eth_stats_reset(PORT_ID(sdev));
+ memset(&sdev->stats_snapshot, 0, sizeof(struct rte_eth_stats));
+ }
+ memset(&PRIV(dev)->stats_accumulator, 0, sizeof(struct rte_eth_stats));
}
/**
diff --git a/drivers/net/failsafe/failsafe_private.h b/drivers/net/failsafe/failsafe_private.h
index 0361cf43..d81cc3ca 100644
--- a/drivers/net/failsafe/failsafe_private.h
+++ b/drivers/net/failsafe/failsafe_private.h
@@ -93,6 +93,11 @@ enum dev_state {
DEV_STARTED,
};
+struct fs_stats {
+ struct rte_eth_stats stats;
+ uint64_t timestamp;
+};
+
struct sub_device {
/* Exhaustive DPDK device description */
struct rte_devargs devargs;
@@ -102,6 +107,8 @@ struct sub_device {
uint8_t sid;
/* Device state machine */
enum dev_state state;
+ /* Last stats snapshot passed to user */
+ struct fs_stats stats_snapshot;
/* Some device are defined as a command line */
char *cmdline;
/* fail-safe device backreference */
@@ -140,6 +147,7 @@ struct fs_priv {
* synchronized state.
*/
enum dev_state state;
+ struct rte_eth_stats stats_accumulator;
unsigned int pending_alarm:1; /* An alarm is pending */
/* flow isolation state */
int flow_isolated:1;
@@ -180,10 +188,12 @@ int failsafe_eal_uninit(struct rte_eth_dev *dev);
int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);
void failsafe_dev_remove(struct rte_eth_dev *dev);
-int failsafe_eth_rmv_event_callback(uint8_t port_id,
+void failsafe_stats_increment(struct rte_eth_stats *to,
+ struct rte_eth_stats *from);
+int failsafe_eth_rmv_event_callback(uint16_t port_id,
enum rte_eth_event_type type,
void *arg, void *out);
-int failsafe_eth_lsc_event_callback(uint8_t port_id,
+int failsafe_eth_lsc_event_callback(uint16_t port_id,
enum rte_eth_event_type event,
void *cb_arg, void *out);
@@ -220,10 +230,10 @@ extern int mac_from_arg;
* dev: (struct rte_eth_dev *), fail-safe ethdev
* state: (enum dev_state), minimum acceptable device state
*/
-#define FOREACH_SUBDEV_STATE(s, i, dev, state) \
- for (i = fs_find_next((dev), 0, state); \
- i < PRIV(dev)->subs_tail && (s = &PRIV(dev)->subs[i]); \
- i = fs_find_next((dev), i + 1, state))
+#define FOREACH_SUBDEV_STATE(s, i, dev, state) \
+ for (s = fs_find_next((dev), 0, state, &i); \
+ s != NULL; \
+ s = fs_find_next((dev), i + 1, state, &i))
/**
* Iterator construct over fail-safe sub-devices:
@@ -294,18 +304,26 @@ extern int mac_from_arg;
/* inlined functions */
-static inline uint8_t
-fs_find_next(struct rte_eth_dev *dev, uint8_t sid,
- enum dev_state min_state)
+static inline struct sub_device *
+fs_find_next(struct rte_eth_dev *dev,
+ uint8_t sid,
+ enum dev_state min_state,
+ uint8_t *sid_out)
{
- while (sid < PRIV(dev)->subs_tail) {
- if (PRIV(dev)->subs[sid].state >= min_state)
+ struct sub_device *subs;
+ uint8_t tail;
+
+ subs = PRIV(dev)->subs;
+ tail = PRIV(dev)->subs_tail;
+ while (sid < tail) {
+ if (subs[sid].state >= min_state)
break;
sid++;
}
- if (sid >= PRIV(dev)->subs_tail)
- return PRIV(dev)->subs_tail;
- return sid;
+ *sid_out = sid;
+ if (sid >= tail)
+ return NULL;
+ return &subs[sid];
}
/*
@@ -334,7 +352,7 @@ fs_switch_dev(struct rte_eth_dev *dev,
} else if ((txd && txd->state < req_state) ||
txd == NULL ||
txd == banned) {
- struct sub_device *sdev;
+ struct sub_device *sdev = NULL;
uint8_t i;
/* Using acceptable device */
@@ -346,9 +364,10 @@ fs_switch_dev(struct rte_eth_dev *dev,
PRIV(dev)->subs_tx = i;
break;
}
- } else if (txd && txd->state < req_state) {
- DEBUG("No device ready, deactivating tx_dev");
- PRIV(dev)->subs_tx = PRIV(dev)->subs_tail;
+ if (i >= PRIV(dev)->subs_tail || sdev == NULL) {
+ DEBUG("No device ready, deactivating tx_dev");
+ PRIV(dev)->subs_tx = PRIV(dev)->subs_tail;
+ }
} else {
return;
}
diff --git a/drivers/net/failsafe/failsafe_rxtx.c b/drivers/net/failsafe/failsafe_rxtx.c
index 73114215..70157c82 100644
--- a/drivers/net/failsafe/failsafe_rxtx.c
+++ b/drivers/net/failsafe/failsafe_rxtx.c
@@ -43,7 +43,8 @@ fs_rx_unsafe(struct sub_device *sdev)
{
return (ETH(sdev) == NULL) ||
(ETH(sdev)->rx_pkt_burst == NULL) ||
- (sdev->state != DEV_STARTED);
+ (sdev->state != DEV_STARTED) ||
+ (sdev->remove != 0);
}
static inline int