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.
This commit is contained in:
parent
5055fe41fa
commit
e140f34c92
@ -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 *, 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 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_addr *lip)
|
||||
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 in6_addr *lip)
|
||||
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 clip_entry *ce)
|
||||
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, struct tom_data *td)
|
||||
* 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)
|
||||
TAILQ_INSERT_TAIL(&td->clip_table, ce, link);
|
||||
else
|
||||
free(ce, M_CXGBE);
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
mtx_unlock(&td->clip_table_lock);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
|
@ -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 *
|
||||
|
Loading…
Reference in New Issue
Block a user