Index: head/sys/conf/files =================================================================== --- head/sys/conf/files +++ head/sys/conf/files @@ -1382,6 +1382,8 @@ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/cxgb_t3fw.c optional cxgb cxgb_t3fw \ compile-with "${NORMAL_C} -I$S/dev/cxgb" +dev/cxgbe/t4_clip.c optional cxgbe pci \ + compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_filter.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_if.m optional cxgbe pci Index: head/sys/dev/cxgbe/adapter.h =================================================================== --- head/sys/dev/cxgbe/adapter.h +++ head/sys/dev/cxgbe/adapter.h @@ -771,6 +771,8 @@ const char *vf_ifnet_name; }; +struct clip_entry; + struct adapter { SLIST_ENTRY(adapter) link; device_t dev; @@ -816,6 +818,10 @@ struct taskqueue *tq[MAX_NCHAN]; /* General purpose taskqueues */ struct port_info *port[MAX_NPORTS]; uint8_t chan_map[MAX_NCHAN]; /* channel -> port */ + + struct mtx clip_table_lock; + TAILQ_HEAD(, clip_entry) clip_table; + int clip_gen; void *tom_softc; /* (struct tom_data *) */ struct tom_tunables tt; Index: head/sys/dev/cxgbe/t4_clip.h =================================================================== --- head/sys/dev/cxgbe/t4_clip.h +++ head/sys/dev/cxgbe/t4_clip.h @@ -0,0 +1,51 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2012 Chelsio Communications, Inc. + * All rights reserved. + * Written by: Navdeep Parhar + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __T4_CLIP_H +#define __T4_CLIP_H + +struct clip_entry { + TAILQ_ENTRY(clip_entry) link; + struct in6_addr lip; /* local IPv6 address */ + u_int refcount; +}; + +void t4_clip_modload(void); +void t4_clip_modunload(void); +void t4_init_clip_table(struct adapter *); +void t4_destroy_clip_table(struct adapter *); +struct clip_entry *t4_hold_lip(struct adapter *, struct in6_addr *, + struct clip_entry *); +void t4_release_lip(struct adapter *, struct clip_entry *); + +int sysctl_clip(SYSCTL_HANDLER_ARGS); + +#endif /* __T4_CLIP_H */ Index: head/sys/dev/cxgbe/t4_clip.c =================================================================== --- head/sys/dev/cxgbe/t4_clip.c +++ head/sys/dev/cxgbe/t4_clip.c @@ -0,0 +1,382 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2012 Chelsio Communications, Inc. + * All rights reserved. + * Written by: Navdeep Parhar + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/common.h" +#include "t4_clip.h" + +static int add_lip(struct adapter *, struct in6_addr *); +static int delete_lip(struct adapter *, struct in6_addr *); +static struct clip_entry *search_lip(struct adapter *, struct in6_addr *); +static void update_clip(struct adapter *, void *); +static void t4_clip_task(void *, int); +static void update_clip_table(struct adapter *); + +static int in6_ifaddr_gen; +static eventhandler_tag ifaddr_evhandler; +static struct timeout_task clip_task; + +static int +add_lip(struct adapter *sc, struct in6_addr *lip) +{ + struct fw_clip_cmd c; + + ASSERT_SYNCHRONIZED_OP(sc); + mtx_assert(&sc->clip_table_lock, MA_OWNED); + + memset(&c, 0, sizeof(c)); + c.op_to_write = htonl(V_FW_CMD_OP(FW_CLIP_CMD) | F_FW_CMD_REQUEST | + F_FW_CMD_WRITE); + c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_ALLOC | FW_LEN16(c)); + 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)); +} + +static int +delete_lip(struct adapter *sc, struct in6_addr *lip) +{ + struct fw_clip_cmd c; + + ASSERT_SYNCHRONIZED_OP(sc); + mtx_assert(&sc->clip_table_lock, MA_OWNED); + + memset(&c, 0, sizeof(c)); + c.op_to_write = htonl(V_FW_CMD_OP(FW_CLIP_CMD) | F_FW_CMD_REQUEST | + F_FW_CMD_READ); + c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_FREE | FW_LEN16(c)); + 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)); +} + +static struct clip_entry * +search_lip(struct adapter *sc, struct in6_addr *lip) +{ + struct clip_entry *ce; + + mtx_assert(&sc->clip_table_lock, MA_OWNED); + + TAILQ_FOREACH(ce, &sc->clip_table, link) { + if (IN6_ARE_ADDR_EQUAL(&ce->lip, lip)) + return (ce); + } + + return (NULL); +} + +struct clip_entry * +t4_hold_lip(struct adapter *sc, struct in6_addr *lip, struct clip_entry *ce) +{ + + mtx_lock(&sc->clip_table_lock); + if (ce == NULL) + ce = search_lip(sc, lip); + if (ce != NULL) + ce->refcount++; + mtx_unlock(&sc->clip_table_lock); + + return (ce); +} + +void +t4_release_lip(struct adapter *sc, struct clip_entry *ce) +{ + + mtx_lock(&sc->clip_table_lock); + KASSERT(search_lip(sc, &ce->lip) == ce, + ("%s: CLIP entry %p p not in CLIP table.", __func__, ce)); + KASSERT(ce->refcount > 0, + ("%s: CLIP entry %p has refcount 0", __func__, ce)); + --ce->refcount; + mtx_unlock(&sc->clip_table_lock); +} + +void +t4_init_clip_table(struct adapter *sc) +{ + + mtx_init(&sc->clip_table_lock, "CLIP table lock", NULL, MTX_DEF); + TAILQ_INIT(&sc->clip_table); + sc->clip_gen = -1; + + /* + * Don't bother forcing an update of the clip table when the + * adapter is initialized. Before an interface can be used it + * must be assigned an address which will trigger the event + * handler to update the table. + */ +} + +static void +update_clip(struct adapter *sc, void *arg __unused) +{ + + if (begin_synchronized_op(sc, NULL, HOLD_LOCK, "t4clip")) + return; + + if (mtx_initialized(&sc->clip_table_lock)) + update_clip_table(sc); + + 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 rm_priotracker in6_ifa_tracker; + struct in6_ifaddr *ia; + struct in6_addr *lip, tlip; + TAILQ_HEAD(, clip_entry) stale; + struct clip_entry *ce, *ce_temp; + struct vi_info *vi; + int rc, gen, i, j; + uintptr_t last_vnet; + + ASSERT_SYNCHRONIZED_OP(sc); + + IN6_IFADDR_RLOCK(&in6_ifa_tracker); + mtx_lock(&sc->clip_table_lock); + + gen = atomic_load_acq_int(&in6_ifaddr_gen); + if (gen == sc->clip_gen) + goto done; + + TAILQ_INIT(&stale); + TAILQ_CONCAT(&stale, &sc->clip_table, link); + + /* + * last_vnet optimizes the common cases where all if_vnet = NULL (no + * VIMAGE) or all if_vnet = vnet0. + */ + last_vnet = (uintptr_t)(-1); + for_each_port(sc, i) + for_each_vi(sc->port[i], j, vi) { + if (last_vnet == (uintptr_t)vi->ifp->if_vnet) + continue; + + /* XXX: races with if_vmove */ + CURVNET_SET(vi->ifp->if_vnet); + CK_STAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { + lip = &ia->ia_addr.sin6_addr; + + KASSERT(!IN6_IS_ADDR_MULTICAST(lip), + ("%s: mcast address in in6_ifaddr list", __func__)); + + if (IN6_IS_ADDR_LOOPBACK(lip)) + continue; + if (IN6_IS_SCOPE_EMBED(lip)) { + /* Remove the embedded scope */ + tlip = *lip; + lip = &tlip; + in6_clearscope(lip); + } + /* + * XXX: how to weed out the link local address for the + * loopback interface? It's fe80::1 usually (always?). + */ + + /* + * If it's in the main list then we already know it's + * not stale. + */ + TAILQ_FOREACH(ce, &sc->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(&sc->clip_table, ce, + link); + 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(&sc->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; + } + CURVNET_RESTORE(); + last_vnet = (uintptr_t)vi->ifp->if_vnet; + } + + /* + * 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); + } + } + } + /* The ones that are still referenced need to stay in the CLIP table */ + TAILQ_CONCAT(&sc->clip_table, &stale, link); + + sc->clip_gen = gen; +done: + mtx_unlock(&sc->clip_table_lock); + IN6_IFADDR_RUNLOCK(&in6_ifa_tracker); +} + +void +t4_destroy_clip_table(struct adapter *sc) +{ + struct clip_entry *ce, *ce_temp; + + if (mtx_initialized(&sc->clip_table_lock)) { + mtx_lock(&sc->clip_table_lock); + TAILQ_FOREACH_SAFE(ce, &sc->clip_table, link, ce_temp) { + KASSERT(ce->refcount == 0, + ("%s: CLIP entry %p still in use (%d)", __func__, + ce, ce->refcount)); + TAILQ_REMOVE(&sc->clip_table, ce, link); + delete_lip(sc, &ce->lip); + free(ce, M_CXGBE); + } + mtx_unlock(&sc->clip_table_lock); + mtx_destroy(&sc->clip_table_lock); + } +} + +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); +} + +int +sysctl_clip(SYSCTL_HANDLER_ARGS) +{ + struct adapter *sc = arg1; + struct clip_entry *ce; + struct sbuf *sb; + int rc, header = 0; + char ip[INET6_ADDRSTRLEN]; + + rc = sysctl_wire_old_buffer(req, 0); + if (rc != 0) + return (rc); + + sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); + if (sb == NULL) + return (ENOMEM); + + mtx_lock(&sc->clip_table_lock); + TAILQ_FOREACH(ce, &sc->clip_table, link) { + if (header == 0) { + sbuf_printf(sb, "%-40s %-5s", "IP address", "Users"); + header = 1; + } + inet_ntop(AF_INET6, &ce->lip, &ip[0], sizeof(ip)); + + sbuf_printf(sb, "\n%-40s %5u", ip, ce->refcount); + } + mtx_unlock(&sc->clip_table_lock); + + rc = sbuf_finish(sb); + sbuf_delete(sb); + + return (rc); +} + +void +t4_clip_modload(void) +{ + + 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); +} + +void +t4_clip_modunload(void) +{ + + EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_evhandler); + taskqueue_cancel_timeout(taskqueue_thread, &clip_task, NULL); +} Index: head/sys/dev/cxgbe/t4_main.c =================================================================== --- head/sys/dev/cxgbe/t4_main.c +++ head/sys/dev/cxgbe/t4_main.c @@ -82,6 +82,7 @@ #include "common/t4_regs.h" #include "common/t4_regs_values.h" #include "cudbg/cudbg.h" +#include "t4_clip.h" #include "t4_ioctl.h" #include "t4_l2t.h" #include "t4_mp_ring.h" @@ -1221,6 +1222,7 @@ #ifdef RATELIMIT t4_init_etid_table(sc); #endif + t4_init_clip_table(sc); if (sc->vres.key.size != 0) sc->key_map = vmem_create("T4TLS key map", sc->vres.key.start, sc->vres.key.size, 32, 0, M_FIRSTFIT | M_WAITOK); @@ -1511,6 +1513,7 @@ #endif if (sc->key_map) vmem_destroy(sc->key_map); + t4_destroy_clip_table(sc); #if defined(TCP_OFFLOAD) || defined(RATELIMIT) free(sc->sge.ofld_txq, M_CXGBE); @@ -5964,6 +5967,10 @@ CTLTYPE_STRING | CTLFLAG_RD, sc, 0, sysctl_smt, "A", "hardware source MAC table"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "clip", + CTLTYPE_STRING | CTLFLAG_RD, sc, 0, + sysctl_clip, "A", "active CLIP table entries"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", CTLTYPE_STRING | CTLFLAG_RD, sc, 0, sysctl_lb_stats, "A", "loopback statistics"); @@ -10520,6 +10527,7 @@ sx_init(&t4_uld_list_lock, "T4/T5 ULDs"); SLIST_INIT(&t4_uld_list); #endif + t4_clip_modload(); t4_tracer_modload(); tweak_tunables(); } @@ -10559,6 +10567,7 @@ if (t4_sge_extfree_refs() == 0) { t4_tracer_modunload(); + t4_clip_modunload(); #ifdef TCP_OFFLOAD sx_destroy(&t4_uld_list_lock); #endif Index: head/sys/dev/cxgbe/tom/t4_connect.c =================================================================== --- head/sys/dev/cxgbe/tom/t4_connect.c +++ head/sys/dev/cxgbe/tom/t4_connect.c @@ -62,6 +62,7 @@ #include "common/t4_msg.h" #include "common/t4_regs.h" #include "common/t4_regs_values.h" +#include "t4_clip.h" #include "tom/t4_tom_l2t.h" #include "tom/t4_tom.h" @@ -316,7 +317,6 @@ struct sockaddr *nam) { struct adapter *sc = tod->tod_softc; - struct tom_data *td = tod_td(tod); struct toepcb *toep = NULL; struct wrqe *wr = NULL; struct ifnet *rt_ifp = rt->rt_ifp; @@ -409,7 +409,7 @@ if ((inp->inp_vflag & INP_IPV6) == 0) DONT_OFFLOAD_ACTIVE_OPEN(ENOTSUP); - toep->ce = hold_lip(td, &inp->in6p_laddr, NULL); + toep->ce = t4_hold_lip(sc, &inp->in6p_laddr, NULL); if (toep->ce == NULL) DONT_OFFLOAD_ACTIVE_OPEN(ENOENT); @@ -496,7 +496,7 @@ if (toep->l2te) t4_l2t_release(toep->l2te); if (toep->ce) - release_lip(td, toep->ce); + t4_release_lip(sc, toep->ce); free_toepcb(toep); } Index: head/sys/dev/cxgbe/tom/t4_listen.c =================================================================== --- head/sys/dev/cxgbe/tom/t4_listen.c +++ head/sys/dev/cxgbe/tom/t4_listen.c @@ -68,6 +68,7 @@ #include "common/common.h" #include "common/t4_msg.h" #include "common/t4_regs.h" +#include "t4_clip.h" #include "tom/t4_tom_l2t.h" #include "tom/t4_tom.h" @@ -212,9 +213,7 @@ if (inp->inp_vflag & INP_IPV6 && !IN6_ARE_ADDR_EQUAL(&in6addr_any, &inp->in6p_laddr)) { - struct tom_data *td = sc->tom_softc; - - lctx->ce = hold_lip(td, &inp->in6p_laddr, NULL); + lctx->ce = t4_hold_lip(sc, &inp->in6p_laddr, NULL); if (lctx->ce == NULL) { free(lctx, M_CXGBE); return (NULL); @@ -238,7 +237,6 @@ free_lctx(struct adapter *sc, struct listen_ctx *lctx) { struct inpcb *inp = lctx->inp; - struct tom_data *td = sc->tom_softc; INP_WLOCK_ASSERT(inp); KASSERT(lctx->refcount == 0, @@ -251,7 +249,7 @@ __func__, lctx->stid, lctx, lctx->inp); if (lctx->ce) - release_lip(td, lctx->ce); + t4_release_lip(sc, lctx->ce); free_stid(sc, lctx); free(lctx, M_CXGBE); @@ -1675,7 +1673,7 @@ MPASS(so->so_vnet == lctx->vnet); toep->vnet = lctx->vnet; if (inc.inc_flags & INC_ISIPV6) - toep->ce = hold_lip(sc->tom_softc, &inc.inc6_laddr, lctx->ce); + toep->ce = t4_hold_lip(sc, &inc.inc6_laddr, lctx->ce); /* * This is for the unlikely case where the syncache entry that we added Index: head/sys/dev/cxgbe/tom/t4_tom.h =================================================================== --- head/sys/dev/cxgbe/tom/t4_tom.h +++ head/sys/dev/cxgbe/tom/t4_tom.h @@ -259,13 +259,6 @@ TAILQ_HEAD(, synq_entry) synq; }; -struct clip_entry { - TAILQ_ENTRY(clip_entry) link; - struct in6_addr lip; /* local IPv6 address */ - u_int refcount; -}; - -TAILQ_HEAD(clip_head, clip_entry); struct tom_data { struct toedev tod; @@ -280,10 +273,6 @@ struct ppod_region pr; - struct mtx clip_table_lock; - struct clip_head clip_table; - int clip_gen; - /* WRs that will not be sent to the chip because L2 resolution failed */ struct mtx unsent_wr_lock; STAILQ_HEAD(, wrqe) unsent_wr_list; @@ -342,9 +331,6 @@ struct offload_settings *); void set_ulp_mode(struct toepcb *, int); int negative_advice(int); -struct clip_entry *hold_lip(struct tom_data *, struct in6_addr *, - struct clip_entry *); -void release_lip(struct tom_data *, struct clip_entry *); /* t4_connect.c */ void t4_init_connect_cpl_handlers(void); Index: head/sys/dev/cxgbe/tom/t4_tom.c =================================================================== --- head/sys/dev/cxgbe/tom/t4_tom.c +++ head/sys/dev/cxgbe/tom/t4_tom.c @@ -71,6 +71,7 @@ #include "common/t4_regs.h" #include "common/t4_regs_values.h" #include "common/t4_tcb.h" +#include "t4_clip.h" #include "tom/t4_tom_l2t.h" #include "tom/t4_tom.h" #include "tom/t4_tls.h" @@ -99,21 +100,9 @@ static void release_offload_resources(struct toepcb *); static int alloc_tid_tabs(struct tid_info *); static void free_tid_tabs(struct tid_info *); -static int add_lip(struct adapter *, struct in6_addr *); -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 void reclaim_wr_resources(void *, int); -static int in6_ifaddr_gen; -static eventhandler_tag ifaddr_evhandler; -static struct timeout_task clip_task; - struct toepcb * alloc_toepcb(struct vi_info *vi, int txqid, int rxqid, int flags) { @@ -315,7 +304,7 @@ } if (toep->ce) - release_lip(td, toep->ce); + t4_release_lip(sc, toep->ce); if (toep->tc_idx != -1) t4_release_cl_rl(sc, toep->vi->pi->port_id, toep->tc_idx); @@ -822,267 +811,7 @@ return (rc); } -static int -add_lip(struct adapter *sc, struct in6_addr *lip) -{ - struct fw_clip_cmd c; - - ASSERT_SYNCHRONIZED_OP(sc); - /* mtx_assert(&td->clip_table_lock, MA_OWNED); */ - - memset(&c, 0, sizeof(c)); - c.op_to_write = htonl(V_FW_CMD_OP(FW_CLIP_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_WRITE); - c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_ALLOC | FW_LEN16(c)); - 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)); -} - -static int -delete_lip(struct adapter *sc, struct in6_addr *lip) -{ - struct fw_clip_cmd c; - - ASSERT_SYNCHRONIZED_OP(sc); - /* mtx_assert(&td->clip_table_lock, MA_OWNED); */ - - memset(&c, 0, sizeof(c)); - c.op_to_write = htonl(V_FW_CMD_OP(FW_CLIP_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_READ); - c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_FREE | FW_LEN16(c)); - 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)); -} - -static struct clip_entry * -search_lip(struct tom_data *td, struct in6_addr *lip) -{ - struct clip_entry *ce; - - mtx_assert(&td->clip_table_lock, MA_OWNED); - - TAILQ_FOREACH(ce, &td->clip_table, link) { - if (IN6_ARE_ADDR_EQUAL(&ce->lip, lip)) - return (ce); - } - - return (NULL); -} - -struct clip_entry * -hold_lip(struct tom_data *td, struct in6_addr *lip, struct clip_entry *ce) -{ - - mtx_lock(&td->clip_table_lock); - if (ce == NULL) - ce = search_lip(td, lip); - if (ce != NULL) - ce->refcount++; - mtx_unlock(&td->clip_table_lock); - - return (ce); -} - -void -release_lip(struct tom_data *td, struct clip_entry *ce) -{ - - mtx_lock(&td->clip_table_lock); - KASSERT(search_lip(td, &ce->lip) == ce, - ("%s: CLIP entry %p p not in CLIP table.", __func__, ce)); - KASSERT(ce->refcount > 0, - ("%s: CLIP entry %p has refcount 0", __func__, ce)); - --ce->refcount; - mtx_unlock(&td->clip_table_lock); -} - static void -init_clip_table(struct adapter *sc, struct tom_data *td) -{ - - 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 (uld_active(sc, ULD_TOM)) - 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 rm_priotracker in6_ifa_tracker; - struct in6_ifaddr *ia; - struct in6_addr *lip, tlip; - struct clip_head stale; - struct clip_entry *ce, *ce_temp; - struct vi_info *vi; - int rc, gen, i, j; - uintptr_t last_vnet; - - ASSERT_SYNCHRONIZED_OP(sc); - - IN6_IFADDR_RLOCK(&in6_ifa_tracker); - mtx_lock(&td->clip_table_lock); - - gen = atomic_load_acq_int(&in6_ifaddr_gen); - if (gen == td->clip_gen) - goto done; - - TAILQ_INIT(&stale); - TAILQ_CONCAT(&stale, &td->clip_table, link); - - /* - * last_vnet optimizes the common cases where all if_vnet = NULL (no - * VIMAGE) or all if_vnet = vnet0. - */ - last_vnet = (uintptr_t)(-1); - for_each_port(sc, i) - for_each_vi(sc->port[i], j, vi) { - if (last_vnet == (uintptr_t)vi->ifp->if_vnet) - continue; - - /* XXX: races with if_vmove */ - CURVNET_SET(vi->ifp->if_vnet); - CK_STAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { - lip = &ia->ia_addr.sin6_addr; - - KASSERT(!IN6_IS_ADDR_MULTICAST(lip), - ("%s: mcast address in in6_ifaddr list", __func__)); - - if (IN6_IS_ADDR_LOOPBACK(lip)) - continue; - if (IN6_IS_SCOPE_EMBED(lip)) { - /* Remove the embedded scope */ - tlip = *lip; - lip = &tlip; - in6_clearscope(lip); - } - /* - * XXX: how to weed out the link local address for the - * loopback interface? It's fe80::1 usually (always?). - */ - - /* - * 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); - 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; - } - CURVNET_RESTORE(); - last_vnet = (uintptr_t)vi->ifp->if_vnet; - } - - /* - * 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); - } - } - } - /* 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(&in6_ifa_tracker); -} - -static void -destroy_clip_table(struct adapter *sc, struct tom_data *td) -{ - struct clip_entry *ce, *ce_temp; - - if (mtx_initialized(&td->clip_table_lock)) { - mtx_lock(&td->clip_table_lock); - TAILQ_FOREACH_SAFE(ce, &td->clip_table, link, ce_temp) { - KASSERT(ce->refcount == 0, - ("%s: CLIP entry %p still in use (%d)", __func__, - ce, ce->refcount)); - TAILQ_REMOVE(&td->clip_table, ce, link); - delete_lip(sc, &ce->lip); - free(ce, M_CXGBE); - } - mtx_unlock(&td->clip_table_lock); - mtx_destroy(&td->clip_table_lock); - } -} - -static void free_tom_data(struct adapter *sc, struct tom_data *td) { @@ -1094,7 +823,6 @@ ("%s: lctx hash table is not empty.", __func__)); t4_free_ppod_region(&td->pr); - destroy_clip_table(sc, td); if (td->listen_mask != 0) hashdestroy(td->listen_hash, M_CXGBE, td->listen_mask); @@ -1369,9 +1097,6 @@ t4_set_reg_field(sc, A_ULP_RX_TDDP_TAGMASK, V_TDDPTAGMASK(M_TDDPTAGMASK), td->pr.pr_tag_mask); - /* CLIP table for IPv6 offload */ - init_clip_table(sc, td); - /* toedev ops */ tod = &td->tod; init_toedev(tod); @@ -1449,14 +1174,6 @@ 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_aio_queue_tom(struct socket *so, struct kaiocb *job) { @@ -1524,10 +1241,6 @@ toe6_protosw.pr_ctloutput = t4_ctloutput_tom; toe6_protosw.pr_usrreqs = &toe6_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); - return (t4_register_uld(&tom_uld_info)); } @@ -1551,11 +1264,6 @@ 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); - } t4_tls_mod_unload(); t4_ddp_mod_unload(); Index: head/sys/modules/cxgbe/if_cxgbe/Makefile =================================================================== --- head/sys/modules/cxgbe/if_cxgbe/Makefile +++ head/sys/modules/cxgbe/if_cxgbe/Makefile @@ -15,6 +15,7 @@ SRCS+= opt_ratelimit.h SRCS+= opt_rss.h SRCS+= pci_if.h pci_iov_if.h +SRCS+= t4_clip.c SRCS+= t4_filter.c SRCS+= t4_hw.c SRCS+= t4_if.c t4_if.h