svn commit: r245434 - in head/sys: dev/cxgbe dev/cxgbe/common dev/cxgbe/tom modules/cxgbe/tom

Navdeep Parhar np at FreeBSD.org
Mon Jan 14 20:36:24 UTC 2013


Author: np
Date: Mon Jan 14 20:36:22 2013
New Revision: 245434
URL: http://svnweb.freebsd.org/changeset/base/245434

Log:
  cxgbe(4): Updates to the hardware L2 table management code.
  
  - Add full support for IPv6 addresses.
  
  - Read the size of the L2 table during attach.  Do not assume that PCIe
    physical function 4 of the card has all of the table to itself.
  
  - Use FNV instead of Jenkins to hash L3 addresses and drop the private
    copy of jhash.h from the driver.
  
  MFC after:	1 week

Deleted:
  head/sys/dev/cxgbe/common/jhash.h
Modified:
  head/sys/dev/cxgbe/offload.h
  head/sys/dev/cxgbe/t4_l2t.c
  head/sys/dev/cxgbe/t4_l2t.h
  head/sys/dev/cxgbe/t4_main.c
  head/sys/dev/cxgbe/tom/t4_tom_l2t.c
  head/sys/modules/cxgbe/tom/Makefile

Modified: head/sys/dev/cxgbe/offload.h
==============================================================================
--- head/sys/dev/cxgbe/offload.h	Mon Jan 14 20:31:45 2013	(r245433)
+++ head/sys/dev/cxgbe/offload.h	Mon Jan 14 20:36:22 2013	(r245434)
@@ -104,8 +104,8 @@ struct tid_info {
 };
 
 struct t4_range {
-	unsigned int start;
-	unsigned int size;
+	u_int start;
+	u_int size;
 };
 
 struct t4_virt_res {                      /* virtualized HW resources */
@@ -117,6 +117,7 @@ struct t4_virt_res {                    
 	struct t4_range qp;
 	struct t4_range cq;
 	struct t4_range ocq;
+	struct t4_range l2t;
 };
 
 #ifdef TCP_OFFLOAD

Modified: head/sys/dev/cxgbe/t4_l2t.c
==============================================================================
--- head/sys/dev/cxgbe/t4_l2t.c	Mon Jan 14 20:31:45 2013	(r245433)
+++ head/sys/dev/cxgbe/t4_l2t.c	Mon Jan 14 20:36:22 2013	(r245434)
@@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
 #include <netinet/in.h>
 
 #include "common/common.h"
-#include "common/jhash.h"
 #include "common/t4_msg.h"
 #include "t4_l2t.h"
 
@@ -78,7 +77,7 @@ t4_alloc_l2e(struct l2t_data *d)
 		return (NULL);
 
 	/* there's definitely a free entry */
-	for (e = d->rover, end = &d->l2tab[L2T_SIZE]; e != end; ++e)
+	for (e = d->rover, end = &d->l2tab[d->l2t_size]; e != end; ++e)
 		if (atomic_load_acq_int(&e->refcnt) == 0)
 			goto found;
 
@@ -115,6 +114,7 @@ t4_write_l2e(struct adapter *sc, struct 
 {
 	struct wrqe *wr;
 	struct cpl_l2t_write_req *req;
+	int idx = e->idx + sc->vres.l2t.start;
 
 	mtx_assert(&e->lock, MA_OWNED);
 
@@ -124,10 +124,10 @@ t4_write_l2e(struct adapter *sc, struct 
 	req = wrtod(wr);
 
 	INIT_TP_WR(req, 0);
-	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx |
+	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, idx |
 	    V_SYNC_WR(sync) | V_TID_QID(sc->sge.fwq.abs_id)));
 	req->params = htons(V_L2T_W_PORT(e->lport) | V_L2T_W_NOREPLY(!sync));
-	req->l2t_idx = htons(e->idx);
+	req->l2t_idx = htons(idx);
 	req->vlan = htons(e->vlan);
 	memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
 
@@ -183,18 +183,24 @@ t4_l2t_set_switching(struct adapter *sc,
 int
 t4_init_l2t(struct adapter *sc, int flags)
 {
-	int i;
+	int i, l2t_size;
 	struct l2t_data *d;
 
-	d = malloc(sizeof(*d), M_CXGBE, M_ZERO | flags);
+	l2t_size = sc->vres.l2t.size;
+	if (l2t_size < 2)	/* At least 1 bucket for IP and 1 for IPv6 */
+		return (EINVAL);
+
+	d = malloc(sizeof(*d) + l2t_size * sizeof (struct l2t_entry), M_CXGBE,
+	    M_ZERO | flags);
 	if (!d)
 		return (ENOMEM);
 
+	d->l2t_size = l2t_size;
 	d->rover = d->l2tab;
-	atomic_store_rel_int(&d->nfree, L2T_SIZE);
+	atomic_store_rel_int(&d->nfree, l2t_size);
 	rw_init(&d->lock, "L2T");
 
-	for (i = 0; i < L2T_SIZE; i++) {
+	for (i = 0; i < l2t_size; i++) {
 		struct l2t_entry *e = &d->l2tab[i];
 
 		e->idx = i;
@@ -215,7 +221,7 @@ t4_free_l2t(struct l2t_data *d)
 {
 	int i;
 
-	for (i = 0; i < L2T_SIZE; i++)
+	for (i = 0; i < d->l2t_size; i++)
 		mtx_destroy(&d->l2tab[i].lock);
 	rw_destroy(&d->lock);
 	free(d, M_CXGBE);
@@ -229,11 +235,11 @@ do_l2t_write_rpl(struct sge_iq *iq, cons
 {
 	const struct cpl_l2t_write_rpl *rpl = (const void *)(rss + 1);
 	unsigned int tid = GET_TID(rpl);
-	unsigned int idx = tid & (L2T_SIZE - 1);
+	unsigned int idx = tid % L2T_SIZE;
 
 	if (__predict_false(rpl->status != CPL_ERR_NONE)) {
 		log(LOG_ERR,
-		    "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
+		    "Unexpected L2T_WRITE_RPL (%u) for entry at hw_idx %u\n",
 		    rpl->status, idx);
 		return (EINVAL);
 	}
@@ -269,7 +275,7 @@ sysctl_l2t(SYSCTL_HANDLER_ARGS)
 	struct l2t_entry *e;
 	struct sbuf *sb;
 	int rc, i, header = 0;
-	char ip[60];
+	char ip[INET6_ADDRSTRLEN];
 
 	if (l2t == NULL)
 		return (ENXIO);
@@ -283,7 +289,7 @@ sysctl_l2t(SYSCTL_HANDLER_ARGS)
 		return (ENOMEM);
 
 	e = &l2t->l2tab[0];
-	for (i = 0; i < L2T_SIZE; i++, e++) {
+	for (i = 0; i < l2t->l2t_size; i++, e++) {
 		mtx_lock(&e->lock);
 		if (e->state == L2T_STATE_UNUSED)
 			goto skip;
@@ -295,11 +301,15 @@ sysctl_l2t(SYSCTL_HANDLER_ARGS)
 		}
 		if (e->state == L2T_STATE_SWITCHING)
 			ip[0] = 0;
-		else
-			snprintf(ip, sizeof(ip), "%s",
-			    inet_ntoa(*(struct in_addr *)&e->addr));
+		else {
+			inet_ntop(e->ipv6 ? AF_INET6 : AF_INET, &e->addr[0],
+			    &ip[0], sizeof(ip));
+		}
 
-		/* XXX: e->ifp may not be around */
+		/*
+		 * XXX: e->ifp may not be around.
+		 * XXX: IPv6 addresses may not align properly in the output.
+		 */
 		sbuf_printf(sb, "\n%4u %-15s %02x:%02x:%02x:%02x:%02x:%02x %4d"
 			   " %u %2u   %c   %5u %s",
 			   e->idx, ip, e->dmac[0], e->dmac[1], e->dmac[2],

Modified: head/sys/dev/cxgbe/t4_l2t.h
==============================================================================
--- head/sys/dev/cxgbe/t4_l2t.h	Mon Jan 14 20:31:45 2013	(r245433)
+++ head/sys/dev/cxgbe/t4_l2t.h	Mon Jan 14 20:36:22 2013	(r245434)
@@ -60,7 +60,7 @@ enum {
 struct l2t_entry {
 	uint16_t state;			/* entry state */
 	uint16_t idx;			/* entry index */
-	uint32_t addr;			/* next hop IP address */
+	uint32_t addr[4];		/* next hop IP or IPv6 address */
 	struct ifnet *ifp;		/* outgoing interface */
 	uint16_t smt_idx;		/* SMT index */
 	uint16_t vlan;			/* VLAN TCI (id: 0-11, prio: 13-15) */
@@ -70,15 +70,17 @@ struct l2t_entry {
 	struct mtx lock;
 	volatile int refcnt;		/* entry reference count */
 	uint16_t hash;			/* hash bucket the entry is on */
+	uint8_t ipv6;			/* entry is for an IPv6 address */
 	uint8_t lport;			/* associated offload logical port */
 	uint8_t dmac[ETHER_ADDR_LEN];	/* next hop's MAC address */
 };
 
 struct l2t_data {
 	struct rwlock lock;
+	u_int l2t_size;
 	volatile int nfree;	/* number of free entries */
 	struct l2t_entry *rover;/* starting point for next allocation */
-	struct l2t_entry l2tab[L2T_SIZE];
+	struct l2t_entry l2tab[];
 };
 
 

Modified: head/sys/dev/cxgbe/t4_main.c
==============================================================================
--- head/sys/dev/cxgbe/t4_main.c	Mon Jan 14 20:31:45 2013	(r245433)
+++ head/sys/dev/cxgbe/t4_main.c	Mon Jan 14 20:36:22 2013	(r245434)
@@ -1866,7 +1866,9 @@ get_params__post_init(struct adapter *sc
 	param[1] = FW_PARAM_PFVF(EQ_START);
 	param[2] = FW_PARAM_PFVF(FILTER_START);
 	param[3] = FW_PARAM_PFVF(FILTER_END);
-	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 4, param, val);
+	param[4] = FW_PARAM_PFVF(L2T_START);
+	param[5] = FW_PARAM_PFVF(L2T_END);
+	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
 	if (rc != 0) {
 		device_printf(sc->dev,
 		    "failed to query parameters (post_init): %d.\n", rc);
@@ -1877,6 +1879,11 @@ get_params__post_init(struct adapter *sc
 	sc->sge.eq_start = val[1];
 	sc->tids.ftid_base = val[2];
 	sc->tids.nftids = val[3] - val[2] + 1;
+	sc->vres.l2t.start = val[4];
+	sc->vres.l2t.size = val[5] - val[4] + 1;
+	KASSERT(sc->vres.l2t.size <= L2T_SIZE,
+	    ("%s: L2 table size (%u) larger than expected (%u)",
+	    __func__, sc->vres.l2t.size, L2T_SIZE));
 
 	/* get capabilites */
 	bzero(&caps, sizeof(caps));

Modified: head/sys/dev/cxgbe/tom/t4_tom_l2t.c
==============================================================================
--- head/sys/dev/cxgbe/tom/t4_tom_l2t.c	Mon Jan 14 20:31:45 2013	(r245433)
+++ head/sys/dev/cxgbe/tom/t4_tom_l2t.c	Mon Jan 14 20:36:22 2013	(r245434)
@@ -27,6 +27,7 @@
 __FBSDID("$FreeBSD$");
 
 #include "opt_inet.h"
+#include "opt_inet6.h"
 
 #ifdef TCP_OFFLOAD
 #include <sys/param.h>
@@ -34,6 +35,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/module.h>
 #include <sys/bus.h>
+#include <sys/fnv_hash.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/rwlock.h>
@@ -48,28 +50,89 @@ __FBSDID("$FreeBSD$");
 #include <netinet/toecore.h>
 
 #include "common/common.h"
-#include "common/jhash.h"
 #include "common/t4_msg.h"
 #include "tom/t4_tom_l2t.h"
 #include "tom/t4_tom.h"
 
 #define VLAN_NONE	0xfff
 
-#define SA(x)           ((struct sockaddr *)(x))
-#define SIN(x)          ((struct sockaddr_in *)(x))
-#define SINADDR(x)      (SIN(x)->sin_addr.s_addr)
-
 static inline void
 l2t_hold(struct l2t_data *d, struct l2t_entry *e)
 {
+
 	if (atomic_fetchadd_int(&e->refcnt, 1) == 0)  /* 0 -> 1 transition */
 		atomic_subtract_int(&d->nfree, 1);
 }
 
-static inline unsigned int
-arp_hash(const uint32_t key, int ifindex)
+static inline u_int
+l2_hash(struct l2t_data *d, const struct sockaddr *sa, int ifindex)
+{
+	u_int hash, half = d->l2t_size / 2, start = 0;
+	const void *key;
+	size_t len;
+
+	KASSERT(sa->sa_family == AF_INET || sa->sa_family == AF_INET6,
+	    ("%s: sa %p has unexpected sa_family %d", __func__, sa,
+	    sa->sa_family));
+
+	if (sa->sa_family == AF_INET) {
+		const struct sockaddr_in *sin = (const void *)sa;
+
+		key = &sin->sin_addr;
+		len = sizeof(sin->sin_addr);
+	} else {
+		const struct sockaddr_in6 *sin6 = (const void *)sa;
+
+		key = &sin6->sin6_addr;
+		len = sizeof(sin6->sin6_addr);
+		start = half;
+	}
+
+	hash = fnv_32_buf(key, len, FNV1_32_INIT);
+	hash = fnv_32_buf(&ifindex, sizeof(ifindex), hash);
+	hash %= half;
+
+	return (hash + start);
+}
+
+static inline int
+l2_cmp(const struct sockaddr *sa, struct l2t_entry *e)
+{
+
+	KASSERT(sa->sa_family == AF_INET || sa->sa_family == AF_INET6,
+	    ("%s: sa %p has unexpected sa_family %d", __func__, sa,
+	    sa->sa_family));
+
+	if (sa->sa_family == AF_INET) {
+		const struct sockaddr_in *sin = (const void *)sa;
+
+		return (e->addr[0] != sin->sin_addr.s_addr);
+	} else {
+		const struct sockaddr_in6 *sin6 = (const void *)sa;
+
+		return (memcmp(&e->addr[0], &sin6->sin6_addr, sizeof(e->addr)));
+	}
+}
+
+static inline void
+l2_store(const struct sockaddr *sa, struct l2t_entry *e)
 {
-	return jhash_2words(key, ifindex, 0) & (L2T_SIZE - 1);
+
+	KASSERT(sa->sa_family == AF_INET || sa->sa_family == AF_INET6,
+	    ("%s: sa %p has unexpected sa_family %d", __func__, sa,
+	    sa->sa_family));
+
+	if (sa->sa_family == AF_INET) {
+		const struct sockaddr_in *sin = (const void *)sa;
+
+		e->addr[0] = sin->sin_addr.s_addr;
+		e->ipv6 = 0;
+	} else {
+		const struct sockaddr_in6 *sin6 = (const void *)sa;
+
+		memcpy(&e->addr[0], &sin6->sin6_addr, sizeof(e->addr));
+		e->ipv6 = 1;
+	}
 }
 
 /*
@@ -100,7 +163,7 @@ send_pending(struct adapter *sc, struct 
 static void
 resolution_failed_for_wr(struct wrqe *wr)
 {
-	log(LOG_ERR, "%s: leaked work request %p, wr_len %d", __func__, wr,
+	log(LOG_ERR, "%s: leaked work request %p, wr_len %d\n", __func__, wr,
 	    wr->wr_len);
 
 	/* free(wr, M_CXGBE); */
@@ -175,15 +238,25 @@ resolve_entry(struct adapter *sc, struct
 	struct tom_data *td = sc->tom_softc;
 	struct toedev *tod = &td->tod;
 	struct sockaddr_in sin = {0};
+	struct sockaddr_in6 sin6 = {0};
+	struct sockaddr *sa;
 	uint8_t dmac[ETHER_ADDR_LEN];
 	uint16_t vtag = VLAN_NONE;
 	int rc;
 
-	sin.sin_family = AF_INET;
-	sin.sin_len = sizeof(struct sockaddr_in);
-	SINADDR(&sin) = e->addr;
+	if (e->ipv6 == 0) {
+		sin.sin_family = AF_INET;
+		sin.sin_len = sizeof(struct sockaddr_in);
+		sin.sin_addr.s_addr = e->addr[0];
+		sa = (void *)&sin;
+	} else {
+		sin6.sin6_family = AF_INET6;
+		sin6.sin6_len = sizeof(struct sockaddr_in6);
+		memcpy(&sin6.sin6_addr, &e->addr[0], sizeof(e->addr));
+		sa = (void *)&sin6;
+	}
 
-	rc = toe_l2_resolve(tod, e->ifp, SA(&sin), dmac, &vtag);
+	rc = toe_l2_resolve(tod, e->ifp, sa, dmac, &vtag);
 	if (rc == EWOULDBLOCK)
 		return (rc);
 
@@ -263,7 +336,7 @@ do_l2t_write_rpl2(struct sge_iq *iq, con
 	struct adapter *sc = iq->adapter;
 	const struct cpl_l2t_write_rpl *rpl = (const void *)(rss + 1);
 	unsigned int tid = GET_TID(rpl);
-	unsigned int idx = tid & (L2T_SIZE - 1);
+	unsigned int idx = tid % L2T_SIZE;
 	int rc;
 
 	rc = do_l2t_write_rpl(iq, rss, m);
@@ -271,7 +344,7 @@ do_l2t_write_rpl2(struct sge_iq *iq, con
 		return (rc);
 
 	if (tid & F_SYNC_WR) {
-		struct l2t_entry *e = &sc->l2t->l2tab[idx];
+		struct l2t_entry *e = &sc->l2t->l2tab[idx - sc->vres.l2t.start];
 
 		mtx_lock(&e->lock);
 		if (e->state != L2T_STATE_SWITCHING) {
@@ -310,21 +383,22 @@ t4_l2t_get(struct port_info *pi, struct 
 {
 	struct l2t_entry *e;
 	struct l2t_data *d = pi->adapter->l2t;
-	uint32_t addr = SINADDR(sa);
-	int hash = arp_hash(addr, ifp->if_index);
-	unsigned int smt_idx = pi->port_id;
+	u_int hash, smt_idx = pi->port_id;
 
-	if (sa->sa_family != AF_INET)
-		return (NULL);	/* XXX: no IPv6 support right now */
+	KASSERT(sa->sa_family == AF_INET || sa->sa_family == AF_INET6,
+	    ("%s: sa %p has unexpected sa_family %d", __func__, sa,
+	    sa->sa_family));
 
 #ifndef VLAN_TAG
 	if (ifp->if_type == IFT_L2VLAN)
 		return (NULL);
 #endif
 
+	hash = l2_hash(d, sa, ifp->if_index);
 	rw_wlock(&d->lock);
 	for (e = d->l2tab[hash].first; e; e = e->next) {
-		if (e->addr == addr && e->ifp == ifp && e->smt_idx == smt_idx) {
+		if (l2_cmp(sa, e) == 0 && e->ifp == ifp &&
+		    e->smt_idx == smt_idx) {
 			l2t_hold(d, e);
 			goto done;
 		}
@@ -338,7 +412,7 @@ t4_l2t_get(struct port_info *pi, struct 
 		d->l2tab[hash].first = e;
 
 		e->state = L2T_STATE_RESOLVING;
-		e->addr = addr;
+		l2_store(sa, e);
 		e->ifp = ifp;
 		e->smt_idx = smt_idx;
 		e->hash = hash;
@@ -368,14 +442,14 @@ t4_l2_update(struct toedev *tod, struct 
 	struct adapter *sc = tod->tod_softc;
 	struct l2t_entry *e;
 	struct l2t_data *d = sc->l2t;
-	uint32_t addr = SINADDR(sa);
-	int hash = arp_hash(addr, ifp->if_index);
+	u_int hash;
 
 	KASSERT(d != NULL, ("%s: no L2 table", __func__));
 
+	hash = l2_hash(d, sa, ifp->if_index);
 	rw_rlock(&d->lock);
 	for (e = d->l2tab[hash].first; e; e = e->next) {
-		if (e->addr == addr && e->ifp == ifp) {
+		if (l2_cmp(sa, e) == 0 && e->ifp == ifp) {
 			mtx_lock(&e->lock);
 			if (atomic_load_acq_int(&e->refcnt))
 				goto found;

Modified: head/sys/modules/cxgbe/tom/Makefile
==============================================================================
--- head/sys/modules/cxgbe/tom/Makefile	Mon Jan 14 20:31:45 2013	(r245433)
+++ head/sys/modules/cxgbe/tom/Makefile	Mon Jan 14 20:36:22 2013	(r245434)
@@ -10,15 +10,20 @@ CXGBE = ${.CURDIR}/../../../dev/cxgbe
 KMOD = t4_tom
 SRCS = t4_tom.c t4_connect.c t4_listen.c t4_cpl_io.c t4_tom_l2t.c t4_ddp.c
 SRCS+= device_if.h bus_if.h pci_if.h
-SRCS+= opt_inet.h
+SRCS+= opt_inet.h opt_inet6.h
 
 CFLAGS+= -I${CXGBE}
 
 .if !defined(KERNBUILDDIR)
 .if ${MK_INET_SUPPORT} != "no"
 opt_inet.h:
-	echo "#define INET 1" > ${.TARGET}
-	echo "#define TCP_OFFLOAD 1" >> ${.TARGET}
+	@echo "#define INET 1" > ${.TARGET}
+	@echo "#define TCP_OFFLOAD 1" >> ${.TARGET}
+.endif
+
+.if ${MK_INET6_SUPPORT} != "no"
+opt_inet6.h:
+	@echo "#define INET6 1" > ${.TARGET}
 .endif
 .endif
 


More information about the svn-src-all mailing list