Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 18 Apr 2013 19:52:12 +0000 (UTC)
From:      Navdeep Parhar <np@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r249627 - head/sys/dev/cxgbe/tom
Message-ID:  <201304181952.r3IJqCr6085467@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: np
Date: Thu Apr 18 19:52:11 2013
New Revision: 249627
URL: http://svnweb.freebsd.org/changeset/base/249627

Log:
  cxgbe/tom: Update the CLIP table on the chip when there are changes
  to the list of IPv6 addresses on the system.  The table is used for
  TOE+IPv6 only.

Modified:
  head/sys/dev/cxgbe/tom/t4_tom.c
  head/sys/dev/cxgbe/tom/t4_tom.h

Modified: head/sys/dev/cxgbe/tom/t4_tom.c
==============================================================================
--- head/sys/dev/cxgbe/tom/t4_tom.c	Thu Apr 18 18:11:30 2013	(r249626)
+++ head/sys/dev/cxgbe/tom/t4_tom.c	Thu Apr 18 19:52:11 2013	(r249627)
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/domain.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
+#include <sys/taskqueue.h>
 #include <net/if.h>
 #include <netinet/in.h>
 #include <netinet/in_pcb.h>
@@ -89,9 +90,16 @@ static int add_lip(struct adapter *, str
 static int delete_lip(struct adapter *, struct in6_addr *);
 static struct clip_entry *search_lip(struct tom_data *, struct in6_addr *);
 static void init_clip_table(struct adapter *, struct tom_data *);
+static void update_clip(struct adapter *, void *);
+static void t4_clip_task(void *, int);
+static void update_clip_table(struct adapter *, struct tom_data *);
 static void destroy_clip_table(struct adapter *, struct tom_data *);
 static void free_tom_data(struct adapter *, struct tom_data *);
 
+static int in6_ifaddr_gen;
+static eventhandler_tag ifaddr_evhandler;
+static struct timeout_task clip_task;
+
 struct toepcb *
 alloc_toepcb(struct port_info *pi, int txqid, int rxqid, int flags)
 {
@@ -626,7 +634,7 @@ add_lip(struct adapter *sc, struct in6_a
         c.ip_hi = *(uint64_t *)&lip->s6_addr[0];
         c.ip_lo = *(uint64_t *)&lip->s6_addr[8];
 
-	return (t4_wr_mbox_ns(sc, sc->mbox, &c, sizeof(c), &c));
+	return (-t4_wr_mbox_ns(sc, sc->mbox, &c, sizeof(c), &c));
 }
 
 static int
@@ -644,7 +652,7 @@ delete_lip(struct adapter *sc, struct in
         c.ip_hi = *(uint64_t *)&lip->s6_addr[0];
         c.ip_lo = *(uint64_t *)&lip->s6_addr[8];
 
-	return (t4_wr_mbox_ns(sc, sc->mbox, &c, sizeof(c), &c));
+	return (-t4_wr_mbox_ns(sc, sc->mbox, &c, sizeof(c), &c));
 }
 
 static struct clip_entry *
@@ -692,16 +700,56 @@ release_lip(struct tom_data *td, struct 
 static void
 init_clip_table(struct adapter *sc, struct tom_data *td)
 {
-	struct in6_ifaddr *ia;
-	struct in6_addr *lip, tlip;
-	struct clip_entry *ce;
 
 	ASSERT_SYNCHRONIZED_OP(sc);
 
 	mtx_init(&td->clip_table_lock, "CLIP table lock", NULL, MTX_DEF);
 	TAILQ_INIT(&td->clip_table);
+	td->clip_gen = -1;
+
+	update_clip_table(sc, td);
+}
+
+static void
+update_clip(struct adapter *sc, void *arg __unused)
+{
+
+	if (begin_synchronized_op(sc, NULL, HOLD_LOCK, "t4tomuc"))
+		return;
+
+	if (sc->flags & TOM_INIT_DONE)
+		update_clip_table(sc, sc->tom_softc);
+
+	end_synchronized_op(sc, LOCK_HELD);
+}
+
+static void
+t4_clip_task(void *arg, int count)
+{
+
+	t4_iterate(update_clip, NULL);
+}
+
+static void
+update_clip_table(struct adapter *sc, struct tom_data *td)
+{
+	struct in6_ifaddr *ia;
+	struct in6_addr *lip, tlip;
+	struct clip_head stale;
+	struct clip_entry *ce, *ce_temp;
+	int rc, gen = atomic_load_acq_int(&in6_ifaddr_gen);
+
+	ASSERT_SYNCHRONIZED_OP(sc);
 
 	IN6_IFADDR_RLOCK();
+	mtx_lock(&td->clip_table_lock);
+
+	if (gen == td->clip_gen)
+		goto done;
+
+	TAILQ_INIT(&stale);
+	TAILQ_CONCAT(&stale, &td->clip_table, link);
+
 	TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
 		lip = &ia->ia_addr.sin6_addr;
 
@@ -721,18 +769,70 @@ init_clip_table(struct adapter *sc, stru
 		 * interface?  It's fe80::1 usually (always?).
 		 */
 
-		mtx_lock(&td->clip_table_lock);
-		if (search_lip(td, lip) == NULL) {
-			ce = malloc(sizeof(*ce), M_CXGBE, M_NOWAIT);
-			memcpy(&ce->lip, lip, sizeof(ce->lip));
-			ce->refcount = 0;
-			if (add_lip(sc, lip) == 0)
+		/*
+		 * If it's in the main list then we already know it's not stale.
+		 */
+		TAILQ_FOREACH(ce, &td->clip_table, link) {
+			if (IN6_ARE_ADDR_EQUAL(&ce->lip, lip))
+				goto next;
+		}
+
+		/*
+		 * If it's in the stale list we should move it to the main list.
+		 */
+		TAILQ_FOREACH(ce, &stale, link) {
+			if (IN6_ARE_ADDR_EQUAL(&ce->lip, lip)) {
+				TAILQ_REMOVE(&stale, ce, link);
 				TAILQ_INSERT_TAIL(&td->clip_table, ce, link);
-			else
+				goto next;
+			}
+		}
+
+		/* A new IP6 address; add it to the CLIP table */
+		ce = malloc(sizeof(*ce), M_CXGBE, M_NOWAIT);
+		memcpy(&ce->lip, lip, sizeof(ce->lip));
+		ce->refcount = 0;
+		rc = add_lip(sc, lip);
+		if (rc == 0)
+			TAILQ_INSERT_TAIL(&td->clip_table, ce, link);
+		else {
+			char ip[INET6_ADDRSTRLEN];
+
+			inet_ntop(AF_INET6, &ce->lip, &ip[0], sizeof(ip));
+			log(LOG_ERR, "%s: could not add %s (%d)\n",
+			    __func__, ip, rc);
+			free(ce, M_CXGBE);
+		}
+next:
+		continue;
+	}
+
+	/*
+	 * Remove stale addresses (those no longer in V_in6_ifaddrhead) that are
+	 * no longer referenced by the driver.
+	 */
+	TAILQ_FOREACH_SAFE(ce, &stale, link, ce_temp) {
+		if (ce->refcount == 0) {
+			rc = delete_lip(sc, &ce->lip);
+			if (rc == 0) {
+				TAILQ_REMOVE(&stale, ce, link);
 				free(ce, M_CXGBE);
+			} else {
+				char ip[INET6_ADDRSTRLEN];
+
+				inet_ntop(AF_INET6, &ce->lip, &ip[0],
+				    sizeof(ip));
+				log(LOG_ERR, "%s: could not delete %s (%d)\n",
+				    __func__, ip, rc);
+			}
 		}
-		mtx_unlock(&td->clip_table_lock);
 	}
+	/* The ones that are still referenced need to stay in the CLIP table */
+	TAILQ_CONCAT(&td->clip_table, &stale, link);
+
+	td->clip_gen = gen;
+done:
+	mtx_unlock(&td->clip_table_lock);
 	IN6_IFADDR_RUNLOCK();
 }
 
@@ -893,6 +993,14 @@ t4_tom_deactivate(struct adapter *sc)
 	return (rc);
 }
 
+static void
+t4_tom_ifaddr_event(void *arg __unused, struct ifnet *ifp)
+{
+
+	atomic_add_rel_int(&in6_ifaddr_gen, 1);
+	taskqueue_enqueue_timeout(taskqueue_thread, &clip_task, -hz / 4);
+}
+
 static int
 t4_tom_mod_load(void)
 {
@@ -915,6 +1023,10 @@ t4_tom_mod_load(void)
 	ddp6_usrreqs.pru_soreceive = t4_soreceive_ddp;
 	ddp6_protosw.pr_usrreqs = &ddp6_usrreqs;
 
+	TIMEOUT_TASK_INIT(taskqueue_thread, &clip_task, 0, t4_clip_task, NULL);
+	ifaddr_evhandler = EVENTHANDLER_REGISTER(ifaddr_event,
+	    t4_tom_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY);
+
 	rc = t4_register_uld(&tom_uld_info);
 	if (rc != 0)
 		t4_tom_mod_unload();
@@ -943,6 +1055,11 @@ t4_tom_mod_unload(void)
 	if (t4_unregister_uld(&tom_uld_info) == EBUSY)
 		return (EBUSY);
 
+	if (ifaddr_evhandler) {
+		EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_evhandler);
+		taskqueue_cancel_timeout(taskqueue_thread, &clip_task, NULL);
+	}
+
 	return (0);
 }
 #endif	/* TCP_OFFLOAD */

Modified: head/sys/dev/cxgbe/tom/t4_tom.h
==============================================================================
--- head/sys/dev/cxgbe/tom/t4_tom.h	Thu Apr 18 18:11:30 2013	(r249626)
+++ head/sys/dev/cxgbe/tom/t4_tom.h	Thu Apr 18 19:52:11 2013	(r249627)
@@ -182,6 +182,7 @@ struct clip_entry {
 	u_int refcount;
 };
 
+TAILQ_HEAD(clip_head, clip_entry);
 struct tom_data {
 	struct toedev tod;
 
@@ -201,7 +202,8 @@ struct tom_data {
 	struct ppod_head ppods;
 
 	struct mtx clip_table_lock;
-	TAILQ_HEAD(, clip_entry) clip_table;
+	struct clip_head clip_table;
+	int clip_gen;
 };
 
 static inline struct tom_data *



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201304181952.r3IJqCr6085467>