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>