diff options
Diffstat (limited to 'drivers/net/failsafe')
-rw-r--r-- | drivers/net/failsafe/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/failsafe/failsafe.c | 2 | ||||
-rw-r--r-- | drivers/net/failsafe/failsafe_args.c | 32 | ||||
-rw-r--r-- | drivers/net/failsafe/failsafe_eal.c | 28 | ||||
-rw-r--r-- | drivers/net/failsafe/failsafe_ether.c | 55 | ||||
-rw-r--r-- | drivers/net/failsafe/failsafe_ops.c | 149 | ||||
-rw-r--r-- | drivers/net/failsafe/failsafe_private.h | 55 | ||||
-rw-r--r-- | drivers/net/failsafe/failsafe_rxtx.c | 3 |
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", ¶ms[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 ? "," : "", ¶ms[a]); + i += len; + } else if (params[b] == '(') { size_t start = b; + b += closing_paren(¶ms[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 |