2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2012 Chelsio Communications, Inc.
6 * Written by: Navdeep Parhar <np@FreeBSD.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
34 #include "opt_inet6.h"
36 #include <sys/types.h>
38 #include <sys/eventhandler.h>
39 #include <sys/malloc.h>
40 #include <sys/rmlock.h>
42 #include <sys/socket.h>
43 #include <sys/taskqueue.h>
45 #include <net/if_var.h>
46 #include <netinet/in.h>
47 #include <netinet6/in6_var.h>
48 #include <netinet6/scope6_var.h>
50 #include "common/common.h"
54 static int add_lip(struct adapter *, struct in6_addr *);
55 static int delete_lip(struct adapter *, struct in6_addr *);
56 static struct clip_entry *search_lip(struct adapter *, struct in6_addr *);
57 static void update_clip(struct adapter *, void *);
58 static void t4_clip_task(void *, int);
59 static void update_clip_table(struct adapter *);
61 static int in6_ifaddr_gen;
62 static eventhandler_tag ifaddr_evhandler;
63 static struct timeout_task clip_task;
66 add_lip(struct adapter *sc, struct in6_addr *lip)
70 ASSERT_SYNCHRONIZED_OP(sc);
71 mtx_assert(&sc->clip_table_lock, MA_OWNED);
73 memset(&c, 0, sizeof(c));
74 c.op_to_write = htonl(V_FW_CMD_OP(FW_CLIP_CMD) | F_FW_CMD_REQUEST |
76 c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_ALLOC | FW_LEN16(c));
77 c.ip_hi = *(uint64_t *)&lip->s6_addr[0];
78 c.ip_lo = *(uint64_t *)&lip->s6_addr[8];
80 return (-t4_wr_mbox_ns(sc, sc->mbox, &c, sizeof(c), &c));
84 delete_lip(struct adapter *sc, struct in6_addr *lip)
88 ASSERT_SYNCHRONIZED_OP(sc);
89 mtx_assert(&sc->clip_table_lock, MA_OWNED);
91 memset(&c, 0, sizeof(c));
92 c.op_to_write = htonl(V_FW_CMD_OP(FW_CLIP_CMD) | F_FW_CMD_REQUEST |
94 c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_FREE | FW_LEN16(c));
95 c.ip_hi = *(uint64_t *)&lip->s6_addr[0];
96 c.ip_lo = *(uint64_t *)&lip->s6_addr[8];
98 return (-t4_wr_mbox_ns(sc, sc->mbox, &c, sizeof(c), &c));
101 static struct clip_entry *
102 search_lip(struct adapter *sc, struct in6_addr *lip)
104 struct clip_entry *ce;
106 mtx_assert(&sc->clip_table_lock, MA_OWNED);
108 TAILQ_FOREACH(ce, &sc->clip_table, link) {
109 if (IN6_ARE_ADDR_EQUAL(&ce->lip, lip))
118 t4_hold_lip(struct adapter *sc, struct in6_addr *lip, struct clip_entry *ce)
122 mtx_lock(&sc->clip_table_lock);
124 ce = search_lip(sc, lip);
127 mtx_unlock(&sc->clip_table_lock);
136 t4_release_lip(struct adapter *sc, struct clip_entry *ce)
140 mtx_lock(&sc->clip_table_lock);
141 KASSERT(search_lip(sc, &ce->lip) == ce,
142 ("%s: CLIP entry %p p not in CLIP table.", __func__, ce));
143 KASSERT(ce->refcount > 0,
144 ("%s: CLIP entry %p has refcount 0", __func__, ce));
146 mtx_unlock(&sc->clip_table_lock);
152 t4_init_clip_table(struct adapter *sc)
155 mtx_init(&sc->clip_table_lock, "CLIP table lock", NULL, MTX_DEF);
156 TAILQ_INIT(&sc->clip_table);
160 * Don't bother forcing an update of the clip table when the
161 * adapter is initialized. Before an interface can be used it
162 * must be assigned an address which will trigger the event
163 * handler to update the table.
168 update_clip(struct adapter *sc, void *arg __unused)
171 if (begin_synchronized_op(sc, NULL, HOLD_LOCK, "t4clip"))
174 if (mtx_initialized(&sc->clip_table_lock))
175 update_clip_table(sc);
177 end_synchronized_op(sc, LOCK_HELD);
181 t4_clip_task(void *arg, int count)
184 t4_iterate(update_clip, NULL);
188 update_clip_table(struct adapter *sc)
190 struct rm_priotracker in6_ifa_tracker;
191 struct in6_ifaddr *ia;
192 struct in6_addr *lip, tlip;
193 TAILQ_HEAD(, clip_entry) stale;
194 struct clip_entry *ce, *ce_temp;
199 ASSERT_SYNCHRONIZED_OP(sc);
201 IN6_IFADDR_RLOCK(&in6_ifa_tracker);
202 mtx_lock(&sc->clip_table_lock);
204 gen = atomic_load_acq_int(&in6_ifaddr_gen);
205 if (gen == sc->clip_gen)
209 TAILQ_CONCAT(&stale, &sc->clip_table, link);
212 * last_vnet optimizes the common cases where all if_vnet = NULL (no
213 * VIMAGE) or all if_vnet = vnet0.
215 last_vnet = (uintptr_t)(-1);
217 for_each_vi(sc->port[i], j, vi) {
218 if (last_vnet == (uintptr_t)vi->ifp->if_vnet)
221 /* XXX: races with if_vmove */
222 CURVNET_SET(vi->ifp->if_vnet);
223 CK_STAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
224 lip = &ia->ia_addr.sin6_addr;
226 KASSERT(!IN6_IS_ADDR_MULTICAST(lip),
227 ("%s: mcast address in in6_ifaddr list", __func__));
229 if (IN6_IS_ADDR_LOOPBACK(lip))
231 if (IN6_IS_SCOPE_EMBED(lip)) {
232 /* Remove the embedded scope */
238 * XXX: how to weed out the link local address for the
239 * loopback interface? It's fe80::1 usually (always?).
243 * If it's in the main list then we already know it's
246 TAILQ_FOREACH(ce, &sc->clip_table, link) {
247 if (IN6_ARE_ADDR_EQUAL(&ce->lip, lip))
252 * If it's in the stale list we should move it to the
255 TAILQ_FOREACH(ce, &stale, link) {
256 if (IN6_ARE_ADDR_EQUAL(&ce->lip, lip)) {
257 TAILQ_REMOVE(&stale, ce, link);
258 TAILQ_INSERT_TAIL(&sc->clip_table, ce,
264 /* A new IP6 address; add it to the CLIP table */
265 ce = malloc(sizeof(*ce), M_CXGBE, M_NOWAIT);
266 memcpy(&ce->lip, lip, sizeof(ce->lip));
268 rc = add_lip(sc, lip);
270 TAILQ_INSERT_TAIL(&sc->clip_table, ce, link);
272 char ip[INET6_ADDRSTRLEN];
274 inet_ntop(AF_INET6, &ce->lip, &ip[0],
276 if (sc->flags & KERN_TLS_OK ||
277 sc->active_ulds != 0) {
279 "%s: could not add %s (%d)\n",
288 last_vnet = (uintptr_t)vi->ifp->if_vnet;
292 * Remove stale addresses (those no longer in V_in6_ifaddrhead) that are
293 * no longer referenced by the driver.
295 TAILQ_FOREACH_SAFE(ce, &stale, link, ce_temp) {
296 if (ce->refcount == 0) {
297 rc = delete_lip(sc, &ce->lip);
299 TAILQ_REMOVE(&stale, ce, link);
302 char ip[INET6_ADDRSTRLEN];
304 inet_ntop(AF_INET6, &ce->lip, &ip[0],
306 log(LOG_ERR, "%s: could not delete %s (%d)\n",
311 /* The ones that are still referenced need to stay in the CLIP table */
312 TAILQ_CONCAT(&sc->clip_table, &stale, link);
316 mtx_unlock(&sc->clip_table_lock);
317 IN6_IFADDR_RUNLOCK(&in6_ifa_tracker);
321 t4_destroy_clip_table(struct adapter *sc)
323 struct clip_entry *ce, *ce_temp;
325 if (mtx_initialized(&sc->clip_table_lock)) {
326 mtx_lock(&sc->clip_table_lock);
327 TAILQ_FOREACH_SAFE(ce, &sc->clip_table, link, ce_temp) {
328 KASSERT(ce->refcount == 0,
329 ("%s: CLIP entry %p still in use (%d)", __func__,
331 TAILQ_REMOVE(&sc->clip_table, ce, link);
333 delete_lip(sc, &ce->lip);
337 mtx_unlock(&sc->clip_table_lock);
338 mtx_destroy(&sc->clip_table_lock);
343 t4_tom_ifaddr_event(void *arg __unused, struct ifnet *ifp)
346 atomic_add_rel_int(&in6_ifaddr_gen, 1);
347 taskqueue_enqueue_timeout(taskqueue_thread, &clip_task, -hz / 4);
351 sysctl_clip(SYSCTL_HANDLER_ARGS)
353 struct adapter *sc = arg1;
354 struct clip_entry *ce;
357 char ip[INET6_ADDRSTRLEN];
359 rc = sysctl_wire_old_buffer(req, 0);
363 sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
367 mtx_lock(&sc->clip_table_lock);
368 TAILQ_FOREACH(ce, &sc->clip_table, link) {
370 sbuf_printf(sb, "%-40s %-5s", "IP address", "Users");
373 inet_ntop(AF_INET6, &ce->lip, &ip[0], sizeof(ip));
375 sbuf_printf(sb, "\n%-40s %5u", ip, ce->refcount);
377 mtx_unlock(&sc->clip_table_lock);
379 rc = sbuf_finish(sb);
386 t4_clip_modload(void)
389 TIMEOUT_TASK_INIT(taskqueue_thread, &clip_task, 0, t4_clip_task, NULL);
390 ifaddr_evhandler = EVENTHANDLER_REGISTER(ifaddr_event,
391 t4_tom_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY);
395 t4_clip_modunload(void)
398 EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_evhandler);
399 taskqueue_cancel_timeout(taskqueue_thread, &clip_task, NULL);