[2/5] net/mlx5: introduce encapsulation rules container

Message ID 1546113340-30356-3-git-send-email-viacheslavo@mellanox.com
State Accepted, archived
Delegated to: Shahaf Shuler
Headers show
Series
  • net/mlx5: simplify VXLAN devices management for E-Switch
Related show

Checks

Context Check Description
ci/Intel-compilation success Compilation OK
ci/checkpatch success coding style OK

Commit Message

Slava Ovsiienko Dec. 29, 2018, 7:55 p.m.
Currently the VXLAN encapsulation neigh/local rules
are stored in the list contained in the VTEP device
structure. Encapsulation VTEP device is attached to
outer interface and stored rules are related to this
underlying interface. We are going to use unattached
VXLAN devices for encapsulation (kernel does not use
attached interface to find egress one), so we should
introduce the structure to keep interface related
neigh/local rules instead of VTEP structure. This
patch introduces internal tcf_irule structure, and
its create/delete methods.

Signed-off-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow_tcf.c | 108 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 107 insertions(+), 1 deletion(-)

Patch

diff --git a/drivers/net/mlx5/mlx5_flow_tcf.c b/drivers/net/mlx5/mlx5_flow_tcf.c
index b4734a0..a6dca08 100644
--- a/drivers/net/mlx5/mlx5_flow_tcf.c
+++ b/drivers/net/mlx5/mlx5_flow_tcf.c
@@ -431,6 +431,15 @@  struct tcf_local_rule {
 	};
 };
 
+/** Outer interface VXLAN encapsulation rules container. */
+struct tcf_irule {
+	LIST_ENTRY(tcf_irule) next;
+	LIST_HEAD(, tcf_neigh_rule) neigh;
+	LIST_HEAD(, tcf_local_rule) local;
+	uint32_t refcnt;
+	unsigned int ifouter; /**< Own interface index. */
+};
+
 /** VXLAN virtual netdev. */
 struct tcf_vtep {
 	LIST_ENTRY(tcf_vtep) next;
@@ -458,6 +467,7 @@  struct flow_tcf_vxlan_decap {
 
 struct flow_tcf_vxlan_encap {
 	struct flow_tcf_tunnel_hdr hdr;
+	struct tcf_irule *iface;
 	uint32_t mask;
 	uint8_t ip_tos;
 	uint8_t ip_ttl_hop;
@@ -4971,11 +4981,90 @@  struct tcf_nlcb_context {
 	return 0;
 }
 
+/* VXLAN encap rule database for outer interfaces. */
+static  LIST_HEAD(, tcf_irule) iface_list_vxlan = LIST_HEAD_INITIALIZER();
+
 /* VTEP device list is shared between PMD port instances. */
 static LIST_HEAD(, tcf_vtep) vtep_list_vxlan = LIST_HEAD_INITIALIZER();
 static pthread_mutex_t vtep_list_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 /**
+ * Acquire the VXLAN encap rules container for specified interface.
+ * First looks for the container in the existing ones list, creates
+ * and initializes the new container if existing not found.
+ *
+ * @param[in] tcf
+ *   Context object initialized by mlx5_flow_tcf_context_create().
+ * @param[in] ifouter
+ *   Network interface index to create VXLAN encap rules on.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ * @return
+ *   Rule container pointer on success,
+ *   NULL otherwise and rte_errno is set.
+ */
+static struct tcf_irule*
+flow_tcf_encap_irule_acquire(struct mlx5_flow_tcf_context *tcf,
+			     unsigned int ifouter,
+			     struct rte_flow_error *error)
+{
+	struct tcf_irule *iface;
+
+	/* Look whether the container for encap rules is created. */
+	assert(ifouter);
+	LIST_FOREACH(iface, &iface_list_vxlan, next) {
+		if (iface->ifouter == ifouter)
+			break;
+	}
+	if (iface) {
+		/* Container already exists, just increment the reference. */
+		iface->refcnt++;
+		return iface;
+	}
+	/* Not found, we should create the new container. */
+	iface = rte_zmalloc(__func__, sizeof(*iface),
+			    alignof(struct tcf_irule));
+	if (!iface) {
+		rte_flow_error_set(error, ENOMEM,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "unable to allocate memory for container");
+		return NULL;
+	}
+	*iface = (struct tcf_irule){
+			.local = LIST_HEAD_INITIALIZER(),
+			.neigh = LIST_HEAD_INITIALIZER(),
+			.ifouter = ifouter,
+			.refcnt = 1,
+	};
+	/* Interface cleanup for new container created. */
+	flow_tcf_encap_iface_cleanup(tcf, ifouter);
+	flow_tcf_encap_local_cleanup(tcf, ifouter);
+	flow_tcf_encap_neigh_cleanup(tcf, ifouter);
+	LIST_INSERT_HEAD(&iface_list_vxlan, iface, next);
+	return iface;
+}
+
+/**
+ * Releases VXLAN encap rules container by pointer. Decrements the
+ * reference cointer and deletes the container if counter is zero.
+ *
+ * @param[in] irule
+ *   VXLAN rule container pointer to release.
+ */
+static void
+flow_tcf_encap_irule_release(struct tcf_irule *iface)
+{
+	assert(iface->refcnt);
+	if (--iface->refcnt == 0) {
+		/* Reference counter is zero, delete the container. */
+		assert(LIST_EMPTY(&iface->local));
+		assert(LIST_EMPTY(&iface->neigh));
+		LIST_REMOVE(iface, next);
+		rte_free(iface);
+	}
+}
+
+/**
  * Deletes VTEP network device.
  *
  * @param[in] tcf
@@ -5247,6 +5336,7 @@  struct tcf_nlcb_context {
 {
 	static uint16_t encap_port = MLX5_VXLAN_PORT_MIN - 1;
 	struct tcf_vtep *vtep;
+	struct tcf_irule *iface;
 	int ret;
 
 	assert(ifouter);
@@ -5296,6 +5386,13 @@  struct tcf_nlcb_context {
 	}
 	assert(vtep->ifouter == ifouter);
 	assert(vtep->ifindex);
+	iface = flow_tcf_encap_irule_acquire(tcf, ifouter, error);
+	if (!iface) {
+		if (--vtep->refcnt == 0)
+			flow_tcf_vtep_delete(tcf, vtep);
+		return NULL;
+	}
+	dev_flow->tcf.vxlan_encap->iface = iface;
 	/* Create local ipaddr with peer to specify the outer IPs. */
 	ret = flow_tcf_encap_local(tcf, vtep, dev_flow, true, error);
 	if (!ret) {
@@ -5306,6 +5403,8 @@  struct tcf_nlcb_context {
 					     dev_flow, false, error);
 	}
 	if (ret) {
+		dev_flow->tcf.vxlan_encap->iface = NULL;
+		flow_tcf_encap_irule_release(iface);
 		if (--vtep->refcnt == 0)
 			flow_tcf_vtep_delete(tcf, vtep);
 		return NULL;
@@ -5378,11 +5477,18 @@  struct tcf_nlcb_context {
 	switch (dev_flow->tcf.tunnel->type) {
 	case FLOW_TCF_TUNACT_VXLAN_DECAP:
 		break;
-	case FLOW_TCF_TUNACT_VXLAN_ENCAP:
+	case FLOW_TCF_TUNACT_VXLAN_ENCAP: {
+		struct tcf_irule *iface;
+
 		/* Remove the encap ancillary rules first. */
+		iface = dev_flow->tcf.vxlan_encap->iface;
+		assert(iface);
 		flow_tcf_encap_neigh(tcf, vtep, dev_flow, false, NULL);
 		flow_tcf_encap_local(tcf, vtep, dev_flow, false, NULL);
+		flow_tcf_encap_irule_release(iface);
+		dev_flow->tcf.vxlan_encap->iface = NULL;
 		break;
+	}
 	default:
 		assert(false);
 		DRV_LOG(WARNING, "Unsupported tunnel type");