Skip to contentSkip to conversation

introduce fail-safe PMD

PATCH Superseded Gaetan Rivet 6 participants 49 messages Mar 3, 2017 – May 17, 2017 Network drivers

v1 of 11 Superseded Latest is v11 →

lore
Share & tools
lore
#0 lore raw

cover introduce fail-safe PMD

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This series depends on the series
[PATCH 0/4] clarify eth_dev state management
[PATCH 0/5] add device removal event

Gaetan Rivet (12):
ethdev: save VLAN filter setting
ethdev: add flow API rule copy function
ethdev: add deferred intermediate device state
pci: expose device detach routine
pci: expose parse and probe routines
net/failsafe: add fail-safe PMD
net/failsafe: add plug-in support
net/failsafe: add flexible device definition
net/failsafe: support flow API
net/failsafe: support offload capabilities
net/failsafe: add fast burst functions
net/failsafe: support device removal

 MAINTAINERS                                     |   4 +
 app/test-pmd/config.c                           | 263 ++------
 app/test-pmd/testpmd.h                          |   5 +-
 config/common_linuxapp                          |   1 +
 drivers/net/Makefile                            |   1 +
 drivers/net/failsafe/Makefile                   |  73 +++
 drivers/net/failsafe/failsafe.c                 | 279 ++++++++
 drivers/net/failsafe/failsafe_args.c            | 503 ++++++++++++++
 drivers/net/failsafe/failsafe_eal.c             | 300 +++++++++
 drivers/net/failsafe/failsafe_ether.c           | 368 +++++++++++
 drivers/net/failsafe/failsafe_flow.c            | 230 +++++++
 drivers/net/failsafe/failsafe_ops.c             | 838 ++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h         | 326 +++++++++
 drivers/net/failsafe/failsafe_rxtx.c            | 184 ++++++
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   6 +
 lib/librte_eal/common/eal_common_pci.c          |  16 +-
 lib/librte_eal/common/include/rte_pci.h         |  40 ++
 lib/librte_eal/linuxapp/eal/eal_pci.c           |  39 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   7 +
 lib/librte_ether/rte_ethdev.c                   |  22 +-
 lib/librte_ether/rte_ethdev.h                   |  11 +
 lib/librte_ether/rte_flow.c                     | 283 ++++++++
 lib/librte_ether/rte_flow.h                     |  59 ++
 mk/rte.app.mk                                   |   1 +
 24 files changed, 3611 insertions(+), 248 deletions(-)
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
Signature · 1 line
2.1.4
#1 lore raw

PATCH 1/12 ethdev: save VLAN filter setting

Other configuration items (i.e. MAC addresses) are stored within rte_eth_dev_data, but not this one.

---
 lib/librte_ether/rte_ethdev.c | 19 ++++++++++++++++++-
 lib/librte_ether/rte_ethdev.h | 10 ++++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)
lib/librte_ether/rte_ethdev.c +18 -1
index 6c4b796..61a63b7 100644
@@ -1764,6 +1764,7 @@ int
 rte_eth_dev_vlan_filter(uint8_t port_id, uint16_t vlan_id, int on)
 {
 	struct rte_eth_dev *dev;
+	int ret;
 
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 	dev = &rte_eth_devices[port_id];
@@ -1779,7 +1780,23 @@ rte_eth_dev_vlan_filter(uint8_t port_id, uint16_t vlan_id, int on)
 	}
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->vlan_filter_set, -ENOTSUP);
 
-	return (*dev->dev_ops->vlan_filter_set)(dev, vlan_id, on);
+	ret = (*dev->dev_ops->vlan_filter_set)(dev, vlan_id, on);
+	if (ret == 0) {
+		struct rte_vlan_filter_conf *vfc;
+		int vidx;
+		int vbit;
+
+		vfc = &dev->data->vlan_filter_conf;
+		vidx = vlan_id / 64;
+		vbit = vlan_id % 64;
+
+		if (on)
+			vfc->ids[vidx] |= UINT64_C(1) << vbit;
+		else
+			vfc->ids[vidx] &= ~(UINT64_C(1) << vbit);
+	}
+
+	return ret;
 }
 
 int
lib/librte_ether/rte_ethdev.h +10 -0
index ed99660..f01d140 100644
@@ -375,6 +375,14 @@ enum rte_vlan_type {
 };
 
 /**
+ * A structure used to describe a vlan filter.
+ * If the bit corresponding to a VID is set, such VID is on.
+ */
+struct rte_vlan_filter_conf {
+	uint64_t ids[64];
+};
+
+/**
  * A structure used to configure the Receive Side Scaling (RSS) feature
  * of an Ethernet port.
  * If not NULL, the *rss_key* pointer of the *rss_conf* structure points
@@ -1716,6 +1724,8 @@ struct rte_eth_dev_data {
 	enum rte_kernel_driver kdrv;    /**< Kernel driver passthrough */
 	int numa_node;  /**< NUMA node connection */
 	const char *drv_name;   /**< Driver name */
+	struct rte_vlan_filter_conf vlan_filter_conf;
+	/**< VLAN filter configuration. */
 };
 
 /** Device supports hotplug detach */
Signature · 1 line
2.1.4
#2 lore raw

Re: [PATCH 01/12] ethdev: save VLAN filter setting

Quoted 4 lines · On Fri, 3 Mar 2017 16:40:23 +0100 Gaetan Rivet <[email protected]> wrote:

Other configuration items (i.e. MAC addresses) are stored within rte_eth_dev_data, but not this one.

Maybe time to introduce a generic set of bit array operations like kernel set/clear/test bit functions. There are architecture specific instructions for this (doesn't matter for this case). May even be GCC builtin support

#3 lore raw

PATCH 2/12 ethdev: add flow API rule copy function

In reply to Gaetan Rivet

Take this helper from the testpmd app to offer it alongside the flow API.

This allows PMDs and applications to save flow rules in their generic format for later processing. This is useful when rules cannot be applied immediately, such as when the device is not properly initialized.

---
 app/test-pmd/config.c       | 263 +++++++---------------------------------
 app/test-pmd/testpmd.h      |   5 +-
 lib/librte_ether/rte_flow.c | 283 ++++++++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_flow.h |  59 +++++++++
 4 files changed, 387 insertions(+), 223 deletions(-)
app/test-pmd/config.c +44 -219
index 54e38c4..f20e258 100644
@@ -932,208 +932,6 @@ port_mtu_set(portid_t port_id, uint16_t mtu)
 	printf("Set MTU failed. diag=%d\n", diag);
 }
 
-/* Generic flow management functions. */
-
-/** Generate flow_item[] entry. */
-#define MK_FLOW_ITEM(t, s) \
-	[RTE_FLOW_ITEM_TYPE_ ## t] = { \
-		.name = # t, \
-		.size = s, \
-	}
-
-/** Information about known flow pattern items. */
-static const struct {
-	const char *name;
-	size_t size;
-} flow_item[] = {
-	MK_FLOW_ITEM(END, 0),
-	MK_FLOW_ITEM(VOID, 0),
-	MK_FLOW_ITEM(INVERT, 0),
-	MK_FLOW_ITEM(ANY, sizeof(struct rte_flow_item_any)),
-	MK_FLOW_ITEM(PF, 0),
-	MK_FLOW_ITEM(VF, sizeof(struct rte_flow_item_vf)),
-	MK_FLOW_ITEM(PORT, sizeof(struct rte_flow_item_port)),
-	MK_FLOW_ITEM(RAW, sizeof(struct rte_flow_item_raw)), /* +pattern[] */
-	MK_FLOW_ITEM(ETH, sizeof(struct rte_flow_item_eth)),
-	MK_FLOW_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),
-	MK_FLOW_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),
-	MK_FLOW_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),
-	MK_FLOW_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)),
-	MK_FLOW_ITEM(UDP, sizeof(struct rte_flow_item_udp)),
-	MK_FLOW_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),
-	MK_FLOW_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),
-	MK_FLOW_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),
-};
-
-/** Compute storage space needed by item specification. */
-static void
-flow_item_spec_size(const struct rte_flow_item *item,
-		    size_t *size, size_t *pad)
-{
-	if (!item->spec)
-		goto empty;
-	switch (item->type) {
-		union {
-			const struct rte_flow_item_raw *raw;
-		} spec;
-
-	case RTE_FLOW_ITEM_TYPE_RAW:
-		spec.raw = item->spec;
-		*size = offsetof(struct rte_flow_item_raw, pattern) +
-			spec.raw->length * sizeof(*spec.raw->pattern);
-		break;
-	default:
-empty:
-		*size = 0;
-		break;
-	}
-	*pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size;
-}
-
-/** Generate flow_action[] entry. */
-#define MK_FLOW_ACTION(t, s) \
-	[RTE_FLOW_ACTION_TYPE_ ## t] = { \
-		.name = # t, \
-		.size = s, \
-	}
-
-/** Information about known flow actions. */
-static const struct {
-	const char *name;
-	size_t size;
-} flow_action[] = {
-	MK_FLOW_ACTION(END, 0),
-	MK_FLOW_ACTION(VOID, 0),
-	MK_FLOW_ACTION(PASSTHRU, 0),
-	MK_FLOW_ACTION(MARK, sizeof(struct rte_flow_action_mark)),
-	MK_FLOW_ACTION(FLAG, 0),
-	MK_FLOW_ACTION(QUEUE, sizeof(struct rte_flow_action_queue)),
-	MK_FLOW_ACTION(DROP, 0),
-	MK_FLOW_ACTION(COUNT, 0),
-	MK_FLOW_ACTION(DUP, sizeof(struct rte_flow_action_dup)),
-	MK_FLOW_ACTION(RSS, sizeof(struct rte_flow_action_rss)), /* +queue[] */
-	MK_FLOW_ACTION(PF, 0),
-	MK_FLOW_ACTION(VF, sizeof(struct rte_flow_action_vf)),
-};
-
-/** Compute storage space needed by action configuration. */
-static void
-flow_action_conf_size(const struct rte_flow_action *action,
-		      size_t *size, size_t *pad)
-{
-	if (!action->conf)
-		goto empty;
-	switch (action->type) {
-		union {
-			const struct rte_flow_action_rss *rss;
-		} conf;
-
-	case RTE_FLOW_ACTION_TYPE_RSS:
-		conf.rss = action->conf;
-		*size = offsetof(struct rte_flow_action_rss, queue) +
-			conf.rss->num * sizeof(*conf.rss->queue);
-		break;
-	default:
-empty:
-		*size = 0;
-		break;
-	}
-	*pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size;
-}
-
-/** Generate a port_flow entry from attributes/pattern/actions. */
-static struct port_flow *
-port_flow_new(const struct rte_flow_attr *attr,
-	      const struct rte_flow_item *pattern,
-	      const struct rte_flow_action *actions)
-{
-	const struct rte_flow_item *item;
-	const struct rte_flow_action *action;
-	struct port_flow *pf = NULL;
-	size_t tmp;
-	size_t pad;
-	size_t off1 = 0;
-	size_t off2 = 0;
-	int err = ENOTSUP;
-
-store:
-	item = pattern;
-	if (pf)
-		pf->pattern = (void *)&pf->data[off1];
-	do {
-		struct rte_flow_item *dst = NULL;
-
-		if ((unsigned int)item->type >= RTE_DIM(flow_item) ||
-		    !flow_item[item->type].name)
-			goto notsup;
-		if (pf)
-			dst = memcpy(pf->data + off1, item, sizeof(*item));
-		off1 += sizeof(*item);
-		flow_item_spec_size(item, &tmp, &pad);
-		if (item->spec) {
-			if (pf)
-				dst->spec = memcpy(pf->data + off2,
-						   item->spec, tmp);
-			off2 += tmp + pad;
-		}
-		if (item->last) {
-			if (pf)
-				dst->last = memcpy(pf->data + off2,
-						   item->last, tmp);
-			off2 += tmp + pad;
-		}
-		if (item->mask) {
-			if (pf)
-				dst->mask = memcpy(pf->data + off2,
-						   item->mask, tmp);
-			off2 += tmp + pad;
-		}
-		off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
-	} while ((item++)->type != RTE_FLOW_ITEM_TYPE_END);
-	off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
-	action = actions;
-	if (pf)
-		pf->actions = (void *)&pf->data[off1];
-	do {
-		struct rte_flow_action *dst = NULL;
-
-		if ((unsigned int)action->type >= RTE_DIM(flow_action) ||
-		    !flow_action[action->type].name)
-			goto notsup;
-		if (pf)
-			dst = memcpy(pf->data + off1, action, sizeof(*action));
-		off1 += sizeof(*action);
-		flow_action_conf_size(action, &tmp, &pad);
-		if (action->conf) {
-			if (pf)
-				dst->conf = memcpy(pf->data + off2,
-						   action->conf, tmp);
-			off2 += tmp + pad;
-		}
-		off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
-	} while ((action++)->type != RTE_FLOW_ACTION_TYPE_END);
-	if (pf != NULL)
-		return pf;
-	off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
-	tmp = RTE_ALIGN_CEIL(offsetof(struct port_flow, data), sizeof(double));
-	pf = calloc(1, tmp + off1 + off2);
-	if (pf == NULL)
-		err = errno;
-	else {
-		*pf = (const struct port_flow){
-			.size = tmp + off1 + off2,
-			.attr = *attr,
-		};
-		tmp -= offsetof(struct port_flow, data);
-		off2 = tmp + off1;
-		off1 = tmp;
-		goto store;
-	}
-notsup:
-	rte_errno = err;
-	return NULL;
-}
-
 /** Print a message out of a flow error. */
 static int
 port_flow_complain(struct rte_flow_error *error)
@@ -1186,6 +984,28 @@ port_flow_validate(portid_t port_id,
 	return 0;
 }
 
+/** Generate a port_flow entry from attributes/pattern/actions. */
+static struct port_flow *
+port_flow_new(const struct rte_flow_attr *attr,
+	      const struct rte_flow_item *pattern,
+	      const struct rte_flow_action *actions)
+{
+	struct port_flow *pf;
+
+	pf = calloc(1, sizeof(struct port_flow));
+	if (!pf)
+		return NULL;
+
+	pf->fd = rte_flow_copy(attr, pattern, actions, NULL);
+	if (pf->fd == NULL) {
+		free(pf);
+		return NULL;
+	}
+	pf->size += pf->fd->size;
+
+	return pf;
+}
+
 /** Create flow rule. */
 int
 port_flow_create(portid_t port_id,
@@ -1265,6 +1085,7 @@ port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule)
 			}
 			printf("Flow rule #%u destroyed\n", pf->id);
 			*tmp = pf->next;
+			free(pf->fd);
 			free(pf);
 			break;
 		}
@@ -1325,11 +1146,11 @@ port_flow_query(portid_t port_id, uint32_t rule,
 		printf("Flow rule #%u not found\n", rule);
 		return -ENOENT;
 	}
-	if ((unsigned int)action >= RTE_DIM(flow_action) ||
-	    !flow_action[action].name)
+	if ((unsigned int)action >= RTE_FLOW_ACTION_TYPE_MAX ||
+	    !rte_flow_desc_data_action[action].name)
 		name = "unknown";
 	else
-		name = flow_action[action].name;
+		name = rte_flow_desc_data_action[action].name;
 	switch (action) {
 	case RTE_FLOW_ACTION_TYPE_COUNT:
 		break;
@@ -1385,18 +1206,18 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
 		if (n) {
 			/* Filter out unwanted groups. */
 			for (i = 0; i != n; ++i)
-				if (pf->attr.group == group[i])
+				if (pf->fd->attr.group == group[i])
 					break;
 			if (i == n)
 				continue;
 		}
 		tmp = &list;
 		while (*tmp &&
-		       (pf->attr.group > (*tmp)->attr.group ||
-			(pf->attr.group == (*tmp)->attr.group &&
-			 pf->attr.priority > (*tmp)->attr.priority) ||
-			(pf->attr.group == (*tmp)->attr.group &&
-			 pf->attr.priority == (*tmp)->attr.priority &&
+		       (pf->fd->attr.group > (*tmp)->fd->attr.group ||
+			(pf->fd->attr.group == (*tmp)->fd->attr.group &&
+			 pf->fd->attr.priority > (*tmp)->fd->attr.priority) ||
+			(pf->fd->attr.group == (*tmp)->fd->attr.group &&
+			 pf->fd->attr.priority == (*tmp)->fd->attr.priority &&
 			 pf->id > (*tmp)->id)))
 			tmp = &(*tmp)->tmp;
 		pf->tmp = *tmp;
@@ -1404,24 +1225,28 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
 	}
 	printf("ID\tGroup\tPrio\tAttr\tRule\n");
 	for (pf = list; pf != NULL; pf = pf->tmp) {
-		const struct rte_flow_item *item = pf->pattern;
-		const struct rte_flow_action *action = pf->actions;
+		const struct rte_flow_item *item = pf->fd->items;
+		const struct rte_flow_action *action = pf->fd->actions;
 
 		printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c\t",
 		       pf->id,
-		       pf->attr.group,
-		       pf->attr.priority,
-		       pf->attr.ingress ? 'i' : '-',
-		       pf->attr.egress ? 'e' : '-');
+		       pf->fd->attr.group,
+		       pf->fd->attr.priority,
+		       pf->fd->attr.ingress ? 'i' : '-',
+		       pf->fd->attr.egress ? 'e' : '-');
 		while (item->type != RTE_FLOW_ITEM_TYPE_END) {
 			if (item->type != RTE_FLOW_ITEM_TYPE_VOID)
-				printf("%s ", flow_item[item->type].name);
+				printf("%s ",
+				       rte_flow_desc_data_item[item->type].
+									name);
 			++item;
 		}
 		printf("=>");
 		while (action->type != RTE_FLOW_ACTION_TYPE_END) {
 			if (action->type != RTE_FLOW_ACTION_TYPE_VOID)
-				printf(" %s", flow_action[action->type].name);
+				printf(" %s",
+				       rte_flow_desc_data_action[action->type].
+									name);
 			++action;
 		}
 		printf("\n");
app/test-pmd/testpmd.h +1 -4
index 85d3e82..6002388 100644
@@ -153,10 +153,7 @@ struct port_flow {
 	struct port_flow *tmp; /**< Temporary linking. */
 	uint32_t id; /**< Flow rule ID. */
 	struct rte_flow *flow; /**< Opaque flow object returned by PMD. */
-	struct rte_flow_attr attr; /**< Attributes. */
-	struct rte_flow_item *pattern; /**< Pattern. */
-	struct rte_flow_action *actions; /**< Actions. */
-	uint8_t data[]; /**< Storage for pattern/actions. */
+	struct rte_flow_desc *fd; /**< Generic flow description */
 };
 
 /**
lib/librte_ether/rte_flow.c +283 -0

292 lines not on this page · raw message

lib/librte_ether/rte_flow.h +59 -0

77 lines not on this page · raw message

Signature · 1 line
2.1.4
#4 lore raw

PATCH 3/12 ethdev: add deferred intermediate device state

In reply to Gaetan Rivet

This device state means that the device is managed externally, by whichever party has set this state (PMD or application).

Note: this new device state is only an information. The related device structure and operators are still valid and can be used normally.

It is however made private by device management helpers within ethdev, making the device invisible to applications.

---
 lib/librte_ether/rte_ethdev.c | 3 ++-
 lib/librte_ether/rte_ethdev.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
lib/librte_ether/rte_ethdev.c +2 -1
index 61a63b7..7824f87 100644
@@ -382,7 +382,8 @@ int
 rte_eth_dev_is_valid_port(uint8_t port_id)
 {
 	if (port_id >= RTE_MAX_ETHPORTS ||
-	    rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED)
+	    (rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED &&
+	     rte_eth_devices[port_id].state != RTE_ETH_DEV_DEFERRED))
 		return 0;
 	else
 		return 1;
lib/librte_ether/rte_ethdev.h +1 -0
index f01d140..ae1e9e6 100644
@@ -1629,6 +1629,7 @@ struct rte_eth_rxtx_callback {
 enum rte_eth_dev_state {
 	RTE_ETH_DEV_UNUSED = 0,
 	RTE_ETH_DEV_ATTACHED,
+	RTE_ETH_DEV_DEFERRED,
 };
 
 /**
Signature · 1 line
2.1.4
#5 lore raw

Re: [PATCH 03/12] ethdev: add deferred intermediate device state

Quoted 6 lines · On Fri, 3 Mar 2017 16:40:25 +0100 Gaetan Rivet <[email protected]> wrote:

This device state means that the device is managed externally, by whichever party has set this state (PMD or application).

Note: this new device state is only an information. The related device structure and operators are still valid and can be used normally.

Quoted 6 lines

It is however made private by device management helpers within ethdev, making the device invisible to applications.

---
 lib/librte_ether/rte_ethdev.c | 3 ++-
 lib/librte_ether/rte_ethdev.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

Might be better to introduce RFC2863 operational states. This is something management tools might want.

#6 lore raw

PATCH 4/12 pci: expose device detach routine

In reply to Gaetan Rivet

Make the pci_detach_all_drivers public. No further changes.

---
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  5 +++++
 lib/librte_eal/common/eal_common_pci.c          |  6 +++---
 lib/librte_eal/common/include/rte_pci.h         | 15 +++++++++++++++
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  5 +++++
 4 files changed, 28 insertions(+), 3 deletions(-)
lib/librte_eal/bsdapp/eal/rte_eal_version.map +5 -0
index 2cf1ac8..3a87756 100644
@@ -185,3 +185,8 @@ DPDK_17.02 {
 	rte_bus_unregister;
 
 } DPDK_16.11;
+
+DPDK_17.05 {
+	rte_eal_pci_detach_all_drivers;
+
+} DPDK_17.02;
lib/librte_eal/common/eal_common_pci.c +3 -3
index 72547bd..d38335a 100644
@@ -313,8 +313,8 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
  * registered driver for the given device. Return -1 if initialization
  * failed, return 1 if no driver is found for this device.
  */
-static int
-pci_detach_all_drivers(struct rte_pci_device *dev)
+int
+rte_eal_pci_detach_all_drivers(struct rte_pci_device *dev)
 {
 	struct rte_pci_driver *dr = NULL;
 	int rc = 0;
@@ -388,7 +388,7 @@ rte_eal_pci_detach(const struct rte_pci_addr *addr)
 		if (rte_eal_compare_pci_addr(&dev->addr, addr))
 			continue;
 
-		ret = pci_detach_all_drivers(dev);
+		ret = rte_eal_pci_detach_all_drivers(dev);
 		if (ret < 0)
 			goto err_return;
 
lib/librte_eal/common/include/rte_pci.h +15 -0
index 4a67883..598a1ef 100644
@@ -459,6 +459,21 @@ void pci_unmap_resource(void *requested_addr, size_t size);
 int rte_eal_pci_probe_one(const struct rte_pci_addr *addr);
 
 /**
+ * Remove any PCI drivers tied to the device.
+ *
+ * If vendor/device ID match, call the remove() function of all
+ * registered driver for the given device.
+ *
+ * @param dev
+ *	The PCI device to remove
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ *   - Positive if no driver exists for that device.
+ */
+int rte_eal_pci_detach_all_drivers(struct rte_pci_device *dev);
+
+/**
  * Close the single PCI device.
  *
  * Scan the content of the PCI bus, and find the pci device specified by pci
lib/librte_eal/linuxapp/eal/rte_eal_version.map +5 -0
index 3c68ff5..192c0d5 100644
@@ -189,3 +189,8 @@ DPDK_17.02 {
 	rte_bus_unregister;
 
 } DPDK_16.11;
+
+DPDK_17.05 {
+	rte_eal_pci_detach_all_drivers;
+
+} DPDK_17.02;
Signature · 1 line
2.1.4
#7 lore raw

PATCH 5/12 pci: expose parse and probe routines

In reply to Gaetan Rivet

Make pci_probe_all_drivers public, no further changes to it. Introduce a public function for pci_scan_one. This functions scan one device, but does not allocate that device or insert it within the device list.

---
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  1 +
 lib/librte_eal/common/eal_common_pci.c          | 10 +++----
 lib/librte_eal/common/include/rte_pci.h         | 25 ++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           | 39 +++++++++++++++----------
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  2 ++
 5 files changed, 57 insertions(+), 20 deletions(-)
lib/librte_eal/bsdapp/eal/rte_eal_version.map +1 -0
index 3a87756..ba8f8e4 100644
@@ -188,5 +188,6 @@ DPDK_17.02 {
 
 DPDK_17.05 {
 	rte_eal_pci_detach_all_drivers;
+	rte_eal_pci_probe_all_drivers;
 
 } DPDK_17.02;
lib/librte_eal/common/eal_common_pci.c +5 -5
index d38335a..15a0c48 100644
@@ -282,8 +282,8 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr,
  * registered driver for the given device. Return -1 if initialization
  * failed, return 1 if no driver is found for this device.
  */
-static int
-pci_probe_all_drivers(struct rte_pci_device *dev)
+int
+rte_eal_pci_probe_all_drivers(struct rte_pci_device *dev)
 {
 	struct rte_pci_driver *dr = NULL;
 	int rc = 0;
@@ -358,7 +358,7 @@ rte_eal_pci_probe_one(const struct rte_pci_addr *addr)
 		if (rte_eal_compare_pci_addr(&dev->addr, addr))
 			continue;
 
-		ret = pci_probe_all_drivers(dev);
+		ret = rte_eal_pci_probe_all_drivers(dev);
 		if (ret)
 			goto err_return;
 		return 0;
@@ -430,10 +430,10 @@ rte_eal_pci_probe(void)
 
 		/* probe all or only whitelisted devices */
 		if (probe_all)
-			ret = pci_probe_all_drivers(dev);
+			ret = rte_eal_pci_probe_all_drivers(dev);
 		else if (devargs != NULL &&
 			devargs->type == RTE_DEVTYPE_WHITELISTED_PCI)
-			ret = pci_probe_all_drivers(dev);
+			ret = rte_eal_pci_probe_all_drivers(dev);
 		if (ret < 0)
 			rte_exit(EXIT_FAILURE, "Requested device " PCI_PRI_FMT
 				 " cannot be used\n", dev->addr.domain, dev->addr.bus,
lib/librte_eal/common/include/rte_pci.h +25 -0
index 598a1ef..4291da8 100644
@@ -373,6 +373,16 @@ rte_eal_compare_pci_addr(const struct rte_pci_addr *addr,
 int rte_eal_pci_scan(void);
 
 /**
+ * Parse the content of one PCI entry.
+ *
+ * @return
+ *  0 on success, negative on error
+ */
+int rte_eal_pci_parse_sysfs_entry(struct rte_pci_device *dev,
+				 const char *dirname,
+				 const struct rte_pci_addr *addr);
+
+/**
  * Probe the PCI bus for registered drivers.
  *
  * Scan the content of the PCI bus, and call the probe() function for
@@ -459,6 +469,21 @@ void pci_unmap_resource(void *requested_addr, size_t size);
 int rte_eal_pci_probe_one(const struct rte_pci_addr *addr);
 
 /**
+ * Probe all pci drivers against the device.
+ *
+ * If vendor/device ID match, call the probe() function of all
+ * registered driver for the given device.
+ *
+ * @param dev
+ *	The PCI device to probe
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ *   - Positive if no driver exists for that device.
+ */
+int rte_eal_pci_probe_all_drivers(struct rte_pci_device *dev);
+
+/**
  * Remove any PCI drivers tied to the device.
  *
  * If vendor/device ID match, call the remove() function of all
lib/librte_eal/linuxapp/eal/eal_pci.c +24 -15
index e2fc219..51c6b84 100644
@@ -226,27 +226,22 @@ pci_parse_sysfs_resource(const char *filename, struct rte_pci_device *dev)
 	return -1;
 }
 
-/* Scan one pci sysfs entry, and fill the devices list from it. */
-static int
-pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
+/* Parse a pci sysfs entry */
+int
+rte_eal_pci_parse_sysfs_entry(struct rte_pci_device *dev, const char *dirname,
+			const struct rte_pci_addr *addr)
 {
 	char filename[PATH_MAX];
 	unsigned long tmp;
-	struct rte_pci_device *dev;
 	char driver[PATH_MAX];
 	int ret;
 
-	dev = malloc(sizeof(*dev));
-	if (dev == NULL)
-		return -1;
-
 	memset(dev, 0, sizeof(*dev));
 	dev->addr = *addr;
 
 	/* get vendor id */
 	snprintf(filename, sizeof(filename), "%s/vendor", dirname);
 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
-		free(dev);
 		return -1;
 	}
 	dev->id.vendor_id = (uint16_t)tmp;
@@ -254,7 +249,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	/* get device id */
 	snprintf(filename, sizeof(filename), "%s/device", dirname);
 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
-		free(dev);
 		return -1;
 	}
 	dev->id.device_id = (uint16_t)tmp;
@@ -263,7 +257,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	snprintf(filename, sizeof(filename), "%s/subsystem_vendor",
 		 dirname);
 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
-		free(dev);
 		return -1;
 	}
 	dev->id.subsystem_vendor_id = (uint16_t)tmp;
@@ -272,7 +265,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	snprintf(filename, sizeof(filename), "%s/subsystem_device",
 		 dirname);
 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
-		free(dev);
 		return -1;
 	}
 	dev->id.subsystem_device_id = (uint16_t)tmp;
@@ -281,7 +273,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	snprintf(filename, sizeof(filename), "%s/class",
 		 dirname);
 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
-		free(dev);
 		return -1;
 	}
 	/* the least 24 bits are valid: class, subclass, program interface */
@@ -320,7 +311,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	snprintf(filename, sizeof(filename), "%s/resource", dirname);
 	if (pci_parse_sysfs_resource(filename, dev) < 0) {
 		RTE_LOG(ERR, EAL, "%s(): cannot parse resource\n", __func__);
-		free(dev);
 		return -1;
 	}
 
@@ -329,7 +319,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	ret = pci_get_kernel_driver_by_path(filename, driver);
 	if (ret < 0) {
 		RTE_LOG(ERR, EAL, "Fail to get kernel driver\n");
-		free(dev);
 		return -1;
 	}
 
@@ -345,6 +334,26 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	} else
 		dev->kdrv = RTE_KDRV_NONE;
 
+	return 0;
+}
+
+/* Scan one pci sysfs entry, and fill the devices list from it. */
+static int
+pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
+{
+	struct rte_pci_device *dev;
+	int ret;
+
+	dev = malloc(sizeof(*dev));
+	if (dev == NULL)
+		return -1;
+
+	ret = rte_eal_pci_parse_sysfs_entry(dev, dirname, addr);
+	if (ret) {
+		free(dev);
+		return ret;
+	}
+
 	/* device is valid, add in list (sorted) */
 	if (TAILQ_EMPTY(&pci_device_list)) {
 		rte_eal_device_insert(&dev->device);
lib/librte_eal/linuxapp/eal/rte_eal_version.map +2 -0
index 192c0d5..27b7939 100644
@@ -192,5 +192,7 @@ DPDK_17.02 {
 
 DPDK_17.05 {
 	rte_eal_pci_detach_all_drivers;
+	rte_eal_pci_probe_all_drivers;
+	rte_eal_pci_parse_sysfs_entry;
 
 } DPDK_17.02;
Signature · 1 line
2.1.4
#8 lore raw

PATCH 6/12 net/failsafe: add fail-safe PMD

In reply to Gaetan Rivet

Introduce the fail-safe poll mode driver initialization and enable its build infrastructure.

This PMD allows for applications to benefits from true hot-plugging support without having to implement it.

It intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back. It also allows defining a contingency to the removal of a device, by designating a fail-over device that will take on transmitting operations if the preferred device is removed.

Applications only see a fail-safe instance, without caring for underlying operations ensuring their continued operations.

---
 MAINTAINERS                             |   4 +
 config/common_linuxapp                  |   1 +
 drivers/net/Makefile                    |   1 +
 drivers/net/failsafe/Makefile           |  71 ++++
 drivers/net/failsafe/failsafe.c         | 229 +++++++++++
 drivers/net/failsafe/failsafe_args.c    | 347 ++++++++++++++++
 drivers/net/failsafe/failsafe_eal.c     | 318 +++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     | 677 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h | 234 +++++++++++
 drivers/net/failsafe/failsafe_rxtx.c    | 107 +++++
 mk/rte.app.mk                           |   1 +
 11 files changed, 1990 insertions(+)
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
MAINTAINERS +4 -0
index cc3bf98..58a77d0 100644
@@ -315,6 +315,10 @@ M: Matej Vido <[email protected]>
 F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 
+Failsafe PMD
+M: Gaetan Rivet <[email protected]>
+F: drivers/net/failsafe/
+
 Intel e1000
 M: Wenzhuo Lu <[email protected]>
 F: drivers/net/e1000/
config/common_linuxapp +1 -0
index 00ebaac..5e18267 100644
@@ -44,5 +44,6 @@ CONFIG_RTE_LIBRTE_PMD_VHOST=y
 CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_PMD_TAP=y
 CONFIG_RTE_LIBRTE_NFP_PMD=y
+CONFIG_RTE_LIBRTE_FAILSAFE_PMD=y
 CONFIG_RTE_LIBRTE_POWER=y
 CONFIG_RTE_VIRTIO_USER=y
drivers/net/Makefile +1 -0
index 40fc333..b8dcf96 100644
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += cxgbe
 DIRS-$(CONFIG_RTE_LIBRTE_E1000_PMD) += e1000
 DIRS-$(CONFIG_RTE_LIBRTE_ENA_PMD) += ena
 DIRS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) += enic
+DIRS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe
 DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k
 DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e
 DIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += ixgbe
drivers/net/failsafe/Makefile new file +71 -0

71 lines not on this page · raw message

drivers/net/failsafe/failsafe.c new file +229 -0

229 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c new file +347 -0

347 lines not on this page · raw message

drivers/net/failsafe/failsafe_eal.c new file +318 -0

318 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c new file +677 -0

677 lines not on this page · raw message

drivers/net/failsafe/failsafe_private.h new file +234 -0

234 lines not on this page · raw message

drivers/net/failsafe/failsafe_rxtx.c new file +107 -0

107 lines not on this page · raw message

mk/rte.app.mk +1 -0
index 92f3635..bbb64ce 100644
@@ -112,6 +112,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_E1000_PMD)      += -lrte_pmd_e1000
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENA_PMD)        += -lrte_pmd_ena
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENIC_PMD)       += -lrte_pmd_enic
 _LDLIBS-$(CONFIG_RTE_LIBRTE_FM10K_PMD)      += -lrte_pmd_fm10k
+_LDLIBS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD)   += -lrte_pmd_failsafe
 _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD)      += -lrte_pmd_ixgbe
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs
Signature · 1 line
2.1.4
#9 lore raw

Re: [PATCH 06/12] net/failsafe: add fail-safe PMD

Quoted 46 lines · On Fri, 3 Mar 2017 16:40:28 +0100 Gaetan Rivet <[email protected]> wrote:
drivers/net/failsafe/failsafe_eal.c new file +46 -0
+
+static struct rte_eth_dev *
+pci_addr_to_eth_dev(struct rte_pci_addr *addr)
+{
+	uint8_t pid;
+
+	if (addr == NULL)
+		return NULL;
+	for (pid = 0; pid < RTE_MAX_ETHPORTS; pid++) {
+		struct rte_pci_addr *addr2;
+		struct rte_eth_dev *edev;
+
+		edev = &rte_eth_devices[pid];
+		if (edev->device == NULL ||
+		    edev->device->devargs == NULL)
+			continue;
+		addr2 = &edev->device->devargs->pci.addr;
+		if (rte_eal_compare_pci_addr(addr, addr2) == 0)
+			return edev;
+	}
+	return NULL;
+}
+
+static int
+pci_scan_one(struct sub_device *sdev)
+{
+	struct rte_devargs *da;
+	char dirname[PATH_MAX];
+
+	da = &sdev->devargs;
+	snprintf(dirname, sizeof(dirname),
+		"%s/" PCI_PRI_FMT,
+		pci_get_sysfs_path(),
+		da->pci.addr.domain,
+		da->pci.addr.bus,
+		da->pci.addr.devid,
+		da->pci.addr.function);
+	errno = 0;
+	if (rte_eal_pci_parse_sysfs_entry(&sdev->pci_device,
+		dirname, &da->pci.addr) < 0) {
+		if (errno == ENOENT) {
+			DEBUG("Could not scan requested device " PCI_PRI_FMT,
+				da->pci.addr.domain,
+				da->pci.addr.bus,
+				da->pci.addr.devid,
+				da->pci.addr.function);

drivers/net/failsafe/failsafe_eal.c line 92

Quoted 10 lines
drivers/net/failsafe/failsafe_eal.c new file +10 -0
+		} else {
+			ERROR("Error while scanning sysfs entry %s",
+					dirname);
+			return -1;
+		}
+	} else {
+		sdev->state = DEV_SCANNED;
+	}
+	return 0;
+}

This needs to be generic and in EAL.
A bigger problem is that it PCI specific and therefore won't work in environments where devices are attached to different busses (SOC and Hyper-V).

Please rework to play well with bus model.

#10 lore raw

Re: [PATCH 06/12] net/failsafe: add fail-safe PMD

Quoted 64 lines · Stephen Hemminger
Quoted 46 lines · On Fri, 3 Mar 2017 16:40:28 +0100 Gaetan Rivet <[email protected]> wrote:
drivers/net/failsafe/failsafe_eal.c new file +46 -0
+
+static struct rte_eth_dev *
+pci_addr_to_eth_dev(struct rte_pci_addr *addr)
+{
+	uint8_t pid;
+
+	if (addr == NULL)
+		return NULL;
+	for (pid = 0; pid < RTE_MAX_ETHPORTS; pid++) {
+		struct rte_pci_addr *addr2;
+		struct rte_eth_dev *edev;
+
+		edev = &rte_eth_devices[pid];
+		if (edev->device == NULL ||
+		    edev->device->devargs == NULL)
+			continue;
+		addr2 = &edev->device->devargs->pci.addr;
+		if (rte_eal_compare_pci_addr(addr, addr2) == 0)
+			return edev;
+	}
+	return NULL;
+}
+
+static int
+pci_scan_one(struct sub_device *sdev)
+{
+	struct rte_devargs *da;
+	char dirname[PATH_MAX];
+
+	da = &sdev->devargs;
+	snprintf(dirname, sizeof(dirname),
+		"%s/" PCI_PRI_FMT,
+		pci_get_sysfs_path(),
+		da->pci.addr.domain,
+		da->pci.addr.bus,
+		da->pci.addr.devid,
+		da->pci.addr.function);
+	errno = 0;
+	if (rte_eal_pci_parse_sysfs_entry(&sdev->pci_device,
+		dirname, &da->pci.addr) < 0) {
+		if (errno == ENOENT) {
+			DEBUG("Could not scan requested device " PCI_PRI_FMT,
+				da->pci.addr.domain,
+				da->pci.addr.bus,
+				da->pci.addr.devid,
+				da->pci.addr.function);

drivers/net/failsafe/failsafe_eal.c line 92

Quoted 10 lines
drivers/net/failsafe/failsafe_eal.c new file +10 -0
+		} else {
+			ERROR("Error while scanning sysfs entry %s",
+					dirname);
+			return -1;
+		}
+	} else {
+		sdev->state = DEV_SCANNED;
+	}
+	return 0;
+}

This needs to be generic and in EAL.
A bigger problem is that it PCI specific and therefore won't work in environments where devices are attached to different busses (SOC and Hyper-V).

Quoted 1 line

Please rework to play well with bus model.

Yes I agree, I planned to do so in any case for a V2.

I saw a few commits from Jan Blunck about a vdev bus[0].
Do you have other series regarding busses in mind that I should rebase upon for a better support?

[0]: http://dpdk.org/ml/archives/dev/2017-March/059423.html

Signature · 2 lines
Gaëtan Rivet
6WIND
#11 lore raw

PATCH 7/12 net/failsafe: add plug-in support

In reply to Gaetan Rivet

Periodically check for the existence of a device.
If a device has not been initialized and exists on the system, then it is probed and configured.

The configuration process strives to synchronize the states between the plugged-in sub-device and the fail-safe device.

---
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |  49 +++++++
 drivers/net/failsafe/failsafe_args.c    |  32 +++++
 drivers/net/failsafe/failsafe_eal.c     |  30 +----
 drivers/net/failsafe/failsafe_ether.c   | 227 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  24 ++--
 drivers/net/failsafe/failsafe_private.h |  53 ++++++++
 7 files changed, 375 insertions(+), 41 deletions(-)
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
drivers/net/failsafe/Makefile +1 -0
index 3b7a644..38acf3c 100644
@@ -38,6 +38,7 @@ LIB = librte_pmd_failsafe.a
 SRCS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe.c
 SRCS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe_args.c
 SRCS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe_eal.c
+SRCS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe_ether.c
 SRCS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe_rxtx.c
 
drivers/net/failsafe/failsafe.c +49 -0

61 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c +32 -0
index faa48f4..773b322 100644
@@ -45,9 +45,11 @@
 typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
 		uint8_t head);
 
+uint64_t plug_in_poll;
 int mac_from_arg;
 
 const char *pmd_failsafe_init_parameters[] = {
+	PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
 	PMD_FAILSAFE_MAC_KVARG,
 	NULL,
 };
@@ -237,6 +239,24 @@ remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
 }
 
 static int
+get_u64_arg(const char *key __rte_unused,
+		const char *value, void *out)
+{
+	uint64_t *u64 = out;
+	char *endptr = NULL;
+
+	if ((value == NULL) || (out == NULL))
+		return -EINVAL;
+	errno = 0;
+	*u64 = strtoull(value, &endptr, 0);
+	if (errno != 0)
+		return -errno;
+	if (endptr == value)
+		return -1;
+	return 0;
+}
+
+static int
 get_mac_addr_arg(const char *key __rte_unused,
 		const char *value, void *out)
 {
@@ -268,6 +288,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 	ret = 0;
 	priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
 	/* default parameters */
+	plug_in_poll = FAILSAFE_PLUGIN_DEFAULT_TIMEOUT_MS;
 	mac_from_arg = 0;
 	n = snprintf(mut_params, sizeof(mut_params), "%s", params);
 	if (n >= sizeof(mut_params)) {
@@ -290,6 +311,16 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 				PMD_FAILSAFE_PARAM_STRING);
 			return -1;
 		}
+		/* PLUG_IN event poll timer */
+		arg_count = rte_kvargs_count(kvlist,
+				PMD_FAILSAFE_PLUG_IN_POLL_KVARG);
+		if (arg_count == 1) {
+			ret = rte_kvargs_process(kvlist,
+					PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
+					&get_u64_arg, &plug_in_poll);
+			if (ret < 0)
+				goto free_kvlist;
+		}
 		/* MAC addr */
 		arg_count = rte_kvargs_count(kvlist,
 				PMD_FAILSAFE_MAC_KVARG);
@@ -303,6 +334,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 			mac_from_arg = 1;
 		}
 	}
+	PRIV(dev)->state = DEV_PARSED;
 free_kvlist:
 	rte_kvargs_free(kvlist);
 	return ret;
drivers/net/failsafe/failsafe_eal.c +4 -26
index fcee500..a5e8c3c 100644
@@ -198,8 +198,6 @@ pci_probe(struct rte_eth_dev *dev)
 int
 failsafe_eal_init(struct rte_eth_dev *dev)
 {
-	struct sub_device *sdev;
-	uint8_t i;
 	int ret;
 
 	ret = pci_scan(dev);
@@ -211,30 +209,9 @@ failsafe_eal_init(struct rte_eth_dev *dev)
 	ret = dev_init(dev);
 	if (ret)
 		return ret;
-	/*
-	 * We only update TX_SUBDEV if we are not started.
-	 * If a sub_device is emitting, we will switch the TX_SUBDEV to the
-	 * preferred port only upon starting it, so that the switch is smoother.
-	 */
-	if (PREFERRED_SUBDEV(dev)->state >= DEV_PROBED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev) &&
-		    (TX_SUBDEV(dev) == NULL ||
-		     (TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED))) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_PROBED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			/* Using first probed device */
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_PROBED) {
-				DEBUG("Switching tx_dev to sub_device %d",
-				      i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_PROBED)
+		PRIV(dev)->state = DEV_PROBED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -314,5 +291,6 @@ failsafe_eal_uninit(struct rte_eth_dev *dev)
 	ret = dev_uninit(dev);
 	if (ret)
 		return ret;
+	PRIV(dev)->state = DEV_PROBED - 1;
 	return 0;
 }
drivers/net/failsafe/failsafe_ether.c new file +227 -0

227 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +9 -15
index 470fea4..e96b43c 100644
@@ -89,6 +89,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 		sdev->state = DEV_ACTIVE;
 	}
+	if (PRIV(dev)->state < DEV_ACTIVE)
+		PRIV(dev)->state = DEV_ACTIVE;
 	return 0;
 }
 
@@ -108,21 +110,9 @@ fs_dev_start(struct rte_eth_dev *dev)
 			return ret;
 		sdev->state = DEV_STARTED;
 	}
-	if (PREFERRED_SUBDEV(dev)->state == DEV_STARTED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev)) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
-				DEBUG("Switching tx_dev to sub_device %d", i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_STARTED)
+		PRIV(dev)->state = DEV_STARTED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -132,6 +122,7 @@ fs_dev_stop(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	PRIV(dev)->state = DEV_STARTED - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
 		rte_eth_dev_stop(PORT_ID(sdev));
 		sdev->state = DEV_STARTED - 1;
@@ -183,6 +174,9 @@ fs_dev_close(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	if (PRIV(dev)->state == DEV_STARTED)
+		dev->dev_ops->dev_stop(dev);
+	PRIV(dev)->state = DEV_ACTIVE - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
 		DEBUG("Closing sub_device %d", i);
 		rte_eth_dev_close(PORT_ID(sdev));
drivers/net/failsafe/failsafe_private.h +53 -0

84 lines not on this page · raw message

Signature · 1 line
2.1.4
#12 lore raw

PATCH 8/12 net/failsafe: add flexible device definition

In reply to Gaetan Rivet

Add the "exec" device type.
The parameters given to this type of device will be executed in a shell. The output of this command is then used as a definition for a device.

That command can be re-interpreted if the related device is not plugged-in. It allows for a device definition to react to system changes (e.g. changing PCI bus for a given device).

---
 drivers/net/failsafe/failsafe_args.c    | 102 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ether.c   |   7 +++
 drivers/net/failsafe/failsafe_private.h |   4 ++
 3 files changed, 113 insertions(+)
drivers/net/failsafe/failsafe_args.c +102 -0
index 773b322..839831f 100644
@@ -112,6 +112,80 @@ parse_device(struct sub_device *sdev, char *args)
 	return 0;
 }
 
+static void
+sanitize_cmdline(char *args)
+{
+	size_t len;
+
+	len = strnlen(args, DEVARGS_MAXLEN);
+	args[len - 1] = '\0';
+}
+
+static int
+execute_cmd(struct sub_device *sdev, char *cmdline)
+{
+	FILE *fp;
+	/* store possible newline as well */
+	char output[DEVARGS_MAXLEN + 1];
+	size_t len;
+	int old_err;
+	int ret;
+
+	DEBUG("'%s'", cmdline);
+	if (cmdline == NULL &&
+	    sdev->cmdline == NULL) {
+		/* debug: should never happen to a user */
+		DEBUG("Invalid command line");
+		return -EINVAL;
+	}
+	if (sdev->cmdline == NULL) {
+		char *new_str;
+
+		len = strlen(cmdline) + 1;
+		new_str = rte_realloc(sdev->cmdline, len,
+				RTE_CACHE_LINE_SIZE);
+		if (new_str == NULL) {
+			ERROR("Command line allocation failed");
+			return -ENOMEM;
+		}
+		sdev->cmdline = new_str;
+		snprintf(sdev->cmdline, len, "%s", cmdline);
+	} else {
+		if (strcmp(sdev->cmdline, cmdline))
+			DEBUG("cmd mismatch: '%s' != '%s'",
+				sdev->cmdline, cmdline);
+		cmdline = sdev->cmdline;
+	}
+	old_err = errno;
+	fp = popen(cmdline, "r");
+	if (fp == NULL) {
+		ret = errno;
+		ERROR("popen: %s", strerror(errno));
+		errno = old_err;
+		return ret;
+	}
+	/* We only read one line */
+	if (fgets(output, sizeof(output) - 1, fp) == NULL) {
+		DEBUG("Could not read command output");
+		return -ENODEV;
+	}
+	sanitize_cmdline(output);
+	ret = parse_device(sdev, output);
+	if (ret) {
+		ERROR("Parsing device '%s' failed", output);
+		goto ret_pclose;
+	}
+ret_pclose:
+	ret = pclose(fp);
+	if (ret) {
+		ret = errno;
+		ERROR("pclose: %s", strerror(errno));
+		errno = old_err;
+		return ret;
+	}
+	return ret;
+}
+
 static int
 parse_device_param(struct rte_eth_dev *dev, const char *param,
 		uint8_t head)
@@ -146,6 +220,14 @@ parse_device_param(struct rte_eth_dev *dev, const char *param,
 		ret = parse_device(sdev, args);
 		if (ret)
 			goto free_args;
+	} else if (strncmp(param, "exec", 4) == 0) {
+		ret = execute_cmd(sdev, args);
+		if (ret == -ENODEV) {
+			DEBUG("Reading device info from command line failed");
+			ret = 0;
+		}
+		if (ret)
+			goto free_args;
 	} else {
 		ERROR("Unrecognized device type: %.*s", (int)b, param);
 		return -EINVAL;
@@ -347,6 +429,8 @@ failsafe_args_free(struct rte_eth_dev *dev)
 	uint8_t i;
 
 	FOREACH_SUBDEV(sdev, i, dev) {
+		rte_free(sdev->cmdline);
+		sdev->cmdline = NULL;
 		free(sdev->devargs.args);
 		sdev->devargs.args = NULL;
 	}
@@ -377,3 +461,21 @@ failsafe_args_count_subdevice(struct rte_eth_dev *dev,
 	return parse_sub_devices(count_device,
 				dev, params);
 }
+
+int
+failsafe_args_parse_subs(struct rte_eth_dev *dev)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret = 0;
+
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state >= DEV_PARSED)
+			continue;
+		if (sdev->cmdline)
+			ret = execute_cmd(sdev, sdev->cmdline);
+		if (ret == 0)
+			sdev->state = DEV_PARSED;
+	}
+	return 0;
+}
drivers/net/failsafe/failsafe_ether.c +7 -0
index 9f4a0a0..2d90bcb 100644
@@ -188,6 +188,13 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	int ret;
 	uint8_t i;
 
+	if (PRIV(dev)->state < DEV_PARSED)
+		return 0;
+
+	ret = failsafe_args_parse_subs(dev);
+	if (ret)
+		return ret;
+
 	if (PRIV(dev)->state < DEV_PROBED)
 		return 0;
 	ret = failsafe_eal_init(dev);
drivers/net/failsafe/failsafe_private.h +4 -0
index 8659c6f..c1aa24d 100644
@@ -94,6 +94,9 @@ struct sub_device {
 	struct rte_eth_dev_data data;
 	/* Device state machine */
 	enum dev_state state;
+
+	/* Some device are defined as a command line */
+	char *cmdline;
 };
 
 struct fs_priv {
@@ -140,6 +143,7 @@ uint16_t failsafe_tx_burst(void *txq,
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
 void failsafe_args_free(struct rte_eth_dev *dev);
 int failsafe_args_count_subdevice(struct rte_eth_dev *dev, const char *params);
+int failsafe_args_parse_subs(struct rte_eth_dev *dev);
 
 /* EAL */
 
Signature · 1 line
2.1.4
#13 lore raw

PATCH 9/12 net/failsafe: support flow API

In reply to Gaetan Rivet
---
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |   1 +
 drivers/net/failsafe/failsafe_eal.c     |   2 +
 drivers/net/failsafe/failsafe_ether.c   |  76 +++++++++++
 drivers/net/failsafe/failsafe_flow.c    | 230 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  29 ++++
 drivers/net/failsafe/failsafe_private.h |  20 +++
 7 files changed, 359 insertions(+)
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
drivers/net/failsafe/Makefile +1 -0
index 38acf3c..92519ac 100644
@@ -41,6 +41,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe_ether.c
 SRCS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe_rxtx.c
+SRCS-$(CONFIG_RTE_LIBRTE_FAILSAFE_PMD) += failsafe_flow.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +1 -0
index 36d266f..fbe8f55 100644
@@ -161,6 +161,7 @@ eth_dev_create(const char *name,
 	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
 	dev->data->dev_link = eth_link;
 	PRIV(dev)->nb_mac_addr = 1;
+	TAILQ_INIT(&PRIV(dev)->flow_list);
 	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
 	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
 	if (params == NULL) {
drivers/net/failsafe/failsafe_eal.c +2 -0
index a5e8c3c..9817fc9 100644
@@ -139,6 +139,7 @@ dev_init(struct rte_eth_dev *dev)
 				continue;
 			}
 			ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
+			SUB_ID(sdev) = i;
 			sdev->state = DEV_PROBED;
 		}
 	}
@@ -189,6 +190,7 @@ pci_probe(struct rte_eth_dev *dev)
 				continue;
 			}
 			ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
+			SUB_ID(sdev) = i;
 			sdev->state = DEV_PROBED;
 		}
 	}
drivers/net/failsafe/failsafe_ether.c +76 -0

96 lines not on this page · raw message

drivers/net/failsafe/failsafe_flow.c new file +230 -0

230 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +29 -0
index e96b43c..57de33f 100644
@@ -35,6 +35,7 @@
 #include <stdint.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_flow.h>
 
 #include "failsafe_private.h"
 
@@ -641,6 +642,33 @@ fs_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 		rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), mac_addr);
 }
 
+static int
+fs_filter_ctrl(struct rte_eth_dev *dev,
+		enum rte_filter_type type,
+		enum rte_filter_op op,
+		void *arg)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	if (type == RTE_ETH_FILTER_GENERIC &&
+	    op == RTE_ETH_FILTER_GET) {
+		*(const void **)arg = &fs_flow_ops;
+		return 0;
+	}
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		DEBUG("Calling rte_eth_dev_filter_ctrl on sub_device %d", i);
+		ret = rte_eth_dev_filter_ctrl(PORT_ID(sdev), type, op, arg);
+		if (ret) {
+			ERROR("Operation rte_eth_dev_filter_ctrl failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
 const struct eth_dev_ops failsafe_ops = {
 	.dev_configure = fs_dev_configure,
 	.dev_start = fs_dev_start,
@@ -668,4 +696,5 @@ const struct eth_dev_ops failsafe_ops = {
 	.mac_addr_remove = fs_mac_addr_remove,
 	.mac_addr_add = fs_mac_addr_add,
 	.mac_addr_set = fs_mac_addr_set,
+	.filter_ctrl = fs_filter_ctrl,
 };
drivers/net/failsafe/failsafe_private.h +20 -0
index c1aa24d..d20f9b6 100644
@@ -34,6 +34,8 @@
 #ifndef _RTE_ETH_FAILSAFE_PRIVATE_H_
 #define _RTE_ETH_FAILSAFE_PRIVATE_H_
 
+#include <sys/queue.h>
+
 #include <rte_dev.h>
 #include <rte_pci.h>
 #include <rte_ethdev.h>
@@ -73,6 +75,16 @@ struct txq {
 	struct rte_eth_txq_info info;
 };
 
+struct rte_flow {
+	TAILQ_ENTRY(rte_flow) next;
+
+	/* sub_flows */
+	struct rte_flow *flows[FAILSAFE_MAX_ETHPORTS];
+
+	/* flow description for synchronization */
+	struct rte_flow_desc *fd;
+};
+
 enum dev_state {
 	DEV_UNDEFINED = 0,
 	DEV_PARSED,
@@ -92,6 +104,7 @@ struct sub_device {
 	};
 	struct rte_eth_dev *eth_dev;
 	struct rte_eth_dev_data data;
+	uint8_t sid;
 	/* Device state machine */
 	enum dev_state state;
 
@@ -111,6 +124,8 @@ struct fs_priv {
 	uint8_t subs_tx;
 	struct sub_device *subs;
 	uint8_t current_probed;
+	/* flow mapping */
+	TAILQ_HEAD(sub_flows, rte_flow) flow_list;
 	/* current number of mac_addr slots allocated. */
 	uint32_t nb_mac_addr;
 	struct ether_addr mac_addrs[FAILSAFE_MAX_ETHADDR];
@@ -158,6 +173,7 @@ int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);
 
 extern const char pmd_failsafe_driver_name[];
 extern const struct eth_dev_ops failsafe_ops;
+extern const struct rte_flow_ops fs_flow_ops;
 extern uint64_t plug_in_poll;
 extern int mac_from_arg;
 
@@ -175,6 +191,10 @@ extern int mac_from_arg;
 #define PORT_ID(sdev) \
 	(ETH(sdev)->data->port_id)
 
+/* sdev: (struct sub_device *) */
+#define SUB_ID(sdev) \
+	(sdev->sid)
+
 /**
  * Stateful iterator construct over fail-safe sub-devices:
  * s:     (struct sub_device *), iterator
Signature · 1 line
2.1.4
#14 lore raw

PATCH 10/12 net/failsafe: support offload capabilities

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_ops.c | 125 +++++++++++++++++++++++++++++++++++-
 1 file changed, 123 insertions(+), 2 deletions(-)
drivers/net/failsafe/failsafe_ops.c +123 -2
index 57de33f..0ed49b2 100644
@@ -63,22 +63,143 @@ static struct rte_eth_dev_info default_infos = {
 		.nb_seg_max = UINT16_MAX,
 		.nb_mtu_seg_max = UINT16_MAX,
 	},
-	/* Set of understood capabilities */
-	.rx_offload_capa = 0x0,
+	/*
+	 * Set of capabilities that can be verified upon
+	 * configuring a sub-device.
+	 */
+	.rx_offload_capa =
+		DEV_RX_OFFLOAD_VLAN_STRIP |
+		DEV_RX_OFFLOAD_QINQ_STRIP |
+		DEV_RX_OFFLOAD_IPV4_CKSUM |
+		DEV_RX_OFFLOAD_UDP_CKSUM |
+		DEV_RX_OFFLOAD_TCP_CKSUM |
+		DEV_RX_OFFLOAD_TCP_LRO,
 	.tx_offload_capa = 0x0,
 	.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))) {
+			if (PRIV(dev)->state >= DEV_ACTIVE) {
+				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) {
+		if (sdev->state != DEV_PROBED)
+			continue;
 		DEBUG("Configuring sub-device %d", i);
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
 					dev->data->nb_rx_queues,
Signature · 1 line
2.1.4
#15 lore raw

PATCH 11/12 net/failsafe: add fast burst functions

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_private.h |   8 +++
 drivers/net/failsafe/failsafe_rxtx.c    | 117 ++++++++++++++++++++++++++------
 2 files changed, 105 insertions(+), 20 deletions(-)
drivers/net/failsafe/failsafe_private.h +8 -0
index d20f9b6..db7ce93 100644
@@ -148,11 +148,18 @@ int failsafe_plugin_alarm_install(struct rte_eth_dev *dev);
 
 /* RX / TX */
 
+void set_burst_fn(struct rte_eth_dev *dev);
+
 uint16_t failsafe_rx_burst(void *rxq,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t failsafe_tx_burst(void *txq,
 		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 
+uint16_t failsafe_rx_burst_fast(void *rxq,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t failsafe_tx_burst_fast(void *txq,
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+
 /* ARGS */
 
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
@@ -306,6 +313,7 @@ fs_switch_dev(struct rte_eth_dev *dev)
 	} else {
 		return;
 	}
+	set_burst_fn(dev);
 }
 
 #endif /* _RTE_ETH_FAILSAFE_PRIVATE_H_ */
drivers/net/failsafe/failsafe_rxtx.c +97 -20

142 lines not on this page · raw message

Signature · 1 line
2.1.4
#16 lore raw

PATCH 12/12 net/failsafe: support device removal

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_args.c    | 22 ++++++++++++
 drivers/net/failsafe/failsafe_eal.c     |  2 ++
 drivers/net/failsafe/failsafe_ether.c   | 62 +++++++++++++++++++++++++++++++--
 drivers/net/failsafe/failsafe_ops.c     | 17 +++++++++
 drivers/net/failsafe/failsafe_private.h |  7 ++++
 5 files changed, 108 insertions(+), 2 deletions(-)
drivers/net/failsafe/failsafe_args.c +22 -0
index 839831f..62033c4 100644
@@ -462,6 +462,26 @@ failsafe_args_count_subdevice(struct rte_eth_dev *dev,
 				dev, params);
 }
 
+static int
+parse_sub_device(struct sub_device *sdev)
+{
+	struct rte_devargs *da;
+	char params[DEVARGS_MAXLEN] = "";
+
+	da = &sdev->devargs;
+	if (da->type == RTE_DEVTYPE_VIRTUAL)
+		snprintf(params, sizeof(params) - 1,
+			"%s,%s", da->virt.drv_name, da->args);
+	else
+		snprintf(params, sizeof(params) - 1,
+			PCI_PRI_FMT ",%s",
+			da->pci.addr.domain, da->pci.addr.bus,
+			da->pci.addr.devid, da->pci.addr.function,
+			da->args);
+
+	return parse_device(sdev, params);
+}
+
 int
 failsafe_args_parse_subs(struct rte_eth_dev *dev)
 {
@@ -474,6 +494,8 @@ failsafe_args_parse_subs(struct rte_eth_dev *dev)
 			continue;
 		if (sdev->cmdline)
 			ret = execute_cmd(sdev, sdev->cmdline);
+		else
+			ret = parse_sub_device(sdev);
 		if (ret == 0)
 			sdev->state = DEV_PARSED;
 	}
drivers/net/failsafe/failsafe_eal.c +2 -0
index 9817fc9..8bb8d45 100644
@@ -140,6 +140,7 @@ dev_init(struct rte_eth_dev *dev)
 			}
 			ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 			SUB_ID(sdev) = i;
+			sdev->fs_dev = dev;
 			sdev->state = DEV_PROBED;
 		}
 	}
@@ -191,6 +192,7 @@ pci_probe(struct rte_eth_dev *dev)
 			}
 			ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 			SUB_ID(sdev) = i;
+			sdev->fs_dev = dev;
 			sdev->state = DEV_PROBED;
 		}
 	}
drivers/net/failsafe/failsafe_ether.c +60 -2

87 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +17 -0
index 0ed49b2..c2524c7 100644
@@ -198,8 +198,19 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
+		int rmv_interrupt = 0;
+
 		if (sdev->state != DEV_PROBED)
 			continue;
+
+		rmv_interrupt = ETH(sdev)->data->dev_flags &
+				RTE_ETH_DEV_INTR_RMV;
+		if (rmv_interrupt) {
+			DEBUG("Enabling RMV interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.rmv = 1;
+		} else {
+			DEBUG("sub_device %d does not support RMV event", i);
+		}
 		DEBUG("Configuring sub-device %d", i);
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
 					dev->data->nb_rx_queues,
@@ -209,6 +220,12 @@ fs_dev_configure(struct rte_eth_dev *dev)
 			ERROR("Could not configure sub_device %d", i);
 			return ret;
 		}
+		if (rmv_interrupt)
+			rte_eth_dev_callback_register(PORT_ID(sdev),
+					RTE_ETH_EVENT_INTR_RMV,
+					failsafe_eth_rmv_event_callback,
+					sdev);
+		dev->data->dev_conf.intr_conf.rmv = 0;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
drivers/net/failsafe/failsafe_private.h +7 -0
index db7ce93..fcaccc3 100644
@@ -53,6 +53,7 @@
 	""
 
 #define FAILSAFE_PLUGIN_DEFAULT_TIMEOUT_MS 2000
+#define FAILSAFE_PLUGOUT_ASYNC_RESCHED_US 100000
 
 #define FAILSAFE_MAX_ETHPORTS (RTE_MAX_ETHPORTS - 1)
 #define FAILSAFE_MAX_ETHADDR 128
@@ -110,6 +111,9 @@ struct sub_device {
 
 	/* Some device are defined as a command line */
 	char *cmdline;
+
+	/* fail-safe device backreference */
+	struct rte_eth_dev *fs_dev;
 };
 
 struct fs_priv {
@@ -175,6 +179,9 @@ int failsafe_eal_uninit(struct rte_eth_dev *dev);
 /* ETH_DEV */
 
 int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);
+void failsafe_eth_rmv_event_callback(uint8_t port_id,
+				     enum rte_eth_event_type type,
+				     void *arg);
 
 /* GLOBALS */
 
Signature · 1 line
2.1.4
#17 lore raw
In reply to Gaetan Rivet
Quoted 21 lines · Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Quoted 9 lines

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This series depends on the series
[PATCH 0/4] clarify eth_dev state management
[PATCH 0/5] add device removal event

Hi,

this looks an interesting PMD, and I like the wrapper approach. However, why duplicate the functionality of the bonding device in another device driver? Is it not possible to have this driver wrap individual devices and then have the bonding driver use those wrapped devices to present an omni-present device? It seems strange to have support for grouping devices together in two different drivers - one should leverage the other.

Alternatively, should this be merged into the bonding driver or replace it?

Regards,
/Bruce

#18 lore raw
Quoted 27 lines · Bruce Richardson
Quoted 26 lines · Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

Quoted 6 lines
Quoted 4 lines

This series depends on the series
[PATCH 0/4] clarify eth_dev state management
[PATCH 0/5] add device removal event

Hi,

Hi Bruce,

Quoted 8 lines

this looks an interesting PMD, and I like the wrapper approach. However, why duplicate the functionality of the bonding device in another device driver? Is it not possible to have this driver wrap individual devices and then have the bonding driver use those wrapped devices to present an omni-present device? It seems strange to have support for grouping devices together in two different drivers - one should leverage the other.

Yes there appears to be a certain amount of overlap between these two PMDs from the above description. Actually we've considered modifying bonding at first but found it to be fundamentally incompatible:

- By design, with bonding, applications are aware of slave PMDs and can use them directly (even if they shouldn't, depending on the aggregation mode). If they were supported, hot-plug events would have to be managed by the application as well.

- With fail-safe, slaves are provided as PMD parameters and are fully owned by the parent instance, which takes care of their entire initialization and provides transparent support for hot-plug events.

Their purposes also differ:

- Bonding implements various modes of operation for link aggregation (round robin, active backup, LACP...) in the same fashion as the Linux bond driver.

- Fail-safe handles hot-plug events so applications do not have to.

To answer your second question, both are stackable: the fail-safe design aims at being the most transparent possible, meaning that it should make no difference to applications using it, whether within a bond or not.

Quoted 3 lines

Alternatively, should this be merged into the bonding driver or replace it?

Applications (or users) that need their combined functionality benefit from greater flexibility this way, so I think having them both in the tree makes sense.

Quoted 2 lines

Regards,
/Bruce

Regards

Signature · 2 lines
Gaëtan Rivet
6WIND
#19 lore raw
In reply to Gaetan Rivet
Quoted 18 lines · On Fri, 3 Mar 2017 16:40:22 +0100 Gaetan Rivet <[email protected]> wrote:

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Quoted 8 lines

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This looks interesting for SR-IOV VF support on Hyper-V. It would be good if the driver worked in interrupt mode as well.

#20 lore raw

v2 cover introduce fail-safe PMD

In reply to Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This series depends on the series
[PATCH 0/4] clarify eth_dev state management
[PATCH 0/5] add device removal event

v1 --> v2:

- Wrote documentation
- Fixed commit logs, signed-off-by
- Added LSC event support
- A few minor fixes

Gaetan Rivet (13):
ethdev: save VLAN filter setting
ethdev: add flow API rule copy function
ethdev: add deferred intermediate device state
pci: expose device detach routine
pci: expose parse and probe routines
net/failsafe: add fail-safe PMD
net/failsafe: add plug-in support
net/failsafe: add flexible device definition
net/failsafe: support flow API
net/failsafe: support offload capabilities
net/failsafe: add fast burst functions
net/failsafe: support device removal
net/failsafe: support link status change event

 MAINTAINERS                                     |   5 +
 app/test-pmd/config.c                           | 263 ++-----
 app/test-pmd/testpmd.h                          |   5 +-
 config/common_base                              |   5 +
 doc/guides/nics/fail_safe.rst                   | 182 +++++
 doc/guides/nics/features/failsafe.ini           |  32 +
 doc/guides/nics/index.rst                       |   1 +
 drivers/net/Makefile                            |   1 +
 drivers/net/failsafe/Makefile                   |  74 ++
 drivers/net/failsafe/failsafe.c                 | 299 ++++++++
 drivers/net/failsafe/failsafe_args.c            | 503 ++++++++++++++
 drivers/net/failsafe/failsafe_eal.c             | 300 ++++++++
 drivers/net/failsafe/failsafe_ether.c           | 394 +++++++++++
 drivers/net/failsafe/failsafe_flow.c            | 230 +++++++
 drivers/net/failsafe/failsafe_ops.c             | 867 ++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h         | 329 +++++++++
 drivers/net/failsafe/failsafe_rxtx.c            | 184 +++++
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   6 +
 lib/librte_eal/common/eal_common_pci.c          |  16 +-
 lib/librte_eal/common/include/rte_pci.h         |  40 ++
 lib/librte_eal/linuxapp/eal/eal_pci.c           |  39 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   7 +
 lib/librte_ether/rte_ethdev.c                   |  22 +-
 lib/librte_ether/rte_ethdev.h                   |  11 +
 lib/librte_ether/rte_flow.c                     | 283 ++++++++
 lib/librte_ether/rte_flow.h                     |  59 ++
 mk/rte.app.mk                                   |   1 +
 27 files changed, 3910 insertions(+), 248 deletions(-)
 create mode 100644 doc/guides/nics/fail_safe.rst
 create mode 100644 doc/guides/nics/features/failsafe.ini
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
Signature · 1 line
2.1.4
#21 lore raw
Quoted 5 lines · Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

Quoted 7 lines

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Why not just add this feature to the bonding pmd then? A bond is perfectly capable of handling the trivial case of a single underlying device, and adding an option to make the underly slave 'persistent' seem both much simpler in terms of implementation and code size, than adding an entire new pmd, along with its supporting code.

Neil

#22 lore raw
Quoted 13 lines · Neil Horman
Quoted 5 lines · Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

Quoted 7 lines

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Quoted 8 lines

Why not just add this feature to the bonding pmd then? A bond is perfectly capable of handling the trivial case of a single underlying device, and adding an option to make the underly slave 'persistent' seem both much simpler in terms of implementation and code size, than adding an entire new pmd, along with its supporting code.

Neil

+1
I don't like the idea of having multiple PMDs in DPDK to handle combining multiple other devices into one.

/Bruce

#23 lore raw
Quoted 14 lines · Bruce Richardson
Quoted 13 lines · Neil Horman
Quoted 12 lines · Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Quoted 8 lines
Quoted 8 lines

Why not just add this feature to the bonding pmd then? A bond is perfectly capable of handling the trivial case of a single underlying device, and adding an option to make the underly slave 'persistent' seem both much simpler in terms of implementation and code size, than adding an entire new pmd, along with its supporting code.

Neil

@Neil
I don't know if you saw my answer to Bruce on the matter [1], it partially adresses your point.

Quoted 5 lines

+1
I don't like the idea of having multiple PMDs in DPDK to handle combining multiple other devices into one.

/Bruce

I understand the concern. Let's first put aside for the moment the link grouping, which is only part of the fail-safe PMD function.

The fail-safe PMD at its core, provides an alternative paradigm, a new proposal for a hot-plug functionality in a lightweight form-factor from a user standpoint.

The central question that I would like to tackle is this: why should we require from our users declaring a bonding device to have hot-plug support?

I took some time to illustrate a few modes of operation:

Fig. 1

.-------------.
| application |
`------.------'
|
.----'-----.---------. <------ init, conf, Rx/Tx
| | |
| .---|--.------|--. <--- conf, link check, Rx/Tx
| | | | | |
v | v v v v

.---------. | .-------. .------.
| bonding | | | ixgbe | | mlx4 |
`----.----' | `-------' `------'
     |      |
     `------'

Typical link fail-over.

Fig. 2

.-------------.
| application |
`------.------'

        | <-------- init, conf, Rx/Tx
        v
  .-----------.
  | fail-safe |
  `-----.-----'
        |
    .---'----. <--- init, conf, dev check, Rx/Tx
    |        |
    v        v

.-------. .------.
| ixgbe | | mlx4 |
-------' ------'

Typical automatic hot-plug handling with device fail-over.

Fig. 3

.-------------.
| application |
`------.------'
|
.----'-----.-------------. <---------- init, conf, Rx/Tx
| | |
| .---|--.----------|--. <------- conf, link check, Rx/Tx
| | | | | |
v | v v v v

.---------. | .-----------. .-----------.
| bonding | | | fail-safe | | fail-safe |
`----.----' | `-----.-----' `-----.-----'
     |      |       |             | <------ init, conf, dev check, Rx/Tx
     `------'       v             v
                .-------.      .------.
                | ixgbe |      | mlx4 |
                `-------'      `------'

Combination to provide link fail-over with automatic hot-plug handling.

Fig. 4

.-------------.
| application |
`------.------'
|
.----'-----.-------------. <---------- init, conf, Rx/Tx
| | |
| .---|--.----------|--. <------- conf, link check, Rx/Tx
| | | | | |
v | v v v v

.---------. | .-----------. .-----------.
| bonding | | | fail-safe | | fail-safe |
`----.----' | `-----.-----' `-----.-----'
     |      |       |             | <------- init, conf, dev check, Rx/Tx
     `------'       |             |
             .------'---.     .---'------.
             |          |     |          |
             v          v     v          v
      .--------. .--------. .--------. .--------.
      | mlx4 1 | | mlx4 2 | | mlx4 1 | | mlx4 2 |
      | port 1 | | port 1 | | port 2 | | port 2 |
      `--------' `--------' `--------' `--------'

Complex use case with link fail-over at port level and automatic hot-plug handling with device fail-over.

1. LSC vs. RMV

A link status change is a valid state for a device. It calls for specific responses, e.g. a link switch in a bonding device, without losing the general configuration of the port.

The removal of a device calls for more than pausing operations and switching an active device. The party responsible for initializing the device should take care of closing it properly. If this party also wants to be able to restore the device if it was plugged back in, it would need be able to initialize it back and reconfigure its previous state.

As we can see that in [Fig. 1], this responsibility lies upon the application.

2. Bonding and link availability

The hot-plug functionality is not a core function of the bonding PMD. It is only interested in knowing if the link is active or not.

Adding the device persistence to the bonding PMD would mean adding the ability to flexibly parse device definitions to cope with plug-ins in evolving busses (PCI hot-plug could mean changing bus addresses), being able to emulate the EAL and the ether layer and to properly store the device configuration. This means formally describing the life of a device in a DPDK application from start to finish.

All of this hot-plug support, in order for the bonding to be aware of the status of some of its links. This seems like scope-creep.

3. Fail-safe and hot-plug support

An attach / detach (pseudo-hotplug) API exists in DPDK. The main problem of this API is that it does not offer reacting to a device plug-out, only triggering a device detaching from an application. This is a completely different approach from an application standpoint.

The fail-safe PMD offers an out-of-the-box implementation of a newly proposed hot-plug API [2]. It allows a seamless integration to users for device removal support in their applications, without requiring evolutions [Fig. 2]. This flexibility allows it to be used as part of a bond [Fig. 3], [Fig. 4], while current bonding does not allow for detaching devices, even if it were to be considered hot-plug. There is no reason however to require declaring a bonding device to be able to use it, from a user perspective this seems backward.

Both bonding and fail-safe PMDs deal with enslaving devices and acting upon their state changing. The bonding function performs at link level, while the hot-plug function deals with the device itself. I do not think this similarity justify merging both functions. Maintenance would be easier with clear, simpler functions implemented in separate PMDs.

[1]: http://dpdk.org/ml/archives/dev/2017-March/059446.html
[2]: http://dpdk.org/ml/archives/dev/2017-March/059217.html

Signature · 2 lines
Gaëtan Rivet
6WIND
#24 lore raw
Quoted 21 lines · Gaëtan Rivet
Quoted 20 lines · Bruce Richardson
Quoted 19 lines · Neil Horman
Quoted 5 lines · Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

Quoted 7 lines

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Why not just add this feature to the bonding pmd then? A bond is perfectly capable of handling the trivial case of a single underlying device, and adding an option to make the underly slave 'persistent' seem both much simpler in terms of implementation and code size, than adding an entire new pmd, along with its supporting code.

Quoted 7 lines
Quoted 2 lines
Quoted 2 lines

Neil

@Neil
I don't know if you saw my answer to Bruce on the matter [1], it partially adresses your point.

I did, and I think it asserts your points, but doesn't really address mine. See below.

Quoted 4 lines
Quoted 4 lines

+1
I don't like the idea of having multiple PMDs in DPDK to handle combining multiple other devices into one.

Quoted 9 lines
Quoted 1 line

/Bruce

I understand the concern. Let's first put aside for the moment the link grouping, which is only part of the fail-safe PMD function.

The fail-safe PMD at its core, provides an alternative paradigm, a new proposal for a hot-plug functionality in a lightweight form-factor from a user standpoint.

Ok, but lets be clear here, you're duplicating alot of functionality. And for that privlidge, there will be an additional 4000 lines of code to maintain.

Quoted 3 lines

The central question that I would like to tackle is this: why should we require from our users declaring a bonding device to have hot-plug support?

We'll, strictly speaking, I suppose we don't have to require it. But by that same token, we don't need to do it in a separate PMD either, there are lots of other options.

Quoted 90 lines

I took some time to illustrate a few modes of operation:

Fig. 1

   .-------------.
   | application |
   `------.------'
          |
     .----'-----.---------. <------ init, conf, Rx/Tx
     |          |         |
     |      .---|--.------|--. <--- conf, link check, Rx/Tx
     |      |   |  |      |  |
     v      |   v  v      v  v
.---------. | .-------. .------.
| bonding | | | ixgbe | | mlx4 |
`----.----' | `-------' `------'
     |      |
     `------'

Typical link fail-over.

Fig. 2

.-------------.
| application |
`------.------'

        | <-------- init, conf, Rx/Tx
        v
  .-----------.
  | fail-safe |
  `-----.-----'
        |
    .---'----. <--- init, conf, dev check, Rx/Tx
    |        |
    v        v

.-------. .------.
| ixgbe | | mlx4 |
-------' ------'

Typical automatic hot-plug handling with device fail-over.

Fig. 3

   .-------------.
   | application |
   `------.------'
          |
     .----'-----.-------------. <---------- init, conf, Rx/Tx
     |          |             |
     |      .---|--.----------|--. <------- conf, link check, Rx/Tx
     |      |   |  |          |  |
     v      |   v  v          v  v
.---------. | .-----------. .-----------.
| bonding | | | fail-safe | | fail-safe |
`----.----' | `-----.-----' `-----.-----'
     |      |       |             | <------ init, conf, dev check, Rx/Tx
     `------'       v             v
                .-------.      .------.
                | ixgbe |      | mlx4 |
                `-------'      `------'

Combination to provide link fail-over with automatic hot-plug handling.

Fig. 4

   .-------------.
   | application |
   `------.------'
          |
     .----'-----.-------------. <---------- init, conf, Rx/Tx
     |          |             |
     |      .---|--.----------|--. <------- conf, link check, Rx/Tx
     |      |   |  |          |  |
     v      |   v  v          v  v
.---------. | .-----------. .-----------.
| bonding | | | fail-safe | | fail-safe |
`----.----' | `-----.-----' `-----.-----'
     |      |       |             | <------- init, conf, dev check, Rx/Tx
     `------'       |             |
             .------'---.     .---'------.
             |          |     |          |
             v          v     v          v
      .--------. .--------. .--------. .--------.
      | mlx4 1 | | mlx4 2 | | mlx4 1 | | mlx4 2 |
      | port 1 | | port 1 | | port 2 | | port 2 |
      `--------' `--------' `--------' `--------'
Quoted 2 lines

Complex use case with link fail-over at port level and automatic hot-plug handling with device fail-over.

Yes, I think we all understand the purpose of your PMD - its there to provide a placeholder device that can respond to application requests in a sane manner, until such time as real hardware is put in its place via a hot plug/failure. Thats all well and good, I'm saying there are better ways to go about this that can provide the same functionality without having to add an extra 4k lines of code to the project, many of which already exist.

Quoted 13 lines

1. LSC vs. RMV

A link status change is a valid state for a device. It calls for specific responses, e.g. a link switch in a bonding device, without losing the general configuration of the port.

The removal of a device calls for more than pausing operations and switching an active device. The party responsible for initializing the device should take care of closing it properly. If this party also wants to be able to restore the device if it was plugged back in, it would need be able to initialize it back and reconfigure its previous state.

Quoted 3 lines

As we can see that in [Fig. 1], this responsibility lies upon the application.

Again, yes, I think we all see the benefit of centralizing hot plug operations, no one is disagreing with that, its the code/functional duplication that is concerning.

Quoted 5 lines

2. Bonding and link availability

The hot-plug functionality is not a core function of the bonding PMD. It is only interested in knowing if the link is active or not.

Currently, yes. The suggestion was that you augment the bonding driver so that hot plug is a core function of bonding.

Quoted 7 lines

Adding the device persistence to the bonding PMD would mean adding the ability to flexibly parse device definitions to cope with plug-ins in evolving busses (PCI hot-plug could mean changing bus addresses), being able to emulate the EAL and the ether layer and to properly store the device configuration. This means formally describing the life of a device in a DPDK application from start to finish.

Which seems to me to be exactly what your PMD does. I don't see why its fundamentally harder to do that in an existing pmd, than it is in a new one.

Quoted 3 lines

All of this hot-plug support, in order for the bonding to be aware of the status of some of its links. This seems like scope-creep.

But one of your primary use cases is bonding. Its the nature of code to add features as time goes on.

Quoted 16 lines

3. Fail-safe and hot-plug support

An attach / detach (pseudo-hotplug) API exists in DPDK. The main problem
of this API is that it does not offer reacting to a device plug-out, only triggering a device detaching from an application. This is a completely different approach from an application standpoint.

The fail-safe PMD offers an out-of-the-box implementation of a newly proposed hot-plug API [2]. It allows a seamless integration to users for device removal support in their applications, without requiring evolutions [Fig. 2]. This flexibility allows it to be used as part of a bond [Fig. 3], [Fig. 4], while current bonding does not allow for detaching devices, even if it were to be considered hot-plug. There is no reason however to require declaring a bonding device to be able to use it, from a user perspective this seems backward.

Quoted 7 lines

Both bonding and fail-safe PMDs deal with enslaving devices and acting upon their state changing. The bonding function performs at link level, while the hot-plug function deals with the device itself. I do not think this similarity justify merging both functions. Maintenance would be easier with clear, simpler functions implemented in separate PMDs.

My suggestion to you would be to re-architect this in the following way:

1) Augment the null pmd to accept arbitrary parameters. Paremeters which are not explicitly recognized are stored. Create an api call via the ethdev api to retrieve said arguments.

2) Augment the bonding driver so that, upon configuration, null drivers can be added to the bond, and marked as replaceable in some fashion

3) Port your hotplug implementation into the bonding code (or make it a separate library, not sure which yet). On a hot plug event trigger, react by querying the replaceable interfaces to see if the hot plugged nic is meant to replace an existing one. If a match is found, detach the null pmd instance, and add the hot plugged interface.

The intent here is to provide you with the functionality that you have (which is a good feature), without having to support an entire new pmd that replicates a great deal of existing code an functionality.

Regards
Neil

Quoted 7 lines

[1]: http://dpdk.org/ml/archives/dev/2017-March/059446.html
[2]: http://dpdk.org/ml/archives/dev/2017-March/059217.html

Signature · 2 lines
Gaëtan Rivet
6WIND
#25 lore raw
Quoted 8 lines
Quoted 4 lines

The central question that I would like to tackle is this: why should we require from our users declaring a bonding device to have hot-plug support?

We'll, strictly speaking, I suppose we don't have to require it. But by that same token, we don't need to do it in a separate PMD either, there are lots of other options.

I think I used an ambiguous formulation here. To be sure that we understand each other, what I want to express is that it will certainly seem very strange for a user to declare a bond on a single device, first, and to be expected to do so if they wanted hot-plug support on that particular device.

The bonding here would only be used as a place-holder, which does not really make sense from the user point of view.

I think you understood that, and what I take from your response is that while agreeing you would like to do so differently. I just wanted to be clear.

Quoted 42 lines
Quoted 42 lines

I took some time to illustrate a few modes of operation:

Fig. 1

   .-------------.
   | application |
   `------.------'
          |
     .----'-----.---------. <------ init, conf, Rx/Tx
     |          |         |
     |      .---|--.------|--. <--- conf, link check, Rx/Tx
     |      |   |  |      |  |
     v      |   v  v      v  v
.---------. | .-------. .------.
| bonding | | | ixgbe | | mlx4 |
`----.----' | `-------' `------'
     |      |
     `------'

Typical link fail-over.

Fig. 2

.-------------.
| application |
`------.------'

        | <-------- init, conf, Rx/Tx
        v
  .-----------.
  | fail-safe |
  `-----.-----'
        |
    .---'----. <--- init, conf, dev check, Rx/Tx
    |        |
    v        v

.-------. .------.
| ixgbe | | mlx4 |
-------' ------'

Typical automatic hot-plug handling with device fail-over.

Quoted 9 lines
Quoted 1 line

[...]

Yes, I think we all understand the purpose of your PMD - its there to provide a placeholder device that can respond to application requests in a sane manner, until such time as real hardware is put in its place via a hot plug/failure. Thats all well and good, I'm saying there are better ways to go about this that can provide the same functionality without having to add an extra 4k lines of code to the project, many of which already exist.

Ah, yes, I didn't want to imply that the purpose of this PMD wasn't understood already by many. These figures are there to illustrate some use cases that some users could recognize, and serve as a support for the point made afterward.

The main thing that can be taken from these is the division along the link-level and device-level checking that is done. This explains most of my position. The nature of those checks imply different kind of code, most of which is thus actually not duplicated / would require pretty much the same amount of code to be implemented either as libraries or as part of the bonding PMD. This is the crux of my argument, which I expand upon below.

Quoted 13 lines
Quoted 13 lines

1. LSC vs. RMV

A link status change is a valid state for a device. It calls for specific responses, e.g. a link switch in a bonding device, without losing the general configuration of the port.

The removal of a device calls for more than pausing operations and switching an active device. The party responsible for initializing the device should take care of closing it properly. If this party also wants to be able to restore the device if it was plugged back in, it would need be able to initialize it back and reconfigure its previous state.

Quoted 7 lines
Quoted 3 lines

As we can see that in [Fig. 1], this responsibility lies upon the application.

Again, yes, I think we all see the benefit of centralizing hot plug operations, no one is disagreing with that, its the code/functional duplication that is concerning.

Certainly, I will try to explain why the code is not actually duplicated / why the functions are actually only superficially overlapping.

Quoted 15 lines
Quoted 5 lines

2. Bonding and link availability

The hot-plug functionality is not a core function of the bonding PMD. It is only interested in knowing if the link is active or not.

Currently, yes. The suggestion was that you augment the bonding driver so that hot plug is a core function of bonding.

Quoted 7 lines

Adding the device persistence to the bonding PMD would mean adding the ability to flexibly parse device definitions to cope with plug-ins in evolving busses (PCI hot-plug could mean changing bus addresses), being able to emulate the EAL and the ether layer and to properly store the device configuration. This means formally describing the life of a device in a DPDK application from start to finish.

Quoted 3 lines

Which seems to me to be exactly what your PMD does. I don't see why its fundamentally harder to do that in an existing pmd, than it is in a new one.

Indeed it does. I must emphasize the "formally describe the life of a device". The hot-plug functionality goes beyong the link-level check. The description of a device from a DPDK standpoint is complete in the fail-safe PMD. The state-machine must be able to describe the entire life of a device, from the devargs parsing to its start-up.

We cannot reuse the existing bonding PMD architecture for this. We would have to rewrite the bonding PMD from the ground up for the hot-plug function. Because it is actually a different approach to managing the slaves.

This is what I wanted to illustrate in [Fig. 1] and [Fig. 2]:

- In the bonding, the init and configuration steps are still the responsibility of the application and no one else. The bonding PMD captures the device, re-applies its configuration upon dev_configure() which is actually re-applying part of the configuration already present within the slave eth_dev (cf rte_eth_dev_config_restore).

- In the fail-safe, the init and configuration are both the responsibilities of the fail-safe PMD itself, not the application anymore. This handling of these responsibilities in lieu of the application is the whole point of the "deferred hot-plug" support, of proposing a simple implementation to the user.

This change in responsibilities is the bulk of the fail-safe code. It would have to be added as-is to the bonding. Verifying the correctness of the sync of the initialization phase (acceptable states of a device following several events registered by the fail-safe PMD) and the configuration items between the state the application believes it is in and the fail-safe knows it is in, is the bulk of the fail-safe code.

This function is not overlapping with that of the bonding. The reason I did not add this whole architecture to the bonding is that when I tried to do so, I found that I only had two possibilities:

- The current slave handling path is kept, and we only add a new one with additional functionalities: full init and conf handling with extended parsing capabilities.

- The current slave handling is scraped and replaced entirely by the new slave management. The old capturing of existing device is not done anymore.

The first solution is not acceptable, because we effectively end-up with a maintenance nightmare by having to validate two types of slaves with differing capabilities, differing initialization paths and differing configuration code. This is extremely awkward and architecturally unsound. This is essentially the same as having the exact code of the fail-safe as an aside in the bonding, maintening exactly the same breadth of code while having muddier interfaces and organization.

The second solution is not acceptable, because we are bending the whole existing bonding API to our whim. We could just as well simply rename the fail-safe PMD as bonding, add a few grouping capabilities and call it a day. This is not acceptable for users.

All of this, for hotplug support in the bonding PMD, while it actually makes sense to offer this function on its own. Again, this third path with a new PMD clarifies the functions for the users and for the reasons exposed, helps the maintenance of the code.

There is no code duplication, or very little, because the slave management done by the fail-safe is specific to the hot-plug function. We do not handle slaves in the same way, and this is entirely due to the difference in nature between a link-level check and a device-level check.

Quoted 7 lines

My suggestion to you would be to re-architect this in the following way:

1) Augment the null pmd to accept arbitrary parameters. Paremeters which are not explicitly recognized are stored. Create an api call via the ethdev api to retrieve said arguments.

Quoted 9 lines

2) Augment the bonding driver so that, upon configuration, null drivers can be added to the bond, and marked as replaceable in some fashion

3) Port your hotplug implementation into the bonding code (or make it a separate library, not sure which yet). On a hot plug event trigger, react by querying the replaceable interfaces to see if the hot plugged nic is meant to replace an existing one. If a match is found, detach the null pmd instance, and add the hot plugged interface.

Porting this feature either as part of the bonding PMD or as a library means having a good part of the fail-safe PMD added somewhere else. It does not reduce much code length.

It does however modify the proposed user interface: either as a library that an application would have to explicitly use, or part of the bonding PMD with the problems previously explained.

The library form has been considered before. We would have to propose both a library for hot-plug handling (initializing and uninitializing a device), and a library for handling configuration. Neither can be seamlessly integrated in existing applications. They will have to be called correctly, an API will have to be respected to add the hot-plug support.

Additionally, their implementation is not so simple in this form. The configuration store / restore for example will need a full dev_ops coverage in order to deal with each configuration items that can be used. We end up with a complete dev_ops layer that strongly resemble a PMD. It also requires a saving space that will need to be managed, either by an application or by a PMD calling it. Having this space somehow managed by the EAL leads to implementing a PMD.

The PMD form allows for a clean abstraction layer that can be interfaced both with an application on top and a driver underneath. We are able to respect both APIs and to be inserted without either being aware of it. It does not overcomplicate the code itself nor the architecture while the overhead of a PMD is a negligible part, which can be justified to offer the seamless integration feature.

Quoted 4 lines

The intent here is to provide you with the functionality that you have (which is a good feature), without having to support an entire new pmd that replicates a great deal of existing code an functionality.

We already considered using the bonding PMD as much as possible, having generic libraries otherwise for the new facilities that we want. It is not simpler or easier to maintain. It however impedes users in adopting the feature.

Regards,

Signature · 2 lines
Gaëtan Rivet
6WIND
#26 lore raw
Quoted 182 lines · Gaëtan Rivet
Quoted 8 lines
Quoted 4 lines

The central question that I would like to tackle is this: why should we require from our users declaring a bonding device to have hot-plug support?

We'll, strictly speaking, I suppose we don't have to require it. But by that same token, we don't need to do it in a separate PMD either, there are lots of other options.

I think I used an ambiguous formulation here. To be sure that we understand each other, what I want to express is that it will certainly seem very strange for a user to declare a bond on a single device, first, and to be expected to do so if they wanted hot-plug support on that particular device.

The bonding here would only be used as a place-holder, which does not really make sense from the user point of view.

I think you understood that, and what I take from your response is that while agreeing you would like to do so differently. I just wanted to be clear.

Quoted 42 lines
Quoted 42 lines

I took some time to illustrate a few modes of operation:

Fig. 1

   .-------------.
   | application |
   `------.------'
          |
     .----'-----.---------. <------ init, conf, Rx/Tx
     |          |         |
     |      .---|--.------|--. <--- conf, link check, Rx/Tx
     |      |   |  |      |  |
     v      |   v  v      v  v
.---------. | .-------. .------.
| bonding | | | ixgbe | | mlx4 |
`----.----' | `-------' `------'
     |      |
     `------'

Typical link fail-over.

Fig. 2

.-------------.
| application |
`------.------'

        | <-------- init, conf, Rx/Tx
        v
  .-----------.
  | fail-safe |
  `-----.-----'
        |
    .---'----. <--- init, conf, dev check, Rx/Tx
    |        |
    v        v

.-------. .------.
| ixgbe | | mlx4 |
-------' ------'

Typical automatic hot-plug handling with device fail-over.

Quoted 9 lines
Quoted 1 line

[...]

Yes, I think we all understand the purpose of your PMD - its there to provide a placeholder device that can respond to application requests in a sane manner, until such time as real hardware is put in its place via a hot plug/failure. Thats all well and good, I'm saying there are better ways to go about this that can provide the same functionality without having to add an extra 4k lines of code to the project, many of which already exist.

Ah, yes, I didn't want to imply that the purpose of this PMD wasn't understood already by many. These figures are there to illustrate some use cases that some users could recognize, and serve as a support for the point made afterward.

The main thing that can be taken from these is the division along the link-level and device-level checking that is done. This explains most of my position. The nature of those checks imply different kind of code, most of which is thus actually not duplicated / would require pretty much the same amount of code to be implemented either as libraries or as part of the bonding PMD. This is the crux of my argument, which I expand upon below.

Quoted 13 lines
Quoted 13 lines

1. LSC vs. RMV

A link status change is a valid state for a device. It calls for specific responses, e.g. a link switch in a bonding device, without losing the general configuration of the port.

The removal of a device calls for more than pausing operations and switching an active device. The party responsible for initializing the device should take care of closing it properly. If this party also wants to be able to restore the device if it was plugged back in, it would need be able to initialize it back and reconfigure its previous state.

Quoted 7 lines
Quoted 3 lines

As we can see that in [Fig. 1], this responsibility lies upon the application.

Again, yes, I think we all see the benefit of centralizing hot plug operations, no one is disagreing with that, its the code/functional duplication that is concerning.

Certainly, I will try to explain why the code is not actually duplicated / why the functions are actually only superficially overlapping.

Quoted 15 lines
Quoted 5 lines

2. Bonding and link availability

The hot-plug functionality is not a core function of the bonding PMD. It is only interested in knowing if the link is active or not.

Currently, yes. The suggestion was that you augment the bonding driver so that hot plug is a core function of bonding.

Quoted 7 lines

Adding the device persistence to the bonding PMD would mean adding the ability to flexibly parse device definitions to cope with plug-ins in evolving busses (PCI hot-plug could mean changing bus addresses), being able to emulate the EAL and the ether layer and to properly store the device configuration. This means formally describing the life of a device in a DPDK application from start to finish.

Quoted 3 lines

Which seems to me to be exactly what your PMD does. I don't see why its fundamentally harder to do that in an existing pmd, than it is in a new one.

Indeed it does. I must emphasize the "formally describe the life of a device". The hot-plug functionality goes beyong the link-level check. The description of a device from a DPDK standpoint is complete in the fail-safe PMD. The state-machine must be able to describe the entire life of a device, from the devargs parsing to its start-up.

We cannot reuse the existing bonding PMD architecture for this. We would have to rewrite the bonding PMD from the ground up for the hot-plug function. Because it is actually a different approach to managing the slaves.

This is what I wanted to illustrate in [Fig. 1] and [Fig. 2]:

- In the bonding, the init and configuration steps are still the responsibility of the application and no one else. The bonding PMD captures the device, re-applies its configuration upon dev_configure() which is actually re-applying part of the configuration already present
within the slave eth_dev (cf rte_eth_dev_config_restore).

- In the fail-safe, the init and configuration are both the responsibilities of the fail-safe PMD itself, not the application anymore. This handling of these responsibilities in lieu of the application is the whole point of the "deferred hot-plug" support, of proposing a simple implementation to the user.

This change in responsibilities is the bulk of the fail-safe code. It would have to be added as-is to the bonding. Verifying the correctness of the sync of the initialization phase (acceptable states of a device following several events registered by the fail-safe PMD) and the configuration items between the state the application believes it is in and the fail-safe knows it is in, is the bulk of the fail-safe code.

This function is not overlapping with that of the bonding. The reason I did not add this whole architecture to the bonding is that when I tried to do so, I found that I only had two possibilities:

- The current slave handling path is kept, and we only add a new one with additional functionalities: full init and conf handling with extended parsing capabilities.

- The current slave handling is scraped and replaced entirely by the new slave management. The old capturing of existing device is not done anymore.

The first solution is not acceptable, because we effectively end-up with a maintenance nightmare by having to validate two types of slaves with differing capabilities, differing initialization paths and differing configuration code. This is extremely awkward and architecturally unsound. This is essentially the same as having the exact code of the fail-safe as an aside in the bonding, maintening exactly the same breadth of code while having muddier interfaces and organization.

Quoted 5 lines

The second solution is not acceptable, because we are bending the whole existing bonding API to our whim. We could just as well simply rename the fail-safe PMD as bonding, add a few grouping capabilities and call it a day. This is not acceptable for users.

If the first solution is indeed not an option, why do you think this second one would be unacceptable for users? If the functionality remains the same, I don't see how it matters much for users which driver provides it or where the code originates.

Despite all the discussion, it still just doesn't make sense to me to have more than one DPDK driver to handle failover - be it link or device. If nothing else, it's going to be awkward to explain to users that if they want fail-over for when a link goes down they have to use driver A, but if they want fail-over when a NIC gets hotplugged they use driver B, and if they want both kinds of failover - which would surely be the expected case - they need to use both drivers. The usability is a problem here.

Regards,
/Bruce

#27 lore raw

2017-03-15 03:28, Bruce Richardson:

Quoted 82 lines · Gaëtan Rivet
Quoted 71 lines
Quoted 15 lines
Quoted 5 lines

2. Bonding and link availability

The hot-plug functionality is not a core function of the bonding PMD. It is only interested in knowing if the link is active or not.

Currently, yes. The suggestion was that you augment the bonding driver so that hot plug is a core function of bonding.

Quoted 7 lines

Adding the device persistence to the bonding PMD would mean adding the ability to flexibly parse device definitions to cope with plug-ins in evolving busses (PCI hot-plug could mean changing bus addresses), being able to emulate the EAL and the ether layer and to properly store the device configuration. This means formally describing the life of a device in a DPDK application from start to finish.

Quoted 3 lines

Which seems to me to be exactly what your PMD does. I don't see why its fundamentally harder to do that in an existing pmd, than it is in a new one.

Indeed it does. I must emphasize the "formally describe the life of a device". The hot-plug functionality goes beyong the link-level check. The description of a device from a DPDK standpoint is complete in the fail-safe PMD. The state-machine must be able to describe the entire life of a device, from the devargs parsing to its start-up.

We cannot reuse the existing bonding PMD architecture for this. We would have to rewrite the bonding PMD from the ground up for the hot-plug function. Because it is actually a different approach to managing the slaves.

This is what I wanted to illustrate in [Fig. 1] and [Fig. 2]:

- In the bonding, the init and configuration steps are still the responsibility of the application and no one else. The bonding PMD captures the device, re-applies its configuration upon dev_configure() which is actually re-applying part of the configuration already present
within the slave eth_dev (cf rte_eth_dev_config_restore).

- In the fail-safe, the init and configuration are both the responsibilities of the fail-safe PMD itself, not the application anymore. This handling of these responsibilities in lieu of the application is the whole point of the "deferred hot-plug" support, of proposing a simple implementation to the user.

This change in responsibilities is the bulk of the fail-safe code. It would have to be added as-is to the bonding. Verifying the correctness of the sync of the initialization phase (acceptable states of a device following several events registered by the fail-safe PMD) and the configuration items between the state the application believes it is in and the fail-safe knows it is in, is the bulk of the fail-safe code.

This function is not overlapping with that of the bonding. The reason I did not add this whole architecture to the bonding is that when I tried to do so, I found that I only had two possibilities:

- The current slave handling path is kept, and we only add a new one with additional functionalities: full init and conf handling with extended parsing capabilities.

- The current slave handling is scraped and replaced entirely by the new slave management. The old capturing of existing device is not done anymore.

The first solution is not acceptable, because we effectively end-up with a maintenance nightmare by having to validate two types of slaves with differing capabilities, differing initialization paths and differing configuration code. This is extremely awkward and architecturally unsound. This is essentially the same as having the exact code of the fail-safe as an aside in the bonding, maintening exactly the same breadth of code while having muddier interfaces and organization.

Quoted 5 lines

The second solution is not acceptable, because we are bending the whole existing bonding API to our whim. We could just as well simply rename the fail-safe PMD as bonding, add a few grouping capabilities and call it a day. This is not acceptable for users.

If the first solution is indeed not an option, why do you think this second one would be unacceptable for users? If the functionality remains the same, I don't see how it matters much for users which driver provides it or where the code originates.

Quoted 8 lines

Despite all the discussion, it still just doesn't make sense to me to have more than one DPDK driver to handle failover - be it link or device. If nothing else, it's going to be awkward to explain to users that if they want fail-over for when a link goes down they have to use driver A, but if they want fail-over when a NIC gets hotplugged they use driver B, and if they want both kinds of failover - which would surely be the expected case - they need to use both drivers. The usability is a problem here.

It seems everybody agrees on the need for the failsafe code. We are just discussing the right place to implement it.

Gaetan, moving this code in the bonding PMD means replacing the bonding API design by the failsafe design, right?
With the failsafe design in the bonding PMD, is it possible to keep other bonding features?

In case we do not have a consensus in the following days, I suggest to add this topic in the next techboard meeting agenda.

#28 lore raw
Quoted 51 lines · Thomas Monjalon

2017-03-15 03:28, Bruce Richardson:

Quoted 50 lines · Gaëtan Rivet
Quoted 39 lines

- In the bonding, the init and configuration steps are still the responsibility of the application and no one else. The bonding PMD captures the device, re-applies its configuration upon dev_configure() which is actually re-applying part of the configuration already present
within the slave eth_dev (cf rte_eth_dev_config_restore).

- In the fail-safe, the init and configuration are both the responsibilities of the fail-safe PMD itself, not the application anymore. This handling of these responsibilities in lieu of the application is the whole point of the "deferred hot-plug" support, of proposing a simple implementation to the user.

This change in responsibilities is the bulk of the fail-safe code. It would have to be added as-is to the bonding. Verifying the correctness of the sync of the initialization phase (acceptable states of a device following several events registered by the fail-safe PMD) and the configuration items between the state the application believes it is in and the fail-safe knows it is in, is the bulk of the fail-safe code.

This function is not overlapping with that of the bonding. The reason I did not add this whole architecture to the bonding is that when I tried to do so, I found that I only had two possibilities:

- The current slave handling path is kept, and we only add a new one with additional functionalities: full init and conf handling with extended parsing capabilities.

- The current slave handling is scraped and replaced entirely by the new slave management. The old capturing of existing device is not done anymore.

The first solution is not acceptable, because we effectively end-up with a maintenance nightmare by having to validate two types of slaves with differing capabilities, differing initialization paths and differing configuration code. This is extremely awkward and architecturally unsound. This is essentially the same as having the exact code of the fail-safe as an aside in the bonding, maintening exactly the same breadth of code while having muddier interfaces and organization.

Quoted 5 lines

The second solution is not acceptable, because we are bending the whole existing bonding API to our whim. We could just as well simply rename the fail-safe PMD as bonding, add a few grouping capabilities and call it a day. This is not acceptable for users.

If the first solution is indeed not an option, why do you think this second one would be unacceptable for users? If the functionality remains the same, I don't see how it matters much for users which driver provides it or where the code originates.

The problem with the second solution is also that bonding is not only a PMD. It exposes its own public API that existing applications rely on, see rte_eth_bond_*() definitions in rte_eth_bond.h.

Although bonding instances can be set up through command-line options, target "users" are mainly applications explicitly written to use it. This must be preserved for no other reason that it hasn't been deprecated.

Also, trying to implement this API for the device failover function would implies a device capture down to the devargs parsing level. This means that a PMD could request taking over a device, messing with the internals of the EAL: devargs list and busses lists of devices. This seems unacceptable.

The bonding API is thus in conflict with the concept of a device failover in the context of the current DPDK arch.

Quoted 8 lines
Quoted 8 lines

Despite all the discussion, it still just doesn't make sense to me to have more than one DPDK driver to handle failover - be it link or device. If nothing else, it's going to be awkward to explain to users that if they want fail-over for when a link goes down they have to use driver A, but if they want fail-over when a NIC gets hotplugged they use driver B, and if they want both kinds of failover - which would surely be the expected case - they need to use both drivers. The usability is a problem here.

Having both kind of failovers in the same PMD will always lead to the first solution in some form or another.

I am sure we can document all this in a way that does no cause users confusion, with the help of community feedback such as yours.

Perhaps "net_failsafe" is a misnomer? We also thought about "net_persistent" or "net_hotplug". Any other ideas?

It is also possible for me to remove the failover support from this series, only providing deferred hot-plug handling at first. I could then send the failover support as separate patches to better assert that it is a useful, secondary feature that is essentially free to implement.

Quoted 8 lines

It seems everybody agrees on the need for the failsafe code. We are just discussing the right place to implement it.

Gaetan, moving this code in the bonding PMD means replacing the bonding API design by the failsafe design, right?
With the failsafe design in the bonding PMD, is it possible to keep other bonding features?

As seen previously, the bonding API is incompatible with device failover.

Having some features enabled solely for one kind of failover, while having specific code paths for both, seems unecessarily complicated to me ; following suite with my previous points about the first solution.

Quoted 3 lines

In case we do not have a consensus in the following days, I suggest to add this topic in the next techboard meeting agenda.

Regards,

Signature · 2 lines
Gaëtan Rivet
6WIND
#29 lore raw
Quoted 53 lines · Gaëtan Rivet
Quoted 51 lines · Thomas Monjalon

2017-03-15 03:28, Bruce Richardson:

Quoted 50 lines · Gaëtan Rivet
Quoted 39 lines

- In the bonding, the init and configuration steps are still the responsibility of the application and no one else. The bonding PMD captures the device, re-applies its configuration upon dev_configure() which is actually re-applying part of the configuration already present
within the slave eth_dev (cf rte_eth_dev_config_restore).

- In the fail-safe, the init and configuration are both the responsibilities of the fail-safe PMD itself, not the application anymore. This handling of these responsibilities in lieu of the application is the whole point of the "deferred hot-plug" support, of proposing a simple implementation to the user.

This change in responsibilities is the bulk of the fail-safe code. It would have to be added as-is to the bonding. Verifying the correctness of the sync of the initialization phase (acceptable states of a device following several events registered by the fail-safe PMD) and the configuration items between the state the application believes it is in and the fail-safe knows it is in, is the bulk of the fail-safe code.

This function is not overlapping with that of the bonding. The reason I did not add this whole architecture to the bonding is that when I tried to do so, I found that I only had two possibilities:

- The current slave handling path is kept, and we only add a new one with additional functionalities: full init and conf handling with extended parsing capabilities.

- The current slave handling is scraped and replaced entirely by the new slave management. The old capturing of existing device is not done anymore.

The first solution is not acceptable, because we effectively end-up with a maintenance nightmare by having to validate two types of slaves with differing capabilities, differing initialization paths and differing configuration code. This is extremely awkward and architecturally unsound. This is essentially the same as having the exact code of the fail-safe as an aside in the bonding, maintening exactly the same breadth of code while having muddier interfaces and organization.

Quoted 5 lines

The second solution is not acceptable, because we are bending the whole existing bonding API to our whim. We could just as well simply rename the fail-safe PMD as bonding, add a few grouping capabilities and call it a day. This is not acceptable for users.

If the first solution is indeed not an option, why do you think this second one would be unacceptable for users? If the functionality remains the same, I don't see how it matters much for users which driver provides it or where the code originates.

Quoted 8 lines

The problem with the second solution is also that bonding is not only a PMD. It exposes its own public API that existing applications rely on, see rte_eth_bond_*() definitions in rte_eth_bond.h.

Although bonding instances can be set up through command-line options, target "users" are mainly applications explicitly written to use it. This must be preserved for no other reason that it hasn't been deprecated.

I fail to see how either of your points are relevant. The fact that the bonding pmd exposes an api to the application has no bearing on its ability to implement a hot plug function.

Quoted 5 lines

Also, trying to implement this API for the device failover function would implies a device capture down to the devargs parsing level. This means that a PMD could request taking over a device, messing with the internals of the
EAL: devargs list and busses lists of devices. This seems unacceptable.

Why? You just said yourself above that, while there is a devargs interface to the bonding driver, there is also an api, which is the more used method to configure bonding. I'm not sure I agree with that, but I think its beside the point. Your PMD also requires configuration, and it appears necessecary that you do so from the command line (you need to specifically ennumerate the subdevices that you intend to provide failsafe behavior to). I see no reason why such a feature cant' be added to bonding, and the null pmd used as a standin device, should the ennumerated device not yet exist).

To your argument regarding about taking over a device, I don't see how you find that unacceptable, as it is precisely what the bonding driver does today, in the sense that it allows an application to assign a master/slave relationship to devices right now. I see no reason that we can't convey the right and ability for bonding to do that dynamically based on configuration.

Quoted 3 lines

The bonding API is thus in conflict with the concept of a device failover in the context of the current DPDK arch.

I really don't see how you get to this from your argument above.

Quoted 9 lines
Quoted 8 lines
Quoted 8 lines

Despite all the discussion, it still just doesn't make sense to me to have more than one DPDK driver to handle failover - be it link or device. If nothing else, it's going to be awkward to explain to users that if they want fail-over for when a link goes down they have to use driver A, but if they want fail-over when a NIC gets hotplugged they use driver B, and if they want both kinds of failover - which would surely be the expected case - they need to use both drivers. The usability is a problem here.

Quoted 3 lines

Having both kind of failovers in the same PMD will always lead to the first solution in some form or another.

It really isn't because you can model hotplug behavior as a trival form of the failover that bonding does now (i.e. failover between a null device and a preferred real device).

Quoted 11 lines

I am sure we can document all this in a way that does no cause users confusion, with the help of community feedback such as yours.

Perhaps "net_failsafe" is a misnomer? We also thought about "net_persistent" or "net_hotplug". Any other ideas?

It is also possible for me to remove the failover support from this series, only providing deferred hot-plug handling at first. I could then send the failover support as separate patches to better assert that it is a useful, secondary feature that is essentially free to implement.

I think thats solving the wrong problem. I've no issue with the functionality in this patch, its really the implementation that we are all arguing against.

Quoted 11 lines
Quoted 8 lines

It seems everybody agrees on the need for the failsafe code. We are just discussing the right place to implement it.

Gaetan, moving this code in the bonding PMD means replacing the bonding API design by the failsafe design, right?
With the failsafe design in the bonding PMD, is it possible to keep other bonding features?

As seen previously, the bonding API is incompatible with device failover.

Its not been seen previously, you asserted it to be so, and I certainly disagree with that assertion. I think others might too.

Additionally, its not really in line with this discussion, but in looking at your hotplug detection code, I think somewhat lacking. Currently you seem to implement this with a timer that wakes up and checks for device existance, which is pretty substandard in my mind. Thats going to waste cpu cycles that might lead to packet loss. I'd really prefer to see you augment the eal library with an event handling code (it can tie into udev in linux and kqueue in bsd), and create a generic event hook, that we can use to detect device adds/removes without having to wake up constantly to see if anything has changed.

Quoted 13 lines

Having some features enabled solely for one kind of failover, while having specific code paths for both, seems unecessarily complicated to me ; following suite with my previous points about the first solution.

Quoted 3 lines

In case we do not have a consensus in the following days, I suggest to add this topic in the next techboard meeting agenda.

Regards,

Signature · 2 lines
Gaëtan Rivet
6WIND
#30 lore raw
Quoted 58 lines · Neil Horman
Quoted 57 lines · Gaëtan Rivet
Quoted 51 lines · Thomas Monjalon

2017-03-15 03:28, Bruce Richardson:

Quoted 50 lines · Gaëtan Rivet
Quoted 39 lines

- In the bonding, the init and configuration steps are still the responsibility of the application and no one else. The bonding PMD captures the device, re-applies its configuration upon dev_configure() which is actually re-applying part of the configuration already present
within the slave eth_dev (cf rte_eth_dev_config_restore).

- In the fail-safe, the init and configuration are both the responsibilities of the fail-safe PMD itself, not the application anymore. This handling of these responsibilities in lieu of the application is the whole point of the "deferred hot-plug" support, of proposing a simple implementation to the user.

This change in responsibilities is the bulk of the fail-safe code. It would have to be added as-is to the bonding. Verifying the correctness of the sync of the initialization phase (acceptable states of a device following several events registered by the fail-safe PMD) and the configuration items between the state the application believes it is in and the fail-safe knows it is in, is the bulk of the fail-safe code.

This function is not overlapping with that of the bonding. The reason I did not add this whole architecture to the bonding is that when I tried to do so, I found that I only had two possibilities:

- The current slave handling path is kept, and we only add a new one with additional functionalities: full init and conf handling with extended parsing capabilities.

- The current slave handling is scraped and replaced entirely by the new slave management. The old capturing of existing device is not done anymore.

The first solution is not acceptable, because we effectively end-up with a maintenance nightmare by having to validate two types of slaves with differing capabilities, differing initialization paths and differing configuration code. This is extremely awkward and architecturally unsound. This is essentially the same as having the exact code of the fail-safe as an aside in the bonding, maintening exactly the same breadth of code while having muddier interfaces and organization.

Quoted 5 lines

The second solution is not acceptable, because we are bending the whole existing bonding API to our whim. We could just as well simply rename the fail-safe PMD as bonding, add a few grouping capabilities and call it a day. This is not acceptable for users.

If the first solution is indeed not an option, why do you think this second one would be unacceptable for users? If the functionality remains the same, I don't see how it matters much for users which driver provides it or where the code originates.

The problem with the second solution is also that bonding is not only a PMD. It exposes its own public API that existing applications rely on, see rte_eth_bond_*() definitions in rte_eth_bond.h.

Quoted 8 lines
Quoted 4 lines

Although bonding instances can be set up through command-line options, target "users" are mainly applications explicitly written to use it. This must be preserved for no other reason that it hasn't been deprecated.

I fail to see how either of your points are relevant. The fact that the bonding pmd exposes an api to the application has no bearing on its ability to implement a hot plug function.

This depends on the API making sense in the context of the new functionality.

This API offers to add and remove slaves to a bonding and to configure them. In the fail-safe arch, it is not possible to add and remove slaves from the grouping. Doing so would mean adding and removing devices from internal EAL structures.

It is also invalid to try to configure a fail-safe slave. An application only configures a fail-safe device, which will in turn configure its slaves. This separation follows from the nature of a device failover.

As seen previously, the fail-safe PMD handles different responsibilities from the bonding PMD. It is thus necessary to make different assumptions concerning what it can and cannot do with a slave.

Quoted 14 lines
Quoted 5 lines

Also, trying to implement this API for the device failover function would implies a device capture down to the devargs parsing level. This means that a PMD could request taking over a device, messing with the internals of the
EAL: devargs list and busses lists of devices. This seems unacceptable.

Why? You just said yourself above that, while there is a devargs interface to the bonding driver, there is also an api, which is the more used method to configure bonding. I'm not sure I agree with that, but I think its beside the point. Your PMD also requires configuration, and it appears necessecary that you do so from the command line (you need to specifically ennumerate the subdevices that you intend to provide failsafe behavior to). I see no reason why such a feature cant' be added to bonding, and the null pmd used as a standin device, should the ennumerated device not yet exist).

Quoted 6 lines

To your argument regarding about taking over a device, I don't see how you find that unacceptable, as it is precisely what the bonding driver does today, in the sense that it allows an application to assign a master/slave relationship to devices right now. I see no reason that we can't convey the right and ability for bonding to do that dynamically based on configuration.

No, the bonding PMD does not take over a device. It only cares about the ether layer for its link failover. It does not care about parsing parameters of a slave, probing devices, detaching drivers. It does not remove a device from the pci_device_list in the EAL for example.

Doing so would imply exposing private internals structures from the EAL, messing with elements reserved while doing the EAL init. This requires controlling a priority in the device initialization order to create the over-arching ones last (which is a hacky solution). It would wreak havoc with the DPDK arch.

The fail-safe PMD does not rely on the EAL for handling its slaves. This is what I explained before, when I touched upon the differing responsibilities implied by the differences in nature between a link failover and a device failover.

Quoted 5 lines
Quoted 3 lines

The bonding API is thus in conflict with the concept of a device failover in the context of the current DPDK arch.

I really don't see how you get to this from your argument above.

The current DPDK arch does not expose EAL elements to be modified by PMDs, and with good reasons. In this context, it is not possible to handle slaves correctly for a device failover in the bonding PMD, because the bonding PMD from the get-go expects the EAL to handle its slaves on a device level.

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Quoted 8 lines

Despite all the discussion, it still just doesn't make sense to me to have more than one DPDK driver to handle failover - be it link or device. If nothing else, it's going to be awkward to explain to users that if they want fail-over for when a link goes down they have to use driver A, but if they want fail-over when a NIC gets hotplugged they use driver B, and if they want both kinds of failover - which would surely be the expected case - they need to use both drivers. The usability is a problem here.

Quoted 7 lines
Quoted 3 lines

Having both kind of failovers in the same PMD will always lead to the first solution in some form or another.

It really isn't because you can model hotplug behavior as a trival form of the failover that bonding does now (i.e. failover between a null device and a preferred real device).

The preferred real device still has to be created / destroyed. It still relies on EAL entry points for handling. It still puts additional responsibilities on a PMD. Those responsibilities are expressed in sub layers clearly defined in the fail-safe PMD. You would have to create these sub-layers in some form in the bonding for it to be able to create a preferred real device at some point. This additional way of handling slaves has already been discussed as inducing a messy architecture to the bonding PMD.

Quoted 23 lines
Quoted 11 lines

I am sure we can document all this in a way that does no cause users confusion, with the help of community feedback such as yours.

Perhaps "net_failsafe" is a misnomer? We also thought about "net_persistent" or "net_hotplug". Any other ideas?

It is also possible for me to remove the failover support from this series, only providing deferred hot-plug handling at first. I could then send the failover support as separate patches to better assert that it is a useful, secondary feature that is essentially free to implement.

I think thats solving the wrong problem. I've no issue with the functionality in this patch, its really the implementation that we are all arguing against.

Quoted 9 lines
Quoted 8 lines

It seems everybody agrees on the need for the failsafe code. We are just discussing the right place to implement it.

Gaetan, moving this code in the bonding PMD means replacing the bonding API design by the failsafe design, right?
With the failsafe design in the bonding PMD, is it possible to keep other bonding features?

Quoted 5 lines
Quoted 2 lines

As seen previously, the bonding API is incompatible with device failover.

Its not been seen previously, you asserted it to be so, and I certainly disagree with that assertion. I think others might too.

I also explained at length my assertion. I can certainly expand further if necessary, but you need to point the elements you disagree with.

Quoted 10 lines

Additionally, its not really in line with this discussion, but in looking at your hotplug detection code, I think somewhat lacking. Currently you seem to implement this with a timer that wakes up and checks for device existance, which is pretty substandard in my mind. Thats going to waste cpu cycles that might lead to packet loss. I'd really prefer to see you augment the eal library with an event handling code (it can tie into udev in linux and kqueue in bsd), and create a generic event hook, that we can use to detect device adds/removes without having to wake up constantly to see if anything has changed.

I think it's fine. We can discuss it further once we agree on the form the hot-plug implementation will take in the DPDK.

Quoted 7 lines
Quoted 7 lines

Having some features enabled solely for one kind of failover, while having specific code paths for both, seems unecessarily complicated to me ; following suite with my previous points about the first solution.

Quoted 3 lines

In case we do not have a consensus in the following days, I suggest to add this topic in the next techboard meeting agenda.

Best regards,

Signature · 2 lines
Gaëtan Rivet
6WIND
#31 lore raw
Quoted 63 lines · Gaëtan Rivet
Quoted 62 lines · Neil Horman
Quoted 61 lines · Gaëtan Rivet
Quoted 51 lines · Thomas Monjalon

2017-03-15 03:28, Bruce Richardson:

Quoted 50 lines · Gaëtan Rivet
Quoted 39 lines

- In the bonding, the init and configuration steps are still the responsibility of the application and no one else. The bonding PMD captures the device, re-applies its configuration upon dev_configure() which is actually re-applying part of the configuration already present
within the slave eth_dev (cf rte_eth_dev_config_restore).

- In the fail-safe, the init and configuration are both the responsibilities of the fail-safe PMD itself, not the application anymore. This handling of these responsibilities in lieu of the application is the whole point of the "deferred hot-plug" support, of proposing a simple implementation to the user.

This change in responsibilities is the bulk of the fail-safe code. It would have to be added as-is to the bonding. Verifying the correctness of the sync of the initialization phase (acceptable states of a device following several events registered by the fail-safe PMD) and the configuration items between the state the application believes it is in and the fail-safe knows it is in, is the bulk of the fail-safe code.

This function is not overlapping with that of the bonding. The reason I did not add this whole architecture to the bonding is that when I tried to do so, I found that I only had two possibilities:

- The current slave handling path is kept, and we only add a new one with additional functionalities: full init and conf handling with extended parsing capabilities.

- The current slave handling is scraped and replaced entirely by the new slave management. The old capturing of existing device is not done anymore.

The first solution is not acceptable, because we effectively end-up with a maintenance nightmare by having to validate two types of slaves with differing capabilities, differing initialization paths and differing configuration code. This is extremely awkward and architecturally unsound. This is essentially the same as having the exact code of the fail-safe as an aside in the bonding, maintening exactly the same breadth of code while having muddier interfaces and organization.

Quoted 5 lines

The second solution is not acceptable, because we are bending the whole existing bonding API to our whim. We could just as well simply rename the fail-safe PMD as bonding, add a few grouping capabilities and call it a day. This is not acceptable for users.

If the first solution is indeed not an option, why do you think this second one would be unacceptable for users? If the functionality remains the same, I don't see how it matters much for users which driver provides it or where the code originates.

The problem with the second solution is also that bonding is not only a PMD. It exposes its own public API that existing applications rely on, see rte_eth_bond_*() definitions in rte_eth_bond.h.

Although bonding instances can be set up through command-line options, target "users" are mainly applications explicitly written to use it. This must be preserved for no other reason that it hasn't been deprecated.

Quoted 8 lines
Quoted 4 lines

I fail to see how either of your points are relevant. The fact that the bonding pmd exposes an api to the application has no bearing on its ability to implement a hot plug function.

This depends on the API making sense in the context of the new functionality.

Well, the api should always make sense in the context of any added functionality, but it seems to me thats just another way of saying you might need to make some modifications to the bonding api. I'm not saying thats necessecarily going to have to be the case, but while I'm a big proponent of ABI stability, I would support an API change to add valid functionality if it were a big enough feature. Though again, I don't think thats really necessecary if you rethink the model a little bit

Quoted 5 lines

This API offers to add and remove slaves to a bonding and to configure them. In the fail-safe arch, it is not possible to add and remove slaves from the grouping. Doing so would mean adding and removing devices from internal EAL structures.

Ok, so you update the bonding option parser to include a fail-safe mode, which only supports two slaves, one of which is an instance of the null-pmd and the other is to be added at a later date in response to a hot plug event. In the fail safe mode, after initial option parsing, bonds operating in this mode return an error to the application when/if it attempts to remove a slave from a bond. That doesn't seem so hard to me.

Quoted 4 lines

It is also invalid to try to configure a fail-safe slave. An application only configures a fail-safe device, which will in turn configure its slaves. This separation follows from the nature of a device failover.

See my previous mail, you augment the null pmd to allow storage of aribtrary configuration strings or key/value pairs when operating as a bonded slave. The bond is then capable of retrieving configuration from that null instance and pushing it to the real slave on a hot plug event.

Quoted 4 lines

As seen previously, the fail-safe PMD handles different responsibilities from the bonding PMD. It is thus necessary to make different assumptions concerning what it can and cannot do with a slave.

Only because you seem to refuse to think about the failsafe model in any other way than the one you have implemented.

Quoted 21 lines
Quoted 14 lines
Quoted 5 lines

Also, trying to implement this API for the device failover function would implies a device capture down to the devargs parsing level. This means that a PMD could request taking over a device, messing with the internals of the
EAL: devargs list and busses lists of devices. This seems unacceptable.

Why? You just said yourself above that, while there is a devargs interface to the bonding driver, there is also an api, which is the more used method to configure bonding. I'm not sure I agree with that, but I think its beside the point. Your PMD also requires configuration, and it appears necessecary that you do so from the command line (you need to specifically ennumerate the subdevices that you intend to provide failsafe behavior to). I see no reason why such a feature cant' be added to bonding, and the null pmd used as a standin device, should the ennumerated device not yet exist).

Quoted 6 lines

To your argument regarding about taking over a device, I don't see how you find that unacceptable, as it is precisely what the bonding driver does today, in the sense that it allows an application to assign a master/slave relationship to devices right now. I see no reason that we can't convey the right and ability for bonding to do that dynamically based on configuration.

Quoted 5 lines

No, the bonding PMD does not take over a device. It only cares about the ether layer for its link failover. It does not care about parsing parameters of a slave, probing devices, detaching drivers. It does not remove a device from the pci_device_list in the EAL for example.

Again, please take a moment and think about how else your failsafe model might be implemented in the context of bonding. Right now, you are asserting that your failsafe model can't be implemented in any other way becausee of the decisions you have made. If you change how you think of failsafe, you'll see it can be done in other ways.

Quoted 92 lines

Doing so would imply exposing private internals structures from the EAL, messing with elements reserved while doing the EAL init. This requires controlling a priority in the device initialization order to create the over-arching ones last (which is a hacky solution). It would wreak havoc with the DPDK arch.

The fail-safe PMD does not rely on the EAL for handling its slaves. This is what I explained before, when I touched upon the differing responsibilities implied by the differences in nature between a link failover and a device failover.

Quoted 5 lines
Quoted 3 lines

The bonding API is thus in conflict with the concept of a device failover in the context of the current DPDK arch.

I really don't see how you get to this from your argument above.

The current DPDK arch does not expose EAL elements to be modified by PMDs, and with good reasons. In this context, it is not possible to handle slaves correctly for a device failover in the bonding PMD,
because the bonding PMD from the get-go expects the EAL to handle its slaves on a device level.

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Quoted 8 lines

Despite all the discussion, it still just doesn't make sense to me to have more than one DPDK driver to handle failover - be it link or device. If nothing else, it's going to be awkward to explain to users that if they want fail-over for when a link goes down they have to use driver A, but if they want fail-over when a NIC gets hotplugged they use driver B, and if they want both kinds of failover - which would surely be the expected case - they need to use both drivers. The usability is a problem here.

Quoted 7 lines
Quoted 3 lines

Having both kind of failovers in the same PMD will always lead to the first solution in some form or another.

It really isn't because you can model hotplug behavior as a trival form of the failover that bonding does now (i.e. failover between a null device and a preferred real device).

The preferred real device still has to be created / destroyed. It still relies on EAL entry points for handling. It still puts additional responsibilities on a PMD. Those responsibilities are expressed in sub layers clearly defined in the fail-safe PMD. You would have to create these sub-layers in some form in the bonding for it to be able to create a preferred real device at some point. This additional way of handling slaves has already been discussed as inducing a messy architecture to the bonding PMD.

Quoted 23 lines
Quoted 11 lines

I am sure we can document all this in a way that does no cause users confusion, with the help of community feedback such as yours.

Perhaps "net_failsafe" is a misnomer? We also thought about "net_persistent" or "net_hotplug". Any other ideas?

It is also possible for me to remove the failover support from this series, only providing deferred hot-plug handling at first. I could then send the failover support as separate patches to better assert that it is a useful, secondary feature that is essentially free to implement.

I think thats solving the wrong problem. I've no issue with the functionality in this patch, its really the implementation that we are all arguing against.

Quoted 9 lines
Quoted 8 lines

It seems everybody agrees on the need for the failsafe code. We are just discussing the right place to implement it.

Gaetan, moving this code in the bonding PMD means replacing the bonding API design by the failsafe design, right?
With the failsafe design in the bonding PMD, is it possible to keep other bonding features?

Quoted 5 lines
Quoted 2 lines

As seen previously, the bonding API is incompatible with device failover.

Its not been seen previously, you asserted it to be so, and I certainly disagree with that assertion. I think others might too.

I also explained at length my assertion. I can certainly expand further if necessary, but you need to point the elements you disagree with.

Quoted 10 lines

Additionally, its not really in line with this discussion, but in looking at your hotplug detection code, I think somewhat lacking. Currently you seem to implement this with a timer that wakes up and checks for device existance, which is pretty substandard in my mind. Thats going to waste cpu cycles that might lead to packet loss. I'd really prefer to see you augment the eal library with an event handling code (it can tie into udev in linux and kqueue in bsd), and create a generic event hook, that we can use to detect device adds/removes without having to wake up constantly to see if anything has changed.

Quoted 3 lines

I think it's fine. We can discuss it further once we agree on the form the hot-plug implementation will take in the DPDK.

Well, until then, I feel like we're talking past one another at this point, and so I'll just say this driver is a NAK for me.

Neil

Quoted 14 lines
Quoted 8 lines
Quoted 8 lines

Having some features enabled solely for one kind of failover, while having
specific code paths for both, seems unecessarily complicated to me ; following suite with my previous points about the first solution.

Quoted 3 lines

In case we do not have a consensus in the following days, I suggest to add this topic in the next techboard meeting agenda.

Best regards,

Signature · 2 lines
Gaëtan Rivet
6WIND
#32 lore raw
In reply to Gaetan Rivet

There have been some discussions on this new PMD and it will be discussed today in the techboard meeting.

I would like to expose my view and summarize the solutions I have heard. First it is important to remind that everyone agrees on the need for this feature, i.e. masking the hotplug events by maintaining an ethdev object even without real underlying device.

1/
The proposal from Gaetan is to add a failsafe driver with 2 features:
* masking underlying device
* limited and small failover code to switch from a device to another one, with the same centralized configuration
The latter feature makes think to the bonding driver, but it could be kept limited without any intent of implementing real bonding features.

2/
If we really want to merge failsafe and bonding features, we could create a new bonding driver with centralized configuration. The legacy bonding driver let each slave to be configured separately. It is a different model and we should not mix them.
If one is better, it could be deprecated later.

3/
It can be tried to implement the failsafe feature into the bonding driver, as Neil suggests.
However, I am not sure it would work very well or would be easy to use.

4/
We can implement only the failsafe feature as a PMD and use it to wrap the slaves of the bonding driver.
So the order of link would be

	bonding -> failsafe -> real device

In this model, failsafe can have only one slave and do not implement the fail-over feature.

#33 lore raw
Quoted 28 lines · Thomas Monjalon

There have been some discussions on this new PMD and it will be discussed today in the techboard meeting.

I would like to expose my view and summarize the solutions I have heard. First it is important to remind that everyone agrees on the need for this feature, i.e. masking the hotplug events by maintaining an ethdev object even without real underlying device.

1/
The proposal from Gaetan is to add a failsafe driver with 2 features:
* masking underlying device
* limited and small failover code to switch from a device to another one, with the same centralized configuration
The latter feature makes think to the bonding driver, but it could be kept limited without any intent of implementing real bonding features.

2/
If we really want to merge failsafe and bonding features, we could create a new bonding driver with centralized configuration. The legacy bonding driver let each slave to be configured separately. It is a different model and we should not mix them.
If one is better, it could be deprecated later.

3/
It can be tried to implement the failsafe feature into the bonding driver, as Neil suggests.
However, I am not sure it would work very well or would be easy to use.

Quoted 8 lines

4/
We can implement only the failsafe feature as a PMD and use it to wrap the slaves of the bonding driver.
So the order of link would be

	bonding -> failsafe -> real device

In this model, failsafe can have only one slave and do not implement the fail-over feature.

Tech board decided [1] to "reconsider" the PMD for this release (17.08). So, lets start it J

I think it is good idea to continue on top of above summary, is there a plan to how to proceed?

Thanks,
ferruh

[1]
http://dpdk.org/ml/archives/dev/2017-March/061009.html

#34 lore raw
Quoted 38 lines · Ferruh Yigit
Quoted 28 lines · Thomas Monjalon

There have been some discussions on this new PMD and it will be discussed today in the techboard meeting.

I would like to expose my view and summarize the solutions I have heard. First it is important to remind that everyone agrees on the need for this feature, i.e. masking the hotplug events by maintaining an ethdev object even without real underlying device.

1/
The proposal from Gaetan is to add a failsafe driver with 2 features:
* masking underlying device
* limited and small failover code to switch from a device to another one, with the same centralized configuration
The latter feature makes think to the bonding driver, but it could be kept limited without any intent of implementing real bonding features.

2/
If we really want to merge failsafe and bonding features, we could create a new bonding driver with centralized configuration. The legacy bonding driver let each slave to be configured separately. It is a different model and we should not mix them.
If one is better, it could be deprecated later.

3/
It can be tried to implement the failsafe feature into the bonding driver, as Neil suggests.
However, I am not sure it would work very well or would be easy to use.

Quoted 8 lines

4/
We can implement only the failsafe feature as a PMD and use it to wrap the slaves of the bonding driver.
So the order of link would be

	bonding -> failsafe -> real device

In this model, failsafe can have only one slave and do not implement the fail-over feature.

Quoted 6 lines

Tech board decided [1] to "reconsider" the PMD for this release (17.08). So, lets start it J

I think it is good idea to continue on top of above summary, is there a plan to how to proceed?

The fail-safe proposal has not evolved from the techboard point of view. The salient point is still choosing between those 4 possible integrations.

To give a quick overview of its current state:

I have started working on a v3 to be integrated to v17.08. The work however was exceedingly complicated due to deep-rooted dependencies in the PCI implementation within the EAL, which has evolved in v17.05 and will evolve during this release.

The current rte_bus rework from Jan Blunck and myself will greatly simplify the sub-EAL layer that was used in the fail-safe. I am thus waiting on Jan Blunck series on attach / detach, to propose mine in turn for rte_devargs, move the PCI bus where it belongs and, finally, rebase the fail-safe upon it.

The form this work is taking however is still the same as previously, thus currently aiming at solutions 1 or 2.

Quoted 5 lines

Thanks,
ferruh

[1]
http://dpdk.org/ml/archives/dev/2017-March/061009.html

Signature · 2 lines
Gaëtan Rivet
6WIND
#35 lore raw
In reply to Gaetan Rivet
Quoted 37 lines · Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This series depends on the series
[PATCH 0/4] clarify eth_dev state management
[PATCH 0/5] add device removal event

v1 --> v2:

- Wrote documentation
- Fixed commit logs, signed-off-by
- Added LSC event support
- A few minor fixes

Quoted 14 lines

Gaetan Rivet (13):
ethdev: save VLAN filter setting
ethdev: add flow API rule copy function
ethdev: add deferred intermediate device state
pci: expose device detach routine
pci: expose parse and probe routines
net/failsafe: add fail-safe PMD
net/failsafe: add plug-in support
net/failsafe: add flexible device definition
net/failsafe: support flow API
net/failsafe: support offload capabilities
net/failsafe: add fast burst functions
net/failsafe: support device removal
net/failsafe: support link status change event

Postponed to next release (17.08) based on tech board decision [1]

[1]
http://dpdk.org/ml/archives/dev/2017-March/061009.html

#36 lore raw

PATCH v2 1/13 ethdev: save VLAN filter setting

In reply to Gaetan Rivet

Other configuration items (i.e. MAC addresses) are stored within rte_eth_dev_data, but not this one.

---
 lib/librte_ether/rte_ethdev.c | 19 ++++++++++++++++++-
 lib/librte_ether/rte_ethdev.h | 10 ++++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)
lib/librte_ether/rte_ethdev.c +18 -1
index 6c4b796..61a63b7 100644
@@ -1764,6 +1764,7 @@ int
 rte_eth_dev_vlan_filter(uint8_t port_id, uint16_t vlan_id, int on)
 {
 	struct rte_eth_dev *dev;
+	int ret;
 
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 	dev = &rte_eth_devices[port_id];
@@ -1779,7 +1780,23 @@ rte_eth_dev_vlan_filter(uint8_t port_id, uint16_t vlan_id, int on)
 	}
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->vlan_filter_set, -ENOTSUP);
 
-	return (*dev->dev_ops->vlan_filter_set)(dev, vlan_id, on);
+	ret = (*dev->dev_ops->vlan_filter_set)(dev, vlan_id, on);
+	if (ret == 0) {
+		struct rte_vlan_filter_conf *vfc;
+		int vidx;
+		int vbit;
+
+		vfc = &dev->data->vlan_filter_conf;
+		vidx = vlan_id / 64;
+		vbit = vlan_id % 64;
+
+		if (on)
+			vfc->ids[vidx] |= UINT64_C(1) << vbit;
+		else
+			vfc->ids[vidx] &= ~(UINT64_C(1) << vbit);
+	}
+
+	return ret;
 }
 
 int
lib/librte_ether/rte_ethdev.h +10 -0
index ed99660..f01d140 100644
@@ -375,6 +375,14 @@ enum rte_vlan_type {
 };
 
 /**
+ * A structure used to describe a vlan filter.
+ * If the bit corresponding to a VID is set, such VID is on.
+ */
+struct rte_vlan_filter_conf {
+	uint64_t ids[64];
+};
+
+/**
  * A structure used to configure the Receive Side Scaling (RSS) feature
  * of an Ethernet port.
  * If not NULL, the *rss_key* pointer of the *rss_conf* structure points
@@ -1716,6 +1724,8 @@ struct rte_eth_dev_data {
 	enum rte_kernel_driver kdrv;    /**< Kernel driver passthrough */
 	int numa_node;  /**< NUMA node connection */
 	const char *drv_name;   /**< Driver name */
+	struct rte_vlan_filter_conf vlan_filter_conf;
+	/**< VLAN filter configuration. */
 };
 
 /** Device supports hotplug detach */
Signature · 1 line
2.1.4
#37 lore raw

PATCH v2 2/13 ethdev: add flow API rule copy function

In reply to Gaetan Rivet

Take this helper from the testpmd app to offer it alongside the flow API.

This allows PMDs and applications to save flow rules in their generic format for later processing. This is useful when rules cannot be applied immediately, such as when the device is not properly initialized.

---
 app/test-pmd/config.c       | 263 +++++++---------------------------------
 app/test-pmd/testpmd.h      |   5 +-
 lib/librte_ether/rte_flow.c | 283 ++++++++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_flow.h |  59 +++++++++
 4 files changed, 387 insertions(+), 223 deletions(-)
app/test-pmd/config.c +44 -219
index 54e38c4..f20e258 100644
@@ -932,208 +932,6 @@ port_mtu_set(portid_t port_id, uint16_t mtu)
 	printf("Set MTU failed. diag=%d\n", diag);
 }
 
-/* Generic flow management functions. */
-
-/** Generate flow_item[] entry. */
-#define MK_FLOW_ITEM(t, s) \
-	[RTE_FLOW_ITEM_TYPE_ ## t] = { \
-		.name = # t, \
-		.size = s, \
-	}
-
-/** Information about known flow pattern items. */
-static const struct {
-	const char *name;
-	size_t size;
-} flow_item[] = {
-	MK_FLOW_ITEM(END, 0),
-	MK_FLOW_ITEM(VOID, 0),
-	MK_FLOW_ITEM(INVERT, 0),
-	MK_FLOW_ITEM(ANY, sizeof(struct rte_flow_item_any)),
-	MK_FLOW_ITEM(PF, 0),
-	MK_FLOW_ITEM(VF, sizeof(struct rte_flow_item_vf)),
-	MK_FLOW_ITEM(PORT, sizeof(struct rte_flow_item_port)),
-	MK_FLOW_ITEM(RAW, sizeof(struct rte_flow_item_raw)), /* +pattern[] */
-	MK_FLOW_ITEM(ETH, sizeof(struct rte_flow_item_eth)),
-	MK_FLOW_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),
-	MK_FLOW_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),
-	MK_FLOW_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),
-	MK_FLOW_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)),
-	MK_FLOW_ITEM(UDP, sizeof(struct rte_flow_item_udp)),
-	MK_FLOW_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),
-	MK_FLOW_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),
-	MK_FLOW_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),
-};
-
-/** Compute storage space needed by item specification. */
-static void
-flow_item_spec_size(const struct rte_flow_item *item,
-		    size_t *size, size_t *pad)
-{
-	if (!item->spec)
-		goto empty;
-	switch (item->type) {
-		union {
-			const struct rte_flow_item_raw *raw;
-		} spec;
-
-	case RTE_FLOW_ITEM_TYPE_RAW:
-		spec.raw = item->spec;
-		*size = offsetof(struct rte_flow_item_raw, pattern) +
-			spec.raw->length * sizeof(*spec.raw->pattern);
-		break;
-	default:
-empty:
-		*size = 0;
-		break;
-	}
-	*pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size;
-}
-
-/** Generate flow_action[] entry. */
-#define MK_FLOW_ACTION(t, s) \
-	[RTE_FLOW_ACTION_TYPE_ ## t] = { \
-		.name = # t, \
-		.size = s, \
-	}
-
-/** Information about known flow actions. */
-static const struct {
-	const char *name;
-	size_t size;
-} flow_action[] = {
-	MK_FLOW_ACTION(END, 0),
-	MK_FLOW_ACTION(VOID, 0),
-	MK_FLOW_ACTION(PASSTHRU, 0),
-	MK_FLOW_ACTION(MARK, sizeof(struct rte_flow_action_mark)),
-	MK_FLOW_ACTION(FLAG, 0),
-	MK_FLOW_ACTION(QUEUE, sizeof(struct rte_flow_action_queue)),
-	MK_FLOW_ACTION(DROP, 0),
-	MK_FLOW_ACTION(COUNT, 0),
-	MK_FLOW_ACTION(DUP, sizeof(struct rte_flow_action_dup)),
-	MK_FLOW_ACTION(RSS, sizeof(struct rte_flow_action_rss)), /* +queue[] */
-	MK_FLOW_ACTION(PF, 0),
-	MK_FLOW_ACTION(VF, sizeof(struct rte_flow_action_vf)),
-};
-
-/** Compute storage space needed by action configuration. */
-static void
-flow_action_conf_size(const struct rte_flow_action *action,
-		      size_t *size, size_t *pad)
-{
-	if (!action->conf)
-		goto empty;
-	switch (action->type) {
-		union {
-			const struct rte_flow_action_rss *rss;
-		} conf;
-
-	case RTE_FLOW_ACTION_TYPE_RSS:
-		conf.rss = action->conf;
-		*size = offsetof(struct rte_flow_action_rss, queue) +
-			conf.rss->num * sizeof(*conf.rss->queue);
-		break;
-	default:
-empty:
-		*size = 0;
-		break;
-	}
-	*pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size;
-}
-
-/** Generate a port_flow entry from attributes/pattern/actions. */
-static struct port_flow *
-port_flow_new(const struct rte_flow_attr *attr,
-	      const struct rte_flow_item *pattern,
-	      const struct rte_flow_action *actions)
-{
-	const struct rte_flow_item *item;
-	const struct rte_flow_action *action;
-	struct port_flow *pf = NULL;
-	size_t tmp;
-	size_t pad;
-	size_t off1 = 0;
-	size_t off2 = 0;
-	int err = ENOTSUP;
-
-store:
-	item = pattern;
-	if (pf)
-		pf->pattern = (void *)&pf->data[off1];
-	do {
-		struct rte_flow_item *dst = NULL;
-
-		if ((unsigned int)item->type >= RTE_DIM(flow_item) ||
-		    !flow_item[item->type].name)
-			goto notsup;
-		if (pf)
-			dst = memcpy(pf->data + off1, item, sizeof(*item));
-		off1 += sizeof(*item);
-		flow_item_spec_size(item, &tmp, &pad);
-		if (item->spec) {
-			if (pf)
-				dst->spec = memcpy(pf->data + off2,
-						   item->spec, tmp);
-			off2 += tmp + pad;
-		}
-		if (item->last) {
-			if (pf)
-				dst->last = memcpy(pf->data + off2,
-						   item->last, tmp);
-			off2 += tmp + pad;
-		}
-		if (item->mask) {
-			if (pf)
-				dst->mask = memcpy(pf->data + off2,
-						   item->mask, tmp);
-			off2 += tmp + pad;
-		}
-		off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
-	} while ((item++)->type != RTE_FLOW_ITEM_TYPE_END);
-	off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
-	action = actions;
-	if (pf)
-		pf->actions = (void *)&pf->data[off1];
-	do {
-		struct rte_flow_action *dst = NULL;
-
-		if ((unsigned int)action->type >= RTE_DIM(flow_action) ||
-		    !flow_action[action->type].name)
-			goto notsup;
-		if (pf)
-			dst = memcpy(pf->data + off1, action, sizeof(*action));
-		off1 += sizeof(*action);
-		flow_action_conf_size(action, &tmp, &pad);
-		if (action->conf) {
-			if (pf)
-				dst->conf = memcpy(pf->data + off2,
-						   action->conf, tmp);
-			off2 += tmp + pad;
-		}
-		off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
-	} while ((action++)->type != RTE_FLOW_ACTION_TYPE_END);
-	if (pf != NULL)
-		return pf;
-	off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
-	tmp = RTE_ALIGN_CEIL(offsetof(struct port_flow, data), sizeof(double));
-	pf = calloc(1, tmp + off1 + off2);
-	if (pf == NULL)
-		err = errno;
-	else {
-		*pf = (const struct port_flow){
-			.size = tmp + off1 + off2,
-			.attr = *attr,
-		};
-		tmp -= offsetof(struct port_flow, data);
-		off2 = tmp + off1;
-		off1 = tmp;
-		goto store;
-	}
-notsup:
-	rte_errno = err;
-	return NULL;
-}
-
 /** Print a message out of a flow error. */
 static int
 port_flow_complain(struct rte_flow_error *error)
@@ -1186,6 +984,28 @@ port_flow_validate(portid_t port_id,
 	return 0;
 }
 
+/** Generate a port_flow entry from attributes/pattern/actions. */
+static struct port_flow *
+port_flow_new(const struct rte_flow_attr *attr,
+	      const struct rte_flow_item *pattern,
+	      const struct rte_flow_action *actions)
+{
+	struct port_flow *pf;
+
+	pf = calloc(1, sizeof(struct port_flow));
+	if (!pf)
+		return NULL;
+
+	pf->fd = rte_flow_copy(attr, pattern, actions, NULL);
+	if (pf->fd == NULL) {
+		free(pf);
+		return NULL;
+	}
+	pf->size += pf->fd->size;
+
+	return pf;
+}
+
 /** Create flow rule. */
 int
 port_flow_create(portid_t port_id,
@@ -1265,6 +1085,7 @@ port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule)
 			}
 			printf("Flow rule #%u destroyed\n", pf->id);
 			*tmp = pf->next;
+			free(pf->fd);
 			free(pf);
 			break;
 		}
@@ -1325,11 +1146,11 @@ port_flow_query(portid_t port_id, uint32_t rule,
 		printf("Flow rule #%u not found\n", rule);
 		return -ENOENT;
 	}
-	if ((unsigned int)action >= RTE_DIM(flow_action) ||
-	    !flow_action[action].name)
+	if ((unsigned int)action >= RTE_FLOW_ACTION_TYPE_MAX ||
+	    !rte_flow_desc_data_action[action].name)
 		name = "unknown";
 	else
-		name = flow_action[action].name;
+		name = rte_flow_desc_data_action[action].name;
 	switch (action) {
 	case RTE_FLOW_ACTION_TYPE_COUNT:
 		break;
@@ -1385,18 +1206,18 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
 		if (n) {
 			/* Filter out unwanted groups. */
 			for (i = 0; i != n; ++i)
-				if (pf->attr.group == group[i])
+				if (pf->fd->attr.group == group[i])
 					break;
 			if (i == n)
 				continue;
 		}
 		tmp = &list;
 		while (*tmp &&
-		       (pf->attr.group > (*tmp)->attr.group ||
-			(pf->attr.group == (*tmp)->attr.group &&
-			 pf->attr.priority > (*tmp)->attr.priority) ||
-			(pf->attr.group == (*tmp)->attr.group &&
-			 pf->attr.priority == (*tmp)->attr.priority &&
+		       (pf->fd->attr.group > (*tmp)->fd->attr.group ||
+			(pf->fd->attr.group == (*tmp)->fd->attr.group &&
+			 pf->fd->attr.priority > (*tmp)->fd->attr.priority) ||
+			(pf->fd->attr.group == (*tmp)->fd->attr.group &&
+			 pf->fd->attr.priority == (*tmp)->fd->attr.priority &&
 			 pf->id > (*tmp)->id)))
 			tmp = &(*tmp)->tmp;
 		pf->tmp = *tmp;
@@ -1404,24 +1225,28 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
 	}
 	printf("ID\tGroup\tPrio\tAttr\tRule\n");
 	for (pf = list; pf != NULL; pf = pf->tmp) {
-		const struct rte_flow_item *item = pf->pattern;
-		const struct rte_flow_action *action = pf->actions;
+		const struct rte_flow_item *item = pf->fd->items;
+		const struct rte_flow_action *action = pf->fd->actions;
 
 		printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c\t",
 		       pf->id,
-		       pf->attr.group,
-		       pf->attr.priority,
-		       pf->attr.ingress ? 'i' : '-',
-		       pf->attr.egress ? 'e' : '-');
+		       pf->fd->attr.group,
+		       pf->fd->attr.priority,
+		       pf->fd->attr.ingress ? 'i' : '-',
+		       pf->fd->attr.egress ? 'e' : '-');
 		while (item->type != RTE_FLOW_ITEM_TYPE_END) {
 			if (item->type != RTE_FLOW_ITEM_TYPE_VOID)
-				printf("%s ", flow_item[item->type].name);
+				printf("%s ",
+				       rte_flow_desc_data_item[item->type].
+									name);
 			++item;
 		}
 		printf("=>");
 		while (action->type != RTE_FLOW_ACTION_TYPE_END) {
 			if (action->type != RTE_FLOW_ACTION_TYPE_VOID)
-				printf(" %s", flow_action[action->type].name);
+				printf(" %s",
+				       rte_flow_desc_data_action[action->type].
+									name);
 			++action;
 		}
 		printf("\n");
app/test-pmd/testpmd.h +1 -4
index 85d3e82..6002388 100644
@@ -153,10 +153,7 @@ struct port_flow {
 	struct port_flow *tmp; /**< Temporary linking. */
 	uint32_t id; /**< Flow rule ID. */
 	struct rte_flow *flow; /**< Opaque flow object returned by PMD. */
-	struct rte_flow_attr attr; /**< Attributes. */
-	struct rte_flow_item *pattern; /**< Pattern. */
-	struct rte_flow_action *actions; /**< Actions. */
-	uint8_t data[]; /**< Storage for pattern/actions. */
+	struct rte_flow_desc *fd; /**< Generic flow description */
 };
 
 /**
lib/librte_ether/rte_flow.c +283 -0

292 lines not on this page · raw message

lib/librte_ether/rte_flow.h +59 -0

77 lines not on this page · raw message

Signature · 1 line
2.1.4
#38 lore raw

PATCH v2 3/13 ethdev: add deferred intermediate device state

In reply to Gaetan Rivet

This device state means that the device is managed externally, by whichever party has set this state (PMD or application).

Note: this new device state is only an information. The related device structure and operators are still valid and can be used normally.

It is however made private by device management helpers within ethdev, making the device invisible to applications.

---
 lib/librte_ether/rte_ethdev.c | 3 ++-
 lib/librte_ether/rte_ethdev.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
lib/librte_ether/rte_ethdev.c +2 -1
index 61a63b7..7824f87 100644
@@ -382,7 +382,8 @@ int
 rte_eth_dev_is_valid_port(uint8_t port_id)
 {
 	if (port_id >= RTE_MAX_ETHPORTS ||
-	    rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED)
+	    (rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED &&
+	     rte_eth_devices[port_id].state != RTE_ETH_DEV_DEFERRED))
 		return 0;
 	else
 		return 1;
lib/librte_ether/rte_ethdev.h +1 -0
index f01d140..ae1e9e6 100644
@@ -1629,6 +1629,7 @@ struct rte_eth_rxtx_callback {
 enum rte_eth_dev_state {
 	RTE_ETH_DEV_UNUSED = 0,
 	RTE_ETH_DEV_ATTACHED,
+	RTE_ETH_DEV_DEFERRED,
 };
 
 /**
Signature · 1 line
2.1.4
#39 lore raw

PATCH v2 4/13 pci: expose device detach routine

In reply to Gaetan Rivet

Make the pci_detach_all_drivers public. No further changes.

---
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  5 +++++
 lib/librte_eal/common/eal_common_pci.c          |  6 +++---
 lib/librte_eal/common/include/rte_pci.h         | 15 +++++++++++++++
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  5 +++++
 4 files changed, 28 insertions(+), 3 deletions(-)
lib/librte_eal/bsdapp/eal/rte_eal_version.map +5 -0
index 2cf1ac8..3a87756 100644
@@ -185,3 +185,8 @@ DPDK_17.02 {
 	rte_bus_unregister;
 
 } DPDK_16.11;
+
+DPDK_17.05 {
+	rte_eal_pci_detach_all_drivers;
+
+} DPDK_17.02;
lib/librte_eal/common/eal_common_pci.c +3 -3
index 72547bd..d38335a 100644
@@ -313,8 +313,8 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
  * registered driver for the given device. Return -1 if initialization
  * failed, return 1 if no driver is found for this device.
  */
-static int
-pci_detach_all_drivers(struct rte_pci_device *dev)
+int
+rte_eal_pci_detach_all_drivers(struct rte_pci_device *dev)
 {
 	struct rte_pci_driver *dr = NULL;
 	int rc = 0;
@@ -388,7 +388,7 @@ rte_eal_pci_detach(const struct rte_pci_addr *addr)
 		if (rte_eal_compare_pci_addr(&dev->addr, addr))
 			continue;
 
-		ret = pci_detach_all_drivers(dev);
+		ret = rte_eal_pci_detach_all_drivers(dev);
 		if (ret < 0)
 			goto err_return;
 
lib/librte_eal/common/include/rte_pci.h +15 -0
index 4a67883..598a1ef 100644
@@ -459,6 +459,21 @@ void pci_unmap_resource(void *requested_addr, size_t size);
 int rte_eal_pci_probe_one(const struct rte_pci_addr *addr);
 
 /**
+ * Remove any PCI drivers tied to the device.
+ *
+ * If vendor/device ID match, call the remove() function of all
+ * registered driver for the given device.
+ *
+ * @param dev
+ *	The PCI device to remove
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ *   - Positive if no driver exists for that device.
+ */
+int rte_eal_pci_detach_all_drivers(struct rte_pci_device *dev);
+
+/**
  * Close the single PCI device.
  *
  * Scan the content of the PCI bus, and find the pci device specified by pci
lib/librte_eal/linuxapp/eal/rte_eal_version.map +5 -0
index 3c68ff5..192c0d5 100644
@@ -189,3 +189,8 @@ DPDK_17.02 {
 	rte_bus_unregister;
 
 } DPDK_16.11;
+
+DPDK_17.05 {
+	rte_eal_pci_detach_all_drivers;
+
+} DPDK_17.02;
Signature · 1 line
2.1.4
#40 lore raw

PATCH v2 5/13 pci: expose parse and probe routines

In reply to Gaetan Rivet

Make pci_probe_all_drivers public, no further changes to it. Introduce a public function for pci_scan_one. This functions scan one device, but does not allocate that device or insert it within the device list.

---
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  1 +
 lib/librte_eal/common/eal_common_pci.c          | 10 +++----
 lib/librte_eal/common/include/rte_pci.h         | 25 ++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           | 39 +++++++++++++++----------
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  2 ++
 5 files changed, 57 insertions(+), 20 deletions(-)
lib/librte_eal/bsdapp/eal/rte_eal_version.map +1 -0
index 3a87756..ba8f8e4 100644
@@ -188,5 +188,6 @@ DPDK_17.02 {
 
 DPDK_17.05 {
 	rte_eal_pci_detach_all_drivers;
+	rte_eal_pci_probe_all_drivers;
 
 } DPDK_17.02;
lib/librte_eal/common/eal_common_pci.c +5 -5
index d38335a..15a0c48 100644
@@ -282,8 +282,8 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr,
  * registered driver for the given device. Return -1 if initialization
  * failed, return 1 if no driver is found for this device.
  */
-static int
-pci_probe_all_drivers(struct rte_pci_device *dev)
+int
+rte_eal_pci_probe_all_drivers(struct rte_pci_device *dev)
 {
 	struct rte_pci_driver *dr = NULL;
 	int rc = 0;
@@ -358,7 +358,7 @@ rte_eal_pci_probe_one(const struct rte_pci_addr *addr)
 		if (rte_eal_compare_pci_addr(&dev->addr, addr))
 			continue;
 
-		ret = pci_probe_all_drivers(dev);
+		ret = rte_eal_pci_probe_all_drivers(dev);
 		if (ret)
 			goto err_return;
 		return 0;
@@ -430,10 +430,10 @@ rte_eal_pci_probe(void)
 
 		/* probe all or only whitelisted devices */
 		if (probe_all)
-			ret = pci_probe_all_drivers(dev);
+			ret = rte_eal_pci_probe_all_drivers(dev);
 		else if (devargs != NULL &&
 			devargs->type == RTE_DEVTYPE_WHITELISTED_PCI)
-			ret = pci_probe_all_drivers(dev);
+			ret = rte_eal_pci_probe_all_drivers(dev);
 		if (ret < 0)
 			rte_exit(EXIT_FAILURE, "Requested device " PCI_PRI_FMT
 				 " cannot be used\n", dev->addr.domain, dev->addr.bus,
lib/librte_eal/common/include/rte_pci.h +25 -0
index 598a1ef..4291da8 100644
@@ -373,6 +373,16 @@ rte_eal_compare_pci_addr(const struct rte_pci_addr *addr,
 int rte_eal_pci_scan(void);
 
 /**
+ * Parse the content of one PCI entry.
+ *
+ * @return
+ *  0 on success, negative on error
+ */
+int rte_eal_pci_parse_sysfs_entry(struct rte_pci_device *dev,
+				 const char *dirname,
+				 const struct rte_pci_addr *addr);
+
+/**
  * Probe the PCI bus for registered drivers.
  *
  * Scan the content of the PCI bus, and call the probe() function for
@@ -459,6 +469,21 @@ void pci_unmap_resource(void *requested_addr, size_t size);
 int rte_eal_pci_probe_one(const struct rte_pci_addr *addr);
 
 /**
+ * Probe all pci drivers against the device.
+ *
+ * If vendor/device ID match, call the probe() function of all
+ * registered driver for the given device.
+ *
+ * @param dev
+ *	The PCI device to probe
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ *   - Positive if no driver exists for that device.
+ */
+int rte_eal_pci_probe_all_drivers(struct rte_pci_device *dev);
+
+/**
  * Remove any PCI drivers tied to the device.
  *
  * If vendor/device ID match, call the remove() function of all
lib/librte_eal/linuxapp/eal/eal_pci.c +24 -15
index e2fc219..51c6b84 100644
@@ -226,27 +226,22 @@ pci_parse_sysfs_resource(const char *filename, struct rte_pci_device *dev)
 	return -1;
 }
 
-/* Scan one pci sysfs entry, and fill the devices list from it. */
-static int
-pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
+/* Parse a pci sysfs entry */
+int
+rte_eal_pci_parse_sysfs_entry(struct rte_pci_device *dev, const char *dirname,
+			const struct rte_pci_addr *addr)
 {
 	char filename[PATH_MAX];
 	unsigned long tmp;
-	struct rte_pci_device *dev;
 	char driver[PATH_MAX];
 	int ret;
 
-	dev = malloc(sizeof(*dev));
-	if (dev == NULL)
-		return -1;
-
 	memset(dev, 0, sizeof(*dev));
 	dev->addr = *addr;
 
 	/* get vendor id */
 	snprintf(filename, sizeof(filename), "%s/vendor", dirname);
 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
-		free(dev);
 		return -1;
 	}
 	dev->id.vendor_id = (uint16_t)tmp;
@@ -254,7 +249,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	/* get device id */
 	snprintf(filename, sizeof(filename), "%s/device", dirname);
 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
-		free(dev);
 		return -1;
 	}
 	dev->id.device_id = (uint16_t)tmp;
@@ -263,7 +257,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	snprintf(filename, sizeof(filename), "%s/subsystem_vendor",
 		 dirname);
 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
-		free(dev);
 		return -1;
 	}
 	dev->id.subsystem_vendor_id = (uint16_t)tmp;
@@ -272,7 +265,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	snprintf(filename, sizeof(filename), "%s/subsystem_device",
 		 dirname);
 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
-		free(dev);
 		return -1;
 	}
 	dev->id.subsystem_device_id = (uint16_t)tmp;
@@ -281,7 +273,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	snprintf(filename, sizeof(filename), "%s/class",
 		 dirname);
 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
-		free(dev);
 		return -1;
 	}
 	/* the least 24 bits are valid: class, subclass, program interface */
@@ -320,7 +311,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	snprintf(filename, sizeof(filename), "%s/resource", dirname);
 	if (pci_parse_sysfs_resource(filename, dev) < 0) {
 		RTE_LOG(ERR, EAL, "%s(): cannot parse resource\n", __func__);
-		free(dev);
 		return -1;
 	}
 
@@ -329,7 +319,6 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	ret = pci_get_kernel_driver_by_path(filename, driver);
 	if (ret < 0) {
 		RTE_LOG(ERR, EAL, "Fail to get kernel driver\n");
-		free(dev);
 		return -1;
 	}
 
@@ -345,6 +334,26 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 	} else
 		dev->kdrv = RTE_KDRV_NONE;
 
+	return 0;
+}
+
+/* Scan one pci sysfs entry, and fill the devices list from it. */
+static int
+pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
+{
+	struct rte_pci_device *dev;
+	int ret;
+
+	dev = malloc(sizeof(*dev));
+	if (dev == NULL)
+		return -1;
+
+	ret = rte_eal_pci_parse_sysfs_entry(dev, dirname, addr);
+	if (ret) {
+		free(dev);
+		return ret;
+	}
+
 	/* device is valid, add in list (sorted) */
 	if (TAILQ_EMPTY(&pci_device_list)) {
 		rte_eal_device_insert(&dev->device);
lib/librte_eal/linuxapp/eal/rte_eal_version.map +2 -0
index 192c0d5..27b7939 100644
@@ -192,5 +192,7 @@ DPDK_17.02 {
 
 DPDK_17.05 {
 	rte_eal_pci_detach_all_drivers;
+	rte_eal_pci_probe_all_drivers;
+	rte_eal_pci_parse_sysfs_entry;
 
 } DPDK_17.02;
Signature · 1 line
2.1.4
#41 lore raw

PATCH v2 6/13 net/failsafe: add fail-safe PMD

In reply to Gaetan Rivet

Introduce the fail-safe poll mode driver initialization and enable its build infrastructure.

This PMD allows for applications to benefits from true hot-plugging support without having to implement it.

It intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back. It also allows defining a contingency to the removal of a device, by designating a fail-over device that will take on transmitting operations if the preferred device is removed.

Applications only see a fail-safe instance, without caring for underlying activity ensuring their continued operations.

---
 MAINTAINERS                             |   5 +
 config/common_base                      |   5 +
 doc/guides/nics/fail_safe.rst           | 133 +++++++
 doc/guides/nics/features/failsafe.ini   |  24 ++
 doc/guides/nics/index.rst               |   1 +
 drivers/net/Makefile                    |   1 +
 drivers/net/failsafe/Makefile           |  72 ++++
 drivers/net/failsafe/failsafe.c         | 229 +++++++++++
 drivers/net/failsafe/failsafe_args.c    | 347 ++++++++++++++++
 drivers/net/failsafe/failsafe_eal.c     | 318 +++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     | 677 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h | 232 +++++++++++
 drivers/net/failsafe/failsafe_rxtx.c    | 107 +++++
 mk/rte.app.mk                           |   1 +
 14 files changed, 2152 insertions(+)
 create mode 100644 doc/guides/nics/fail_safe.rst
 create mode 100644 doc/guides/nics/features/failsafe.ini
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
MAINTAINERS +5 -0
index cc3bf98..ab9ed0c 100644
@@ -315,6 +315,11 @@ M: Matej Vido <[email protected]>
 F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 
+Fail-safe PMD
+M: Gaetan Rivet <[email protected]>
+F: drivers/net/failsafe/
+F: doc/guides/nics/fail_safe.rst
+
 Intel e1000
 M: Wenzhuo Lu <[email protected]>
 F: drivers/net/e1000/
config/common_base +5 -0
index 71a4fcb..ae64a5b 100644
@@ -364,6 +364,11 @@ CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 CONFIG_RTE_LIBRTE_PMD_NULL=y
 
 #
+# Compile fail-safe PMD
+#
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
doc/guides/nics/fail_safe.rst new file +133 -0

133 lines not on this page · raw message

doc/guides/nics/features/failsafe.ini new file +24 -0
new file mode 100644
index 0000000..3c52823
@@ -0,0 +1,24 @@
+;
+; Supported features of the 'fail-safe' poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Link status          = Y
+Queue start/stop     = Y
+MTU update           = Y
+Jumbo frame          = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Unicast MAC filter   = Y
+Multicast MAC filter = Y
+VLAN filter          = Y
+Packet type parsing  = Y
+Basic stats          = Y
+Stats per queue      = Y
+ARMv7                = Y
+ARMv8                = Y
+Power8               = Y
+x86-32               = Y
+x86-64               = Y
+Usage doc            = Y
doc/guides/nics/index.rst +1 -0
index 87f9334..0ba52e1 100644
@@ -58,6 +58,7 @@ Network Interface Controller Drivers
     vhost
     vmxnet3
     pcap_ring
+    fail_safe
 
 **Figures**
 
drivers/net/Makefile +1 -0
index 40fc333..3c658b4 100644
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += cxgbe
 DIRS-$(CONFIG_RTE_LIBRTE_E1000_PMD) += e1000
 DIRS-$(CONFIG_RTE_LIBRTE_ENA_PMD) += ena
 DIRS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) += enic
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe
 DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k
 DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e
 DIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += ixgbe
drivers/net/failsafe/Makefile new file +72 -0

72 lines not on this page · raw message

drivers/net/failsafe/failsafe.c new file +229 -0

229 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c new file +347 -0

347 lines not on this page · raw message

drivers/net/failsafe/failsafe_eal.c new file +318 -0

318 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c new file +677 -0

677 lines not on this page · raw message

drivers/net/failsafe/failsafe_private.h new file +232 -0

232 lines not on this page · raw message

drivers/net/failsafe/failsafe_rxtx.c new file +107 -0

107 lines not on this page · raw message

mk/rte.app.mk +1 -0
index 92f3635..2032625 100644
@@ -112,6 +112,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_E1000_PMD)      += -lrte_pmd_e1000
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENA_PMD)        += -lrte_pmd_ena
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENIC_PMD)       += -lrte_pmd_enic
 _LDLIBS-$(CONFIG_RTE_LIBRTE_FM10K_PMD)      += -lrte_pmd_fm10k
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE)   += -lrte_pmd_failsafe
 _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD)      += -lrte_pmd_ixgbe
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs
Signature · 1 line
2.1.4
#42 lore raw

PATCH v2 7/13 net/failsafe: add plug-in support

In reply to Gaetan Rivet

Periodically check for the existence of a device.
If a device has not been initialized and exists on the system, then it is probed and configured.

The configuration process strives to synchronize the states between the plugged-in sub-device and the fail-safe device.

---
 doc/guides/nics/fail_safe.rst           |  19 +++
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |  68 ++++++++++
 drivers/net/failsafe/failsafe_args.c    |  32 +++++
 drivers/net/failsafe/failsafe_eal.c     |  30 +----
 drivers/net/failsafe/failsafe_ether.c   | 228 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  25 ++--
 drivers/net/failsafe/failsafe_private.h |  57 +++++++-
 8 files changed, 418 insertions(+), 42 deletions(-)
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
doc/guides/nics/fail_safe.rst +19 -0
index 056f85f..74bd807 100644
@@ -102,6 +102,11 @@ Fail-safe command line parameters
   address is generated, that will be subsequently applied to all sub-device once
   they are probed.
 
+- **plug_in_poll** parameter [UINT64] (default **2000**)
+
+  This parameter allows the user to configure the amount of time in milliseconds
+  between two sub-device probing attempt.
+
 Usage example
 ~~~~~~~~~~~~~
 
@@ -131,3 +136,17 @@ Care must be taken, however, to respect the **ether** API concerning device
 access, and in particular, using the ``RTE_ETH_FOREACH_DEV`` macro to iterate
 over ethernet devices, instead of directly accessing them or by writing one's
 own device iterator.
+
+Plug-in feature
+---------------
+
+A sub-device can be defined without existing on the system when the fail-safe
+PMD is initialized. Upon probing this device, the fail-safe PMD will detect its
+absence and postpone its use. It will then register for a periodic check on any
+missing sub-device.
+
+During this time, the fail-safe PMD can be used normally, configured and told to
+emit and receive packets. It will store any applied configuration, and try to
+apply it upon the probing of its missing sub-device. After this configuration
+pass, the new sub-device will be synchronized with other sub-devices, i.e. be
+started if the fail-safe PMD has been started by the user before.
drivers/net/failsafe/Makefile +1 -0
index 06199ad..4567961 100644
@@ -40,6 +40,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_args.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +68 -0

80 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c +32 -0
index faa48f4..773b322 100644
@@ -45,9 +45,11 @@
 typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
 		uint8_t head);
 
+uint64_t plug_in_poll;
 int mac_from_arg;
 
 const char *pmd_failsafe_init_parameters[] = {
+	PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
 	PMD_FAILSAFE_MAC_KVARG,
 	NULL,
 };
@@ -237,6 +239,24 @@ remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
 }
 
 static int
+get_u64_arg(const char *key __rte_unused,
+		const char *value, void *out)
+{
+	uint64_t *u64 = out;
+	char *endptr = NULL;
+
+	if ((value == NULL) || (out == NULL))
+		return -EINVAL;
+	errno = 0;
+	*u64 = strtoull(value, &endptr, 0);
+	if (errno != 0)
+		return -errno;
+	if (endptr == value)
+		return -1;
+	return 0;
+}
+
+static int
 get_mac_addr_arg(const char *key __rte_unused,
 		const char *value, void *out)
 {
@@ -268,6 +288,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 	ret = 0;
 	priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
 	/* default parameters */
+	plug_in_poll = FAILSAFE_PLUGIN_DEFAULT_TIMEOUT_MS;
 	mac_from_arg = 0;
 	n = snprintf(mut_params, sizeof(mut_params), "%s", params);
 	if (n >= sizeof(mut_params)) {
@@ -290,6 +311,16 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 				PMD_FAILSAFE_PARAM_STRING);
 			return -1;
 		}
+		/* PLUG_IN event poll timer */
+		arg_count = rte_kvargs_count(kvlist,
+				PMD_FAILSAFE_PLUG_IN_POLL_KVARG);
+		if (arg_count == 1) {
+			ret = rte_kvargs_process(kvlist,
+					PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
+					&get_u64_arg, &plug_in_poll);
+			if (ret < 0)
+				goto free_kvlist;
+		}
 		/* MAC addr */
 		arg_count = rte_kvargs_count(kvlist,
 				PMD_FAILSAFE_MAC_KVARG);
@@ -303,6 +334,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 			mac_from_arg = 1;
 		}
 	}
+	PRIV(dev)->state = DEV_PARSED;
 free_kvlist:
 	rte_kvargs_free(kvlist);
 	return ret;
drivers/net/failsafe/failsafe_eal.c +4 -26
index fcee500..a5e8c3c 100644
@@ -198,8 +198,6 @@ pci_probe(struct rte_eth_dev *dev)
 int
 failsafe_eal_init(struct rte_eth_dev *dev)
 {
-	struct sub_device *sdev;
-	uint8_t i;
 	int ret;
 
 	ret = pci_scan(dev);
@@ -211,30 +209,9 @@ failsafe_eal_init(struct rte_eth_dev *dev)
 	ret = dev_init(dev);
 	if (ret)
 		return ret;
-	/*
-	 * We only update TX_SUBDEV if we are not started.
-	 * If a sub_device is emitting, we will switch the TX_SUBDEV to the
-	 * preferred port only upon starting it, so that the switch is smoother.
-	 */
-	if (PREFERRED_SUBDEV(dev)->state >= DEV_PROBED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev) &&
-		    (TX_SUBDEV(dev) == NULL ||
-		     (TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED))) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_PROBED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			/* Using first probed device */
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_PROBED) {
-				DEBUG("Switching tx_dev to sub_device %d",
-				      i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_PROBED)
+		PRIV(dev)->state = DEV_PROBED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -314,5 +291,6 @@ failsafe_eal_uninit(struct rte_eth_dev *dev)
 	ret = dev_uninit(dev);
 	if (ret)
 		return ret;
+	PRIV(dev)->state = DEV_PROBED - 1;
 	return 0;
 }
drivers/net/failsafe/failsafe_ether.c new file +228 -0

228 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +10 -15
index 470fea4..b408877 100644
@@ -89,6 +89,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 		sdev->state = DEV_ACTIVE;
 	}
+	if (PRIV(dev)->state < DEV_ACTIVE)
+		PRIV(dev)->state = DEV_ACTIVE;
 	return 0;
 }
 
@@ -108,21 +110,9 @@ fs_dev_start(struct rte_eth_dev *dev)
 			return ret;
 		sdev->state = DEV_STARTED;
 	}
-	if (PREFERRED_SUBDEV(dev)->state == DEV_STARTED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev)) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
-				DEBUG("Switching tx_dev to sub_device %d", i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_STARTED)
+		PRIV(dev)->state = DEV_STARTED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -132,6 +122,7 @@ fs_dev_stop(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	PRIV(dev)->state = DEV_STARTED - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
 		rte_eth_dev_stop(PORT_ID(sdev));
 		sdev->state = DEV_STARTED - 1;
@@ -183,6 +174,10 @@ fs_dev_close(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	failsafe_plugin_alarm_cancel(dev);
+	if (PRIV(dev)->state == DEV_STARTED)
+		dev->dev_ops->dev_stop(dev);
+	PRIV(dev)->state = DEV_ACTIVE - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
 		DEBUG("Closing sub_device %d", i);
 		rte_eth_dev_close(PORT_ID(sdev));
drivers/net/failsafe/failsafe_private.h +56 -1

87 lines not on this page · raw message

Signature · 1 line
2.1.4
#43 lore raw

PATCH v2 8/13 net/failsafe: add flexible device definition

In reply to Gaetan Rivet

Add the "exec" device type.
The parameters given to this type of device will be executed in a shell. The output of this command is then used as a definition for a device.

That command can be re-interpreted if the related device is not plugged-in. It allows for a device definition to react to system changes (e.g. changing PCI bus for a given device).

---
 doc/guides/nics/fail_safe.rst           |  16 +++++
 drivers/net/failsafe/failsafe_args.c    | 102 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ether.c   |   7 +++
 drivers/net/failsafe/failsafe_private.h |   4 ++
 4 files changed, 129 insertions(+)
doc/guides/nics/fail_safe.rst +16 -0
index 74bd807..bb8a221 100644
@@ -91,6 +91,15 @@ Fail-safe command line parameters
   additional sub-device parameters if need be. They will be passed on to the
   sub-device.
 
+- **exec(<shell command>)** parameter
+
+  This parameter allows the user to provide a command to the fail-safe PMD to
+  execute and define a sub-device. It is done within a regular shell context.
+  The first line of its output is read by the fail-safe PMD and otherwise
+  interpreted as if passed by the regular **dev** parameter. Any other line is
+  discarded. If the command fail or output an incorrect string, the sub-device
+  is not initialized.
+
 - **mac** parameter [MAC address]
 
   This parameter allows the user to set a default MAC address to the fail-safe
@@ -126,6 +135,13 @@ This section shows some example of using **testpmd** with a fail-safe PMD.
          --vdev='net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0,nodeaction=r1:0:CREATE)' -- \
          -i
 
+#. Start testpmd using a flexible device definition
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 --no-pci \
+         --vdev='net_failsafe0,exec(echo 84:00.0)' -- -i
+
 Using the Fail-safe PMD from an application
 -------------------------------------------
 
drivers/net/failsafe/failsafe_args.c +102 -0

123 lines not on this page · raw message

drivers/net/failsafe/failsafe_ether.c +7 -0
index ccdd471..a6ccf8f 100644
@@ -188,6 +188,13 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	int ret;
 	uint8_t i;
 
+	if (PRIV(dev)->state < DEV_PARSED)
+		return 0;
+
+	ret = failsafe_args_parse_subs(dev);
+	if (ret)
+		return ret;
+
 	if (PRIV(dev)->state < DEV_PROBED)
 		return 0;
 	ret = failsafe_eal_init(dev);
drivers/net/failsafe/failsafe_private.h +4 -0
index bb27223..fcd5b75 100644
@@ -45,6 +45,7 @@
 #define PMD_FAILSAFE_PLUG_IN_POLL_KVARG "plug_in_poll"
 #define PMD_FAILSAFE_PARAM_STRING	\
 	"dev(<ifc>),"			\
+	"exec(<shell command>),"	\
 	"mac=mac_addr,"			\
 	"plug_in_poll=u64"		\
 	""
@@ -92,6 +93,8 @@ struct sub_device {
 	struct rte_eth_dev *eth_dev;
 	/* Device state machine */
 	enum dev_state state;
+	/* Some device are defined as a command line */
+	char *cmdline;
 };
 
 struct fs_priv {
@@ -140,6 +143,7 @@ uint16_t failsafe_tx_burst(void *txq,
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
 void failsafe_args_free(struct rte_eth_dev *dev);
 int failsafe_args_count_subdevice(struct rte_eth_dev *dev, const char *params);
+int failsafe_args_parse_subs(struct rte_eth_dev *dev);
 
 /* EAL */
 
Signature · 1 line
2.1.4
#44 lore raw

PATCH v2 9/13 net/failsafe: support flow API

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |   1 +
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |   1 +
 drivers/net/failsafe/failsafe_eal.c     |   2 +
 drivers/net/failsafe/failsafe_ether.c   |  76 +++++++++++
 drivers/net/failsafe/failsafe_flow.c    | 230 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  29 ++++
 drivers/net/failsafe/failsafe_private.h |  20 +++
 8 files changed, 360 insertions(+)
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
doc/guides/nics/features/failsafe.ini +1 -0
index 3c52823..9167b59 100644
@@ -13,6 +13,7 @@ Allmulticast mode    = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
+Flow API             = Y
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/Makefile +1 -0
index 4567961..a53bb75 100644
@@ -41,6 +41,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_flow.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +1 -0
index 2063393..6151736 100644
@@ -180,6 +180,7 @@ eth_dev_create(const char *name,
 	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
 	dev->data->dev_link = eth_link;
 	PRIV(dev)->nb_mac_addr = 1;
+	TAILQ_INIT(&PRIV(dev)->flow_list);
 	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
 	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
 	if (params == NULL) {
drivers/net/failsafe/failsafe_eal.c +2 -0
index a5e8c3c..9817fc9 100644
@@ -139,6 +139,7 @@ dev_init(struct rte_eth_dev *dev)
 				continue;
 			}
 			ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
+			SUB_ID(sdev) = i;
 			sdev->state = DEV_PROBED;
 		}
 	}
@@ -189,6 +190,7 @@ pci_probe(struct rte_eth_dev *dev)
 				continue;
 			}
 			ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
+			SUB_ID(sdev) = i;
 			sdev->state = DEV_PROBED;
 		}
 	}
drivers/net/failsafe/failsafe_ether.c +76 -0

96 lines not on this page · raw message

drivers/net/failsafe/failsafe_flow.c new file +230 -0

230 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +29 -0
index b408877..d837280 100644
@@ -35,6 +35,7 @@
 #include <stdint.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_flow.h>
 
 #include "failsafe_private.h"
 
@@ -642,6 +643,33 @@ fs_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 		rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), mac_addr);
 }
 
+static int
+fs_filter_ctrl(struct rte_eth_dev *dev,
+		enum rte_filter_type type,
+		enum rte_filter_op op,
+		void *arg)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	if (type == RTE_ETH_FILTER_GENERIC &&
+	    op == RTE_ETH_FILTER_GET) {
+		*(const void **)arg = &fs_flow_ops;
+		return 0;
+	}
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		DEBUG("Calling rte_eth_dev_filter_ctrl on sub_device %d", i);
+		ret = rte_eth_dev_filter_ctrl(PORT_ID(sdev), type, op, arg);
+		if (ret) {
+			ERROR("Operation rte_eth_dev_filter_ctrl failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
 const struct eth_dev_ops failsafe_ops = {
 	.dev_configure = fs_dev_configure,
 	.dev_start = fs_dev_start,
@@ -669,4 +697,5 @@ const struct eth_dev_ops failsafe_ops = {
 	.mac_addr_remove = fs_mac_addr_remove,
 	.mac_addr_add = fs_mac_addr_add,
 	.mac_addr_set = fs_mac_addr_set,
+	.filter_ctrl = fs_filter_ctrl,
 };
drivers/net/failsafe/failsafe_private.h +20 -0
index fcd5b75..c636199 100644
@@ -34,6 +34,8 @@
 #ifndef _RTE_ETH_FAILSAFE_PRIVATE_H_
 #define _RTE_ETH_FAILSAFE_PRIVATE_H_
 
+#include <sys/queue.h>
+
 #include <rte_dev.h>
 #include <rte_pci.h>
 #include <rte_ethdev.h>
@@ -73,6 +75,16 @@ struct txq {
 	struct rte_eth_txq_info info;
 };
 
+struct rte_flow {
+	TAILQ_ENTRY(rte_flow) next;
+
+	/* sub_flows */
+	struct rte_flow *flows[FAILSAFE_MAX_ETHPORTS];
+
+	/* flow description for synchronization */
+	struct rte_flow_desc *fd;
+};
+
 enum dev_state {
 	DEV_UNDEFINED = 0,
 	DEV_PARSED,
@@ -91,6 +103,7 @@ struct sub_device {
 		struct rte_pci_device pci_device;
 	};
 	struct rte_eth_dev *eth_dev;
+	uint8_t sid;
 	/* Device state machine */
 	enum dev_state state;
 	/* Some device are defined as a command line */
@@ -109,6 +122,8 @@ struct fs_priv {
 	uint8_t subs_tx;
 	struct sub_device *subs;
 	uint8_t current_probed;
+	/* flow mapping */
+	TAILQ_HEAD(sub_flows, rte_flow) flow_list;
 	/* current number of mac_addr slots allocated. */
 	uint32_t nb_mac_addr;
 	struct ether_addr mac_addrs[FAILSAFE_MAX_ETHADDR];
@@ -158,6 +173,7 @@ int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);
 
 extern const char pmd_failsafe_driver_name[];
 extern const struct eth_dev_ops failsafe_ops;
+extern const struct rte_flow_ops fs_flow_ops;
 extern uint64_t plug_in_poll;
 extern int mac_from_arg;
 
@@ -175,6 +191,10 @@ extern int mac_from_arg;
 #define PORT_ID(sdev) \
 	(ETH(sdev)->data->port_id)
 
+/* sdev: (struct sub_device *) */
+#define SUB_ID(sdev) \
+	(sdev->sid)
+
 /**
  * Stateful iterator construct over fail-safe sub-devices:
  * s:     (struct sub_device *), iterator
Signature · 1 line
2.1.4
#45 lore raw

PATCH v2 10/13 net/failsafe: support offload capabilities

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini |   6 ++
 drivers/net/failsafe/failsafe_ops.c   | 125 +++++++++++++++++++++++++++++++++-
 2 files changed, 129 insertions(+), 2 deletions(-)
doc/guides/nics/features/failsafe.ini +6 -0
index 9167b59..257f579 100644
@@ -14,6 +14,12 @@ Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
 Flow API             = Y
+VLAN offload         = Y
+QinQ offload         = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Inner L3 checksum    = Y
+Inner L4 checksum    = Y
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/failsafe_ops.c +123 -2

145 lines not on this page · raw message

Signature · 1 line
2.1.4
#46 lore raw

PATCH v2 11/13 net/failsafe: add fast burst functions

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_private.h |   8 +++
 drivers/net/failsafe/failsafe_rxtx.c    | 117 ++++++++++++++++++++++++++------
 2 files changed, 105 insertions(+), 20 deletions(-)
drivers/net/failsafe/failsafe_private.h +8 -0
index c636199..faf0e71 100644
@@ -148,11 +148,18 @@ int failsafe_plugin_alarm_cancel(struct rte_eth_dev *dev);
 
 /* RX / TX */
 
+void set_burst_fn(struct rte_eth_dev *dev);
+
 uint16_t failsafe_rx_burst(void *rxq,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t failsafe_tx_burst(void *txq,
 		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 
+uint16_t failsafe_rx_burst_fast(void *rxq,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t failsafe_tx_burst_fast(void *txq,
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+
 /* ARGS */
 
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
@@ -306,6 +313,7 @@ fs_switch_dev(struct rte_eth_dev *dev)
 	} else {
 		return;
 	}
+	set_burst_fn(dev);
 }
 
 #endif /* _RTE_ETH_FAILSAFE_PRIVATE_H_ */
drivers/net/failsafe/failsafe_rxtx.c +97 -20

142 lines not on this page · raw message

Signature · 1 line
2.1.4
#47 lore raw

PATCH v2 12/13 net/failsafe: support device removal

In reply to Gaetan Rivet
---
 doc/guides/nics/fail_safe.rst           | 14 +++++++
 drivers/net/failsafe/failsafe_args.c    | 22 +++++++++++
 drivers/net/failsafe/failsafe_eal.c     |  2 +
 drivers/net/failsafe/failsafe_ether.c   | 67 ++++++++++++++++++++++++++++++++-
 drivers/net/failsafe/failsafe_ops.c     | 21 +++++++++++
 drivers/net/failsafe/failsafe_private.h |  7 ++++
 6 files changed, 132 insertions(+), 1 deletion(-)
doc/guides/nics/fail_safe.rst +14 -0
index bb8a221..8811ed3 100644
@@ -51,6 +51,12 @@ The Fail-safe PMD only supports a limited set of features. If you plan to use a
 device underneath the Fail-safe PMD with a specific feature, this feature must
 be supported by the Fail-safe PMD to avoid throwing any error.
 
+A notable exception is the device removal feature. The fail-safe PMD being a
+virtual device, it cannot currently be removed in the sense of a specific bus
+hotplug, like for PCI for example. It will however enable this feature for its
+sub-device automatically, detecting those that are capable and register the
+relevant callback for such event.
+
 Check the feature matrix for the complete set of supported features.
 
 Compilation options
@@ -166,3 +172,11 @@ emit and receive packets. It will store any applied configuration, and try to
 apply it upon the probing of its missing sub-device. After this configuration
 pass, the new sub-device will be synchronized with other sub-devices, i.e. be
 started if the fail-safe PMD has been started by the user before.
+
+Plug-out feature
+----------------
+
+A sub-device supporting the device removal event can be removed from its bus at
+any time. The fail-safe PMD will register a callback for such event and react
+accordingly. It will try to safely stop, close and uninit the sub-device having
+emitted this event, allowing it to free its eventual resources.
drivers/net/failsafe/failsafe_args.c +22 -0
index 839831f..62033c4 100644
@@ -462,6 +462,26 @@ failsafe_args_count_subdevice(struct rte_eth_dev *dev,
 				dev, params);
 }
 
+static int
+parse_sub_device(struct sub_device *sdev)
+{
+	struct rte_devargs *da;
+	char params[DEVARGS_MAXLEN] = "";
+
+	da = &sdev->devargs;
+	if (da->type == RTE_DEVTYPE_VIRTUAL)
+		snprintf(params, sizeof(params) - 1,
+			"%s,%s", da->virt.drv_name, da->args);
+	else
+		snprintf(params, sizeof(params) - 1,
+			PCI_PRI_FMT ",%s",
+			da->pci.addr.domain, da->pci.addr.bus,
+			da->pci.addr.devid, da->pci.addr.function,
+			da->args);
+
+	return parse_device(sdev, params);
+}
+
 int
 failsafe_args_parse_subs(struct rte_eth_dev *dev)
 {
@@ -474,6 +494,8 @@ failsafe_args_parse_subs(struct rte_eth_dev *dev)
 			continue;
 		if (sdev->cmdline)
 			ret = execute_cmd(sdev, sdev->cmdline);
+		else
+			ret = parse_sub_device(sdev);
 		if (ret == 0)
 			sdev->state = DEV_PARSED;
 	}
drivers/net/failsafe/failsafe_eal.c +2 -0
index 9817fc9..8bb8d45 100644
@@ -140,6 +140,7 @@ dev_init(struct rte_eth_dev *dev)
 			}
 			ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 			SUB_ID(sdev) = i;
+			sdev->fs_dev = dev;
 			sdev->state = DEV_PROBED;
 		}
 	}
@@ -191,6 +192,7 @@ pci_probe(struct rte_eth_dev *dev)
 			}
 			ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 			SUB_ID(sdev) = i;
+			sdev->fs_dev = dev;
 			sdev->state = DEV_PROBED;
 		}
 	}
drivers/net/failsafe/failsafe_ether.c +66 -1

88 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +21 -0
index 2a4d102..8d0e7a2 100644
@@ -198,8 +198,19 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
+		int rmv_interrupt = 0;
+
 		if (sdev->state != DEV_PROBED)
 			continue;
+
+		rmv_interrupt = ETH(sdev)->data->dev_flags &
+				RTE_ETH_DEV_INTR_RMV;
+		if (rmv_interrupt) {
+			DEBUG("Enabling RMV interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.rmv = 1;
+		} else {
+			DEBUG("sub_device %d does not support RMV event", i);
+		}
 		DEBUG("Configuring sub-device %d", i);
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
 					dev->data->nb_rx_queues,
@@ -209,6 +220,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 			ERROR("Could not configure sub_device %d", i);
 			return ret;
 		}
+		if (rmv_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+					RTE_ETH_EVENT_INTR_RMV,
+					failsafe_eth_rmv_event_callback,
+					sdev);
+			if (ret)
+				WARN("Failed to register RMV callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.rmv = 0;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
drivers/net/failsafe/failsafe_private.h +7 -0
index faf0e71..5efd084 100644
@@ -53,6 +53,7 @@
 	""
 
 #define FAILSAFE_PLUGIN_DEFAULT_TIMEOUT_MS 2000
+#define FAILSAFE_PLUGOUT_ASYNC_RESCHED_US 100000
 
 #define FAILSAFE_MAX_ETHPORTS (RTE_MAX_ETHPORTS - 1)
 #define FAILSAFE_MAX_ETHADDR 128
@@ -108,6 +109,9 @@ struct sub_device {
 	enum dev_state state;
 	/* Some device are defined as a command line */
 	char *cmdline;
+
+	/* fail-safe device backreference */
+	struct rte_eth_dev *fs_dev;
 };
 
 struct fs_priv {
@@ -175,6 +179,9 @@ int failsafe_eal_uninit(struct rte_eth_dev *dev);
 /* ETH_DEV */
 
 int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);
+void failsafe_eth_rmv_event_callback(uint8_t port_id,
+				     enum rte_eth_event_type type,
+				     void *arg);
 
 /* GLOBALS */
 
Signature · 1 line
2.1.4
#48 lore raw

PATCH v2 13/13 net/failsafe: support link status change event

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |  1 +
 drivers/net/failsafe/failsafe.c         |  1 +
 drivers/net/failsafe/failsafe_ether.c   | 18 ++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     | 24 ++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h |  3 +++
 5 files changed, 47 insertions(+)
doc/guides/nics/features/failsafe.ini +1 -0
index 257f579..251ce55 100644
@@ -5,6 +5,7 @@
 ;
 [Features]
 Link status          = Y
+Link status event    = Y
 Queue start/stop     = Y
 MTU update           = Y
 Jumbo frame          = Y
drivers/net/failsafe/failsafe.c +1 -0
index 6151736..f885c19 100644
@@ -238,6 +238,7 @@ eth_dev_create(const char *name,
 		mac->addr_bytes[0], mac->addr_bytes[1],
 		mac->addr_bytes[2], mac->addr_bytes[3],
 		mac->addr_bytes[4], mac->addr_bytes[5]);
+	dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
 	return 0;
 free_args:
 	failsafe_args_free(dev);
drivers/net/failsafe/failsafe_ether.c +18 -0
index f12b8d7..5c2e118 100644
@@ -374,3 +374,21 @@ failsafe_eth_rmv_event_callback(uint8_t port_id __rte_unused,
 			      cb_arg))
 		ERROR("Could not set up deferred sub_device removal");
 }
+
+void
+failsafe_eth_lsc_event_callback(uint8_t port_id __rte_unused,
+				enum rte_eth_event_type event,
+				void *cb_arg)
+{
+	struct rte_eth_dev *dev = cb_arg;
+	int ret;
+
+	if (event != RTE_ETH_EVENT_INTR_LSC) {
+		ERROR("Incorrect event");
+		return;
+	}
+	ret = dev->dev_ops->link_update(dev, 0);
+	/* We must pass on the LSC event */
+	if (ret)
+		_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
+}
drivers/net/failsafe/failsafe_ops.c +24 -0
index 8d0e7a2..695e7b3 100644
@@ -199,6 +199,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
 		int rmv_interrupt = 0;
+		int lsc_interrupt = 0;
+		int lsc_enabled;
 
 		if (sdev->state != DEV_PROBED)
 			continue;
@@ -211,6 +213,18 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		} else {
 			DEBUG("sub_device %d does not support RMV event", i);
 		}
+
+		lsc_enabled = dev->data->dev_conf.intr_conf.lsc;
+		lsc_interrupt = lsc_enabled &&
+				(ETH(sdev)->data->dev_flags &
+				 RTE_ETH_DEV_INTR_LSC);
+		if (lsc_interrupt) {
+			DEBUG("Enabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 1;
+		} else if (lsc_enabled && !lsc_interrupt) {
+			DEBUG("Disabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 0;
+		}
 		DEBUG("Configuring sub-device %d", i);
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
 					dev->data->nb_rx_queues,
@@ -230,6 +244,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 				     SUB_ID(sdev));
 		}
 		dev->data->dev_conf.intr_conf.rmv = 0;
+		if (lsc_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+							RTE_ETH_EVENT_INTR_LSC,
+							failsafe_eth_lsc_event_callback,
+							dev);
+			if (ret)
+				WARN("Failed to register LSC callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.lsc = lsc_enabled;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
drivers/net/failsafe/failsafe_private.h +3 -0
index 5efd084..27e2a0c 100644
@@ -182,6 +182,9 @@ int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);
 void failsafe_eth_rmv_event_callback(uint8_t port_id,
 				     enum rte_eth_event_type type,
 				     void *arg);
+void failsafe_eth_lsc_event_callback(uint8_t port_id,
+				     enum rte_eth_event_type event,
+				     void *cb_arg);
 
 /* GLOBALS */
 
Signature · 1 line
2.1.4