1*a6663252SAlexander V. Chernikov /*- 2*a6663252SAlexander V. Chernikov * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*a6663252SAlexander V. Chernikov * 4*a6663252SAlexander V. Chernikov * Copyright (c) 2020 Alexander V. Chernikov 5*a6663252SAlexander V. Chernikov * 6*a6663252SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 7*a6663252SAlexander V. Chernikov * modification, are permitted provided that the following conditions 8*a6663252SAlexander V. Chernikov * are met: 9*a6663252SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 10*a6663252SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 11*a6663252SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 12*a6663252SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 13*a6663252SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 14*a6663252SAlexander V. Chernikov * 15*a6663252SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*a6663252SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*a6663252SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*a6663252SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*a6663252SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*a6663252SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*a6663252SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*a6663252SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*a6663252SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*a6663252SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*a6663252SAlexander V. Chernikov * SUCH DAMAGE. 26*a6663252SAlexander V. Chernikov */ 27*a6663252SAlexander V. Chernikov 28*a6663252SAlexander V. Chernikov #include <sys/cdefs.h> 29*a6663252SAlexander V. Chernikov __FBSDID("$FreeBSD$"); 30*a6663252SAlexander V. Chernikov #include "opt_inet.h" 31*a6663252SAlexander V. Chernikov #include "opt_route.h" 32*a6663252SAlexander V. Chernikov 33*a6663252SAlexander V. Chernikov #include <sys/param.h> 34*a6663252SAlexander V. Chernikov #include <sys/systm.h> 35*a6663252SAlexander V. Chernikov #include <sys/lock.h> 36*a6663252SAlexander V. Chernikov #include <sys/rwlock.h> 37*a6663252SAlexander V. Chernikov #include <sys/malloc.h> 38*a6663252SAlexander V. Chernikov #include <sys/mbuf.h> 39*a6663252SAlexander V. Chernikov #include <sys/socket.h> 40*a6663252SAlexander V. Chernikov #include <sys/kernel.h> 41*a6663252SAlexander V. Chernikov 42*a6663252SAlexander V. Chernikov #include <net/if.h> 43*a6663252SAlexander V. Chernikov #include <net/if_var.h> 44*a6663252SAlexander V. Chernikov #include <net/route.h> 45*a6663252SAlexander V. Chernikov #include <net/route_var.h> 46*a6663252SAlexander V. Chernikov #include <net/route/nhop_utils.h> 47*a6663252SAlexander V. Chernikov #include <net/route/nhop.h> 48*a6663252SAlexander V. Chernikov #include <net/route/nhop_var.h> 49*a6663252SAlexander V. Chernikov #include <net/route/shared.h> 50*a6663252SAlexander V. Chernikov #include <net/vnet.h> 51*a6663252SAlexander V. Chernikov 52*a6663252SAlexander V. Chernikov /* 53*a6663252SAlexander V. Chernikov * This file contains data structures management logic for the nexthop ("nhop") 54*a6663252SAlexander V. Chernikov * route subsystem. 55*a6663252SAlexander V. Chernikov * 56*a6663252SAlexander V. Chernikov * Nexthops in the original sense are the objects containing all the necessary 57*a6663252SAlexander V. Chernikov * information to forward the packet to the selected destination. 58*a6663252SAlexander V. Chernikov * In particular, nexthop is defined by a combination of 59*a6663252SAlexander V. Chernikov * ifp, ifa, aifp, mtu, gw addr(if set), nh_type, nh_family, mask of rt_flags and 60*a6663252SAlexander V. Chernikov * NHF_DEFAULT 61*a6663252SAlexander V. Chernikov * 62*a6663252SAlexander V. Chernikov * All nexthops are stored in the resizable hash table. 63*a6663252SAlexander V. Chernikov * Additionally, each nexthop gets assigned its unique index (nexthop index) 64*a6663252SAlexander V. Chernikov * so userland programs can interact with the nexthops easier. Index allocation 65*a6663252SAlexander V. Chernikov * is backed by the bitmask array. 66*a6663252SAlexander V. Chernikov */ 67*a6663252SAlexander V. Chernikov 68*a6663252SAlexander V. Chernikov static MALLOC_DEFINE(M_NHOP, "nhops", "nexthops data"); 69*a6663252SAlexander V. Chernikov 70*a6663252SAlexander V. Chernikov 71*a6663252SAlexander V. Chernikov /* Hash management functions */ 72*a6663252SAlexander V. Chernikov 73*a6663252SAlexander V. Chernikov int 74*a6663252SAlexander V. Chernikov nhops_init_rib(struct rib_head *rh) 75*a6663252SAlexander V. Chernikov { 76*a6663252SAlexander V. Chernikov struct nh_control *ctl; 77*a6663252SAlexander V. Chernikov size_t alloc_size; 78*a6663252SAlexander V. Chernikov uint32_t num_buckets, num_items; 79*a6663252SAlexander V. Chernikov void *ptr; 80*a6663252SAlexander V. Chernikov 81*a6663252SAlexander V. Chernikov ctl = malloc(sizeof(struct nh_control), M_NHOP, M_WAITOK | M_ZERO); 82*a6663252SAlexander V. Chernikov 83*a6663252SAlexander V. Chernikov /* 84*a6663252SAlexander V. Chernikov * Allocate nexthop hash. Start with 16 items by default (128 bytes). 85*a6663252SAlexander V. Chernikov * This will be enough for most of the cases. 86*a6663252SAlexander V. Chernikov */ 87*a6663252SAlexander V. Chernikov num_buckets = 16; 88*a6663252SAlexander V. Chernikov alloc_size = CHT_SLIST_GET_RESIZE_SIZE(num_buckets); 89*a6663252SAlexander V. Chernikov ptr = malloc(alloc_size, M_NHOP, M_WAITOK | M_ZERO); 90*a6663252SAlexander V. Chernikov CHT_SLIST_INIT(&ctl->nh_head, ptr, num_buckets); 91*a6663252SAlexander V. Chernikov 92*a6663252SAlexander V. Chernikov /* 93*a6663252SAlexander V. Chernikov * Allocate nexthop index bitmask. 94*a6663252SAlexander V. Chernikov */ 95*a6663252SAlexander V. Chernikov num_items = 128 * 8; /* 128 bytes */ 96*a6663252SAlexander V. Chernikov ptr = malloc(bitmask_get_size(num_items), M_NHOP, M_WAITOK | M_ZERO); 97*a6663252SAlexander V. Chernikov bitmask_init(&ctl->nh_idx_head, ptr, num_items); 98*a6663252SAlexander V. Chernikov 99*a6663252SAlexander V. Chernikov NHOPS_LOCK_INIT(ctl); 100*a6663252SAlexander V. Chernikov 101*a6663252SAlexander V. Chernikov rh->nh_control = ctl; 102*a6663252SAlexander V. Chernikov ctl->ctl_rh = rh; 103*a6663252SAlexander V. Chernikov 104*a6663252SAlexander V. Chernikov DPRINTF("NHOPS init for fib %u af %u: ctl %p rh %p", rh->rib_fibnum, 105*a6663252SAlexander V. Chernikov rh->rib_family, ctl, rh); 106*a6663252SAlexander V. Chernikov 107*a6663252SAlexander V. Chernikov return (0); 108*a6663252SAlexander V. Chernikov } 109*a6663252SAlexander V. Chernikov 110*a6663252SAlexander V. Chernikov static void 111*a6663252SAlexander V. Chernikov destroy_ctl(struct nh_control *ctl) 112*a6663252SAlexander V. Chernikov { 113*a6663252SAlexander V. Chernikov 114*a6663252SAlexander V. Chernikov NHOPS_LOCK_DESTROY(ctl); 115*a6663252SAlexander V. Chernikov free(ctl->nh_head.ptr, M_NHOP); 116*a6663252SAlexander V. Chernikov free(ctl->nh_idx_head.idx, M_NHOP); 117*a6663252SAlexander V. Chernikov free(ctl, M_NHOP); 118*a6663252SAlexander V. Chernikov } 119*a6663252SAlexander V. Chernikov 120*a6663252SAlexander V. Chernikov /* 121*a6663252SAlexander V. Chernikov * Epoch callback indicating ctl is safe to destroy 122*a6663252SAlexander V. Chernikov */ 123*a6663252SAlexander V. Chernikov static void 124*a6663252SAlexander V. Chernikov destroy_ctl_epoch(epoch_context_t ctx) 125*a6663252SAlexander V. Chernikov { 126*a6663252SAlexander V. Chernikov struct nh_control *ctl; 127*a6663252SAlexander V. Chernikov 128*a6663252SAlexander V. Chernikov ctl = __containerof(ctx, struct nh_control, ctl_epoch_ctx); 129*a6663252SAlexander V. Chernikov 130*a6663252SAlexander V. Chernikov destroy_ctl(ctl); 131*a6663252SAlexander V. Chernikov } 132*a6663252SAlexander V. Chernikov 133*a6663252SAlexander V. Chernikov void 134*a6663252SAlexander V. Chernikov nhops_destroy_rib(struct rib_head *rh) 135*a6663252SAlexander V. Chernikov { 136*a6663252SAlexander V. Chernikov struct nh_control *ctl; 137*a6663252SAlexander V. Chernikov struct nhop_priv *nh_priv; 138*a6663252SAlexander V. Chernikov 139*a6663252SAlexander V. Chernikov ctl = rh->nh_control; 140*a6663252SAlexander V. Chernikov 141*a6663252SAlexander V. Chernikov /* 142*a6663252SAlexander V. Chernikov * All routes should have been deleted in rt_table_destroy(). 143*a6663252SAlexander V. Chernikov * However, TCP stack or other consumers may store referenced 144*a6663252SAlexander V. Chernikov * nexthop pointers. When these references go to zero, 145*a6663252SAlexander V. Chernikov * nhop_free() will try to unlink these records from the 146*a6663252SAlexander V. Chernikov * datastructures, most likely leading to panic. 147*a6663252SAlexander V. Chernikov * 148*a6663252SAlexander V. Chernikov * Avoid that by explicitly marking all of the remaining 149*a6663252SAlexander V. Chernikov * nexthops as unlinked by removing a reference from a special 150*a6663252SAlexander V. Chernikov * counter. Please see nhop_free() comments for more 151*a6663252SAlexander V. Chernikov * details. 152*a6663252SAlexander V. Chernikov */ 153*a6663252SAlexander V. Chernikov 154*a6663252SAlexander V. Chernikov NHOPS_WLOCK(ctl); 155*a6663252SAlexander V. Chernikov CHT_SLIST_FOREACH(&ctl->nh_head, nhops, nh_priv) { 156*a6663252SAlexander V. Chernikov DPRINTF("Marking nhop %u unlinked", nh_priv->nh_idx); 157*a6663252SAlexander V. Chernikov refcount_release(&nh_priv->nh_linked); 158*a6663252SAlexander V. Chernikov } CHT_SLIST_FOREACH_END; 159*a6663252SAlexander V. Chernikov NHOPS_WUNLOCK(ctl); 160*a6663252SAlexander V. Chernikov 161*a6663252SAlexander V. Chernikov /* 162*a6663252SAlexander V. Chernikov * Postpone destruction till the end of current epoch 163*a6663252SAlexander V. Chernikov * so nhop_free() can safely use nh_control pointer. 164*a6663252SAlexander V. Chernikov */ 165*a6663252SAlexander V. Chernikov epoch_call(net_epoch_preempt, destroy_ctl_epoch, 166*a6663252SAlexander V. Chernikov &ctl->ctl_epoch_ctx); 167*a6663252SAlexander V. Chernikov } 168*a6663252SAlexander V. Chernikov 169*a6663252SAlexander V. Chernikov /* 170*a6663252SAlexander V. Chernikov * Nexhop hash calculation: 171*a6663252SAlexander V. Chernikov * 172*a6663252SAlexander V. Chernikov * Nexthops distribution: 173*a6663252SAlexander V. Chernikov * 2 "mandatory" nexthops per interface ("interface route", "loopback"). 174*a6663252SAlexander V. Chernikov * For direct peering: 1 nexthop for the peering router per ifp/af. 175*a6663252SAlexander V. Chernikov * For Ix-like peering: tens to hundreds nexthops of neghbors per ifp/af. 176*a6663252SAlexander V. Chernikov * IGP control plane & broadcast segment: tens of nexthops per ifp/af. 177*a6663252SAlexander V. Chernikov * 178*a6663252SAlexander V. Chernikov * Each fib/af combination has its own hash table. 179*a6663252SAlexander V. Chernikov * With that in mind, hash nexthops by the combination of the interface 180*a6663252SAlexander V. Chernikov * and GW IP address. 181*a6663252SAlexander V. Chernikov * 182*a6663252SAlexander V. Chernikov * To optimize hash calculation, ignore higher bytes of ifindex, as they 183*a6663252SAlexander V. Chernikov * give very little entropy. 184*a6663252SAlexander V. Chernikov * Similarly, use lower 4 bytes of IPv6 address to distinguish between the 185*a6663252SAlexander V. Chernikov * neighbors. 186*a6663252SAlexander V. Chernikov */ 187*a6663252SAlexander V. Chernikov struct _hash_data { 188*a6663252SAlexander V. Chernikov uint16_t ifindex; 189*a6663252SAlexander V. Chernikov uint8_t family; 190*a6663252SAlexander V. Chernikov uint8_t nh_type; 191*a6663252SAlexander V. Chernikov uint32_t gw_addr; 192*a6663252SAlexander V. Chernikov }; 193*a6663252SAlexander V. Chernikov 194*a6663252SAlexander V. Chernikov static unsigned 195*a6663252SAlexander V. Chernikov djb_hash(const unsigned char *h, const int len) 196*a6663252SAlexander V. Chernikov { 197*a6663252SAlexander V. Chernikov unsigned int result = 0; 198*a6663252SAlexander V. Chernikov int i; 199*a6663252SAlexander V. Chernikov 200*a6663252SAlexander V. Chernikov for (i = 0; i < len; i++) 201*a6663252SAlexander V. Chernikov result = 33 * result ^ h[i]; 202*a6663252SAlexander V. Chernikov 203*a6663252SAlexander V. Chernikov return (result); 204*a6663252SAlexander V. Chernikov } 205*a6663252SAlexander V. Chernikov 206*a6663252SAlexander V. Chernikov static uint32_t 207*a6663252SAlexander V. Chernikov hash_priv(const struct nhop_priv *priv) 208*a6663252SAlexander V. Chernikov { 209*a6663252SAlexander V. Chernikov struct nhop_object *nh; 210*a6663252SAlexander V. Chernikov uint16_t ifindex; 211*a6663252SAlexander V. Chernikov struct _hash_data key; 212*a6663252SAlexander V. Chernikov 213*a6663252SAlexander V. Chernikov nh = priv->nh; 214*a6663252SAlexander V. Chernikov ifindex = nh->nh_ifp->if_index & 0xFFFF; 215*a6663252SAlexander V. Chernikov memset(&key, 0, sizeof(key)); 216*a6663252SAlexander V. Chernikov 217*a6663252SAlexander V. Chernikov key.ifindex = ifindex; 218*a6663252SAlexander V. Chernikov key.family = nh->gw_sa.sa_family; 219*a6663252SAlexander V. Chernikov key.nh_type = priv->nh_type & 0xFF; 220*a6663252SAlexander V. Chernikov if (nh->gw_sa.sa_family == AF_INET6) 221*a6663252SAlexander V. Chernikov memcpy(&key.gw_addr, &nh->gw6_sa.sin6_addr.s6_addr32[3], 4); 222*a6663252SAlexander V. Chernikov else if (nh->gw_sa.sa_family == AF_INET) 223*a6663252SAlexander V. Chernikov memcpy(&key.gw_addr, &nh->gw4_sa.sin_addr, 4); 224*a6663252SAlexander V. Chernikov 225*a6663252SAlexander V. Chernikov return (uint32_t)(djb_hash((const unsigned char *)&key, sizeof(key))); 226*a6663252SAlexander V. Chernikov } 227*a6663252SAlexander V. Chernikov 228*a6663252SAlexander V. Chernikov /* 229*a6663252SAlexander V. Chernikov * Checks if hash needs resizing and performs this resize if necessary 230*a6663252SAlexander V. Chernikov * 231*a6663252SAlexander V. Chernikov */ 232*a6663252SAlexander V. Chernikov static void 233*a6663252SAlexander V. Chernikov consider_resize(struct nh_control *ctl, uint32_t new_nh_buckets, uint32_t new_idx_items) 234*a6663252SAlexander V. Chernikov { 235*a6663252SAlexander V. Chernikov void *nh_ptr, *nh_idx_ptr; 236*a6663252SAlexander V. Chernikov void *old_idx_ptr; 237*a6663252SAlexander V. Chernikov size_t alloc_size; 238*a6663252SAlexander V. Chernikov 239*a6663252SAlexander V. Chernikov nh_ptr = NULL; 240*a6663252SAlexander V. Chernikov if (new_nh_buckets != 0) { 241*a6663252SAlexander V. Chernikov alloc_size = CHT_SLIST_GET_RESIZE_SIZE(new_nh_buckets); 242*a6663252SAlexander V. Chernikov nh_ptr = malloc(alloc_size, M_NHOP, M_NOWAIT | M_ZERO); 243*a6663252SAlexander V. Chernikov } 244*a6663252SAlexander V. Chernikov 245*a6663252SAlexander V. Chernikov nh_idx_ptr = NULL; 246*a6663252SAlexander V. Chernikov if (new_idx_items != 0) { 247*a6663252SAlexander V. Chernikov alloc_size = bitmask_get_size(new_idx_items); 248*a6663252SAlexander V. Chernikov nh_idx_ptr = malloc(alloc_size, M_NHOP, M_NOWAIT | M_ZERO); 249*a6663252SAlexander V. Chernikov } 250*a6663252SAlexander V. Chernikov 251*a6663252SAlexander V. Chernikov if (nh_ptr == NULL && nh_idx_ptr == NULL) { 252*a6663252SAlexander V. Chernikov /* Either resize is not required or allocations have failed. */ 253*a6663252SAlexander V. Chernikov return; 254*a6663252SAlexander V. Chernikov } 255*a6663252SAlexander V. Chernikov 256*a6663252SAlexander V. Chernikov DPRINTF("going to resize: nh:[ptr:%p sz:%u] idx:[ptr:%p sz:%u]", nh_ptr, 257*a6663252SAlexander V. Chernikov new_nh_buckets, nh_idx_ptr, new_idx_items); 258*a6663252SAlexander V. Chernikov 259*a6663252SAlexander V. Chernikov old_idx_ptr = NULL; 260*a6663252SAlexander V. Chernikov 261*a6663252SAlexander V. Chernikov NHOPS_WLOCK(ctl); 262*a6663252SAlexander V. Chernikov if (nh_ptr != NULL) { 263*a6663252SAlexander V. Chernikov CHT_SLIST_RESIZE(&ctl->nh_head, nhops, nh_ptr, new_nh_buckets); 264*a6663252SAlexander V. Chernikov } 265*a6663252SAlexander V. Chernikov if (nh_idx_ptr != NULL) { 266*a6663252SAlexander V. Chernikov if (bitmask_copy(&ctl->nh_idx_head, nh_idx_ptr, new_idx_items) == 0) 267*a6663252SAlexander V. Chernikov bitmask_swap(&ctl->nh_idx_head, nh_idx_ptr, new_idx_items, &old_idx_ptr); 268*a6663252SAlexander V. Chernikov } 269*a6663252SAlexander V. Chernikov NHOPS_WUNLOCK(ctl); 270*a6663252SAlexander V. Chernikov 271*a6663252SAlexander V. Chernikov if (nh_ptr != NULL) 272*a6663252SAlexander V. Chernikov free(nh_ptr, M_NHOP); 273*a6663252SAlexander V. Chernikov if (old_idx_ptr != NULL) 274*a6663252SAlexander V. Chernikov free(old_idx_ptr, M_NHOP); 275*a6663252SAlexander V. Chernikov } 276*a6663252SAlexander V. Chernikov 277*a6663252SAlexander V. Chernikov /* 278*a6663252SAlexander V. Chernikov * Links nextop @nh_priv to the nexhop hash table and allocates 279*a6663252SAlexander V. Chernikov * nexhop index. 280*a6663252SAlexander V. Chernikov * Returns allocated index or 0 on failure. 281*a6663252SAlexander V. Chernikov */ 282*a6663252SAlexander V. Chernikov int 283*a6663252SAlexander V. Chernikov link_nhop(struct nh_control *ctl, struct nhop_priv *nh_priv) 284*a6663252SAlexander V. Chernikov { 285*a6663252SAlexander V. Chernikov uint16_t idx; 286*a6663252SAlexander V. Chernikov uint32_t num_buckets_new, num_items_new; 287*a6663252SAlexander V. Chernikov 288*a6663252SAlexander V. Chernikov KASSERT((nh_priv->nh_idx == 0), ("nhop index is already allocated")); 289*a6663252SAlexander V. Chernikov NHOPS_WLOCK(ctl); 290*a6663252SAlexander V. Chernikov 291*a6663252SAlexander V. Chernikov /* 292*a6663252SAlexander V. Chernikov * Check if we need to resize hash and index. 293*a6663252SAlexander V. Chernikov * The following 2 functions returns either new size or 0 294*a6663252SAlexander V. Chernikov * if resize is not required. 295*a6663252SAlexander V. Chernikov */ 296*a6663252SAlexander V. Chernikov num_buckets_new = CHT_SLIST_GET_RESIZE_BUCKETS(&ctl->nh_head); 297*a6663252SAlexander V. Chernikov num_items_new = bitmask_get_resize_items(&ctl->nh_idx_head); 298*a6663252SAlexander V. Chernikov 299*a6663252SAlexander V. Chernikov if (bitmask_alloc_idx(&ctl->nh_idx_head, &idx) != 0) { 300*a6663252SAlexander V. Chernikov NHOPS_WUNLOCK(ctl); 301*a6663252SAlexander V. Chernikov DPRINTF("Unable to allocate nhop index"); 302*a6663252SAlexander V. Chernikov RTSTAT_INC(rts_nh_idx_alloc_failure); 303*a6663252SAlexander V. Chernikov consider_resize(ctl, num_buckets_new, num_items_new); 304*a6663252SAlexander V. Chernikov return (0); 305*a6663252SAlexander V. Chernikov } 306*a6663252SAlexander V. Chernikov 307*a6663252SAlexander V. Chernikov nh_priv->nh_idx = idx; 308*a6663252SAlexander V. Chernikov nh_priv->nh_control = ctl; 309*a6663252SAlexander V. Chernikov 310*a6663252SAlexander V. Chernikov CHT_SLIST_INSERT_HEAD(&ctl->nh_head, nhops, nh_priv); 311*a6663252SAlexander V. Chernikov 312*a6663252SAlexander V. Chernikov NHOPS_WUNLOCK(ctl); 313*a6663252SAlexander V. Chernikov 314*a6663252SAlexander V. Chernikov DPRINTF("Linked nhop priv %p to %d, hash %u, ctl %p", nh_priv, idx, 315*a6663252SAlexander V. Chernikov hash_priv(nh_priv), ctl); 316*a6663252SAlexander V. Chernikov consider_resize(ctl, num_buckets_new, num_items_new); 317*a6663252SAlexander V. Chernikov 318*a6663252SAlexander V. Chernikov return (idx); 319*a6663252SAlexander V. Chernikov } 320*a6663252SAlexander V. Chernikov 321*a6663252SAlexander V. Chernikov /* 322*a6663252SAlexander V. Chernikov * Unlinks nexthop specified by @nh_priv data from the hash. 323*a6663252SAlexander V. Chernikov * 324*a6663252SAlexander V. Chernikov * Returns found nexthop or NULL. 325*a6663252SAlexander V. Chernikov */ 326*a6663252SAlexander V. Chernikov struct nhop_priv * 327*a6663252SAlexander V. Chernikov unlink_nhop(struct nh_control *ctl, struct nhop_priv *nh_priv_del) 328*a6663252SAlexander V. Chernikov { 329*a6663252SAlexander V. Chernikov struct nhop_priv *priv_ret; 330*a6663252SAlexander V. Chernikov int idx; 331*a6663252SAlexander V. Chernikov uint32_t num_buckets_new, num_items_new; 332*a6663252SAlexander V. Chernikov 333*a6663252SAlexander V. Chernikov idx = 0; 334*a6663252SAlexander V. Chernikov 335*a6663252SAlexander V. Chernikov NHOPS_WLOCK(ctl); 336*a6663252SAlexander V. Chernikov CHT_SLIST_REMOVE_BYOBJ(&ctl->nh_head, nhops, nh_priv_del, priv_ret); 337*a6663252SAlexander V. Chernikov 338*a6663252SAlexander V. Chernikov if (priv_ret != NULL) { 339*a6663252SAlexander V. Chernikov idx = priv_ret->nh_idx; 340*a6663252SAlexander V. Chernikov priv_ret->nh_idx = 0; 341*a6663252SAlexander V. Chernikov 342*a6663252SAlexander V. Chernikov KASSERT((idx != 0), ("bogus nhop index 0")); 343*a6663252SAlexander V. Chernikov if ((bitmask_free_idx(&ctl->nh_idx_head, idx)) != 0) { 344*a6663252SAlexander V. Chernikov DPRINTF("Unable to remove index %d from fib %u af %d", 345*a6663252SAlexander V. Chernikov idx, ctl->ctl_rh->rib_fibnum, 346*a6663252SAlexander V. Chernikov ctl->ctl_rh->rib_family); 347*a6663252SAlexander V. Chernikov } 348*a6663252SAlexander V. Chernikov } 349*a6663252SAlexander V. Chernikov 350*a6663252SAlexander V. Chernikov /* Check if hash or index needs to be resized */ 351*a6663252SAlexander V. Chernikov num_buckets_new = CHT_SLIST_GET_RESIZE_BUCKETS(&ctl->nh_head); 352*a6663252SAlexander V. Chernikov num_items_new = bitmask_get_resize_items(&ctl->nh_idx_head); 353*a6663252SAlexander V. Chernikov 354*a6663252SAlexander V. Chernikov NHOPS_WUNLOCK(ctl); 355*a6663252SAlexander V. Chernikov 356*a6663252SAlexander V. Chernikov if (priv_ret == NULL) 357*a6663252SAlexander V. Chernikov DPRINTF("Unable to unlink nhop priv %p from hash, hash %u ctl %p", 358*a6663252SAlexander V. Chernikov nh_priv_del, hash_priv(nh_priv_del), ctl); 359*a6663252SAlexander V. Chernikov else 360*a6663252SAlexander V. Chernikov DPRINTF("Unlinked nhop %p priv idx %d", priv_ret, idx); 361*a6663252SAlexander V. Chernikov 362*a6663252SAlexander V. Chernikov consider_resize(ctl, num_buckets_new, num_items_new); 363*a6663252SAlexander V. Chernikov 364*a6663252SAlexander V. Chernikov return (priv_ret); 365*a6663252SAlexander V. Chernikov } 366*a6663252SAlexander V. Chernikov 367*a6663252SAlexander V. Chernikov /* 368*a6663252SAlexander V. Chernikov * Searches for the nexthop by data specifcied in @nh_priv. 369*a6663252SAlexander V. Chernikov * Returns referenced nexthop or NULL. 370*a6663252SAlexander V. Chernikov */ 371*a6663252SAlexander V. Chernikov struct nhop_priv * 372*a6663252SAlexander V. Chernikov find_nhop(struct nh_control *ctl, const struct nhop_priv *nh_priv) 373*a6663252SAlexander V. Chernikov { 374*a6663252SAlexander V. Chernikov struct nhop_priv *nh_priv_ret; 375*a6663252SAlexander V. Chernikov 376*a6663252SAlexander V. Chernikov NHOPS_RLOCK(ctl); 377*a6663252SAlexander V. Chernikov CHT_SLIST_FIND_BYOBJ(&ctl->nh_head, nhops, nh_priv, nh_priv_ret); 378*a6663252SAlexander V. Chernikov if (nh_priv_ret != NULL) { 379*a6663252SAlexander V. Chernikov if (refcount_acquire_if_not_zero(&nh_priv_ret->nh_refcnt) == 0){ 380*a6663252SAlexander V. Chernikov /* refcount was 0 -> nhop is being deleted */ 381*a6663252SAlexander V. Chernikov nh_priv_ret = NULL; 382*a6663252SAlexander V. Chernikov } 383*a6663252SAlexander V. Chernikov } 384*a6663252SAlexander V. Chernikov NHOPS_RUNLOCK(ctl); 385*a6663252SAlexander V. Chernikov 386*a6663252SAlexander V. Chernikov return (nh_priv_ret); 387*a6663252SAlexander V. Chernikov } 388*a6663252SAlexander V. Chernikov 389