1a6663252SAlexander V. Chernikov /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3a6663252SAlexander V. Chernikov * 4a6663252SAlexander V. Chernikov * Copyright (c) 2020 Alexander V. Chernikov 5a6663252SAlexander V. Chernikov * 6a6663252SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 7a6663252SAlexander V. Chernikov * modification, are permitted provided that the following conditions 8a6663252SAlexander V. Chernikov * are met: 9a6663252SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 10a6663252SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 11a6663252SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 12a6663252SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 13a6663252SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 14a6663252SAlexander V. Chernikov * 15a6663252SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16a6663252SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17a6663252SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18a6663252SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19a6663252SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20a6663252SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21a6663252SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22a6663252SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23a6663252SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24a6663252SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25a6663252SAlexander V. Chernikov * SUCH DAMAGE. 26a6663252SAlexander V. Chernikov */ 27a6663252SAlexander V. Chernikov 28a6663252SAlexander V. Chernikov #include <sys/cdefs.h> 29a6663252SAlexander V. Chernikov __FBSDID("$FreeBSD$"); 30a6663252SAlexander V. Chernikov #include "opt_inet.h" 31a6663252SAlexander V. Chernikov #include "opt_route.h" 32a6663252SAlexander V. Chernikov 33a6663252SAlexander V. Chernikov #include <sys/param.h> 34a6663252SAlexander V. Chernikov #include <sys/systm.h> 35a6663252SAlexander V. Chernikov #include <sys/lock.h> 36a6663252SAlexander V. Chernikov #include <sys/malloc.h> 37a6663252SAlexander V. Chernikov #include <sys/mbuf.h> 38a6663252SAlexander V. Chernikov #include <sys/kernel.h> 39a6663252SAlexander V. Chernikov 40a6663252SAlexander V. Chernikov #include <net/route/nhop_utils.h> 41a6663252SAlexander V. Chernikov 42a6663252SAlexander V. Chernikov #define BLOCK_ITEMS (8 * sizeof(u_long)) /* Number of items for ffsl() */ 43a6663252SAlexander V. Chernikov 44a6663252SAlexander V. Chernikov #define _BLOCKS_TO_SZ(_blocks) ((size_t)(_blocks) * sizeof(u_long)) 45a6663252SAlexander V. Chernikov #define _BLOCKS_TO_ITEMS(_blocks) ((uint32_t)(_blocks) * BLOCK_ITEMS) 46a6663252SAlexander V. Chernikov #define _ITEMS_TO_BLOCKS(_items) ((_items) / BLOCK_ITEMS) 47a6663252SAlexander V. Chernikov 48a6663252SAlexander V. Chernikov static void _bitmask_init_idx(void *index, uint32_t items); 49a6663252SAlexander V. Chernikov 50a6663252SAlexander V. Chernikov void 51a6663252SAlexander V. Chernikov bitmask_init(struct bitmask_head *bh, void *idx, uint32_t num_items) 52a6663252SAlexander V. Chernikov { 53a6663252SAlexander V. Chernikov 54a6663252SAlexander V. Chernikov if (idx != NULL) 55a6663252SAlexander V. Chernikov _bitmask_init_idx(idx, num_items); 56a6663252SAlexander V. Chernikov 57a6663252SAlexander V. Chernikov memset(bh, 0, sizeof(struct bitmask_head)); 58a6663252SAlexander V. Chernikov bh->blocks = _ITEMS_TO_BLOCKS(num_items); 59a6663252SAlexander V. Chernikov bh->idx = (u_long *)idx; 60a6663252SAlexander V. Chernikov } 61a6663252SAlexander V. Chernikov 62a6663252SAlexander V. Chernikov uint32_t 63a6663252SAlexander V. Chernikov bitmask_get_resize_items(const struct bitmask_head *bh) 64a6663252SAlexander V. Chernikov { 65a6663252SAlexander V. Chernikov if ((bh->items_count * 2 > _BLOCKS_TO_ITEMS(bh->blocks)) && bh->items_count < 65536) 66a6663252SAlexander V. Chernikov return (_BLOCKS_TO_ITEMS(bh->blocks) * 2); 67a6663252SAlexander V. Chernikov 68a6663252SAlexander V. Chernikov return (0); 69a6663252SAlexander V. Chernikov } 70a6663252SAlexander V. Chernikov 71a6663252SAlexander V. Chernikov int 72a6663252SAlexander V. Chernikov bitmask_should_resize(const struct bitmask_head *bh) 73a6663252SAlexander V. Chernikov { 74a6663252SAlexander V. Chernikov 75a6663252SAlexander V. Chernikov return (bitmask_get_resize_items(bh) != 0); 76a6663252SAlexander V. Chernikov } 77a6663252SAlexander V. Chernikov 78a6663252SAlexander V. Chernikov #if 0 79a6663252SAlexander V. Chernikov uint32_t 80a6663252SAlexander V. Chernikov _bitmask_get_blocks(uint32_t items) 81a6663252SAlexander V. Chernikov { 82a6663252SAlexander V. Chernikov 83a6663252SAlexander V. Chernikov return (items / BLOCK_ITEMS); 84a6663252SAlexander V. Chernikov } 85a6663252SAlexander V. Chernikov #endif 86a6663252SAlexander V. Chernikov 87a6663252SAlexander V. Chernikov size_t 88a6663252SAlexander V. Chernikov bitmask_get_size(uint32_t items) 89a6663252SAlexander V. Chernikov { 90a6663252SAlexander V. Chernikov #if _KERNEL 91a6663252SAlexander V. Chernikov KASSERT((items % BLOCK_ITEMS) == 0, 92a6663252SAlexander V. Chernikov ("bitmask size needs to power of 2 and greater or equal to %zu", 93a6663252SAlexander V. Chernikov BLOCK_ITEMS)); 94a6663252SAlexander V. Chernikov #else 95a6663252SAlexander V. Chernikov assert((items % BLOCK_ITEMS) == 0); 96a6663252SAlexander V. Chernikov #endif 97a6663252SAlexander V. Chernikov 98a6663252SAlexander V. Chernikov return (items / 8); 99a6663252SAlexander V. Chernikov } 100a6663252SAlexander V. Chernikov 101a6663252SAlexander V. Chernikov static void 102a6663252SAlexander V. Chernikov _bitmask_init_idx(void *_idx, uint32_t items) 103a6663252SAlexander V. Chernikov { 104a6663252SAlexander V. Chernikov size_t size = bitmask_get_size(items); 105a6663252SAlexander V. Chernikov u_long *idx = (u_long *)_idx; 106a6663252SAlexander V. Chernikov 107a6663252SAlexander V. Chernikov /* Mark all as free */ 108a6663252SAlexander V. Chernikov memset(idx, 0xFF, size); 109a6663252SAlexander V. Chernikov *idx &= ~(u_long)1; /* Always skip index 0 */ 110a6663252SAlexander V. Chernikov } 111a6663252SAlexander V. Chernikov 112a6663252SAlexander V. Chernikov /* 113a6663252SAlexander V. Chernikov * _try_merge api to allow shrinking? 114a6663252SAlexander V. Chernikov */ 115a6663252SAlexander V. Chernikov int 116a6663252SAlexander V. Chernikov bitmask_copy(const struct bitmask_head *bi, void *new_idx, uint32_t new_items) 117a6663252SAlexander V. Chernikov { 118a6663252SAlexander V. Chernikov uint32_t new_blocks = _BLOCKS_TO_ITEMS(new_items); 119a6663252SAlexander V. Chernikov 120a6663252SAlexander V. Chernikov _bitmask_init_idx(new_idx, new_items); 121a6663252SAlexander V. Chernikov 122a6663252SAlexander V. Chernikov if (bi->blocks < new_blocks) { 123a6663252SAlexander V. Chernikov /* extend current blocks */ 124a6663252SAlexander V. Chernikov if (bi->blocks > 0) 125a6663252SAlexander V. Chernikov memcpy(new_idx, bi->idx, _BLOCKS_TO_SZ(bi->blocks)); 126a6663252SAlexander V. Chernikov return (0); 127a6663252SAlexander V. Chernikov } else { 128a6663252SAlexander V. Chernikov /* XXX: ensure all other blocks are non-zero */ 129a6663252SAlexander V. Chernikov for (int i = new_blocks; i < bi->blocks; i++) { 130a6663252SAlexander V. Chernikov } 131a6663252SAlexander V. Chernikov 132a6663252SAlexander V. Chernikov return (1); 133a6663252SAlexander V. Chernikov } 134a6663252SAlexander V. Chernikov } 135a6663252SAlexander V. Chernikov 136a6663252SAlexander V. Chernikov void 137a6663252SAlexander V. Chernikov bitmask_swap(struct bitmask_head *bh, void *new_idx, uint32_t new_items, void **pidx) 138a6663252SAlexander V. Chernikov { 139a6663252SAlexander V. Chernikov void *old_ptr; 140a6663252SAlexander V. Chernikov 141a6663252SAlexander V. Chernikov old_ptr = bh->idx; 142a6663252SAlexander V. Chernikov 143a6663252SAlexander V. Chernikov bh->idx = (u_long *)new_idx; 144a6663252SAlexander V. Chernikov bh->blocks = _ITEMS_TO_BLOCKS(new_items); 145a6663252SAlexander V. Chernikov 146a6663252SAlexander V. Chernikov if (pidx != NULL) 147a6663252SAlexander V. Chernikov *pidx = old_ptr; 148a6663252SAlexander V. Chernikov } 149a6663252SAlexander V. Chernikov 150a6663252SAlexander V. Chernikov /* 151a6663252SAlexander V. Chernikov * Allocate new index in given instance and stores in in @pidx. 152a6663252SAlexander V. Chernikov * Returns 0 on success. 153a6663252SAlexander V. Chernikov */ 154a6663252SAlexander V. Chernikov int 155a6663252SAlexander V. Chernikov bitmask_alloc_idx(struct bitmask_head *bi, uint16_t *pidx) 156a6663252SAlexander V. Chernikov { 157a6663252SAlexander V. Chernikov u_long *mask; 158a6663252SAlexander V. Chernikov int i, off, v; 159a6663252SAlexander V. Chernikov 160a6663252SAlexander V. Chernikov off = bi->free_off; 161a6663252SAlexander V. Chernikov mask = &bi->idx[off]; 162a6663252SAlexander V. Chernikov 163a6663252SAlexander V. Chernikov for (i = off; i < bi->blocks; i++, mask++) { 164a6663252SAlexander V. Chernikov if ((v = ffsl(*mask)) == 0) 165a6663252SAlexander V. Chernikov continue; 166a6663252SAlexander V. Chernikov 167a6663252SAlexander V. Chernikov /* Mark as busy */ 168a6663252SAlexander V. Chernikov *mask &= ~ ((u_long)1 << (v - 1)); 169a6663252SAlexander V. Chernikov 170a6663252SAlexander V. Chernikov bi->free_off = i; 171a6663252SAlexander V. Chernikov 172a6663252SAlexander V. Chernikov v = BLOCK_ITEMS * i + v - 1; 173a6663252SAlexander V. Chernikov 174a6663252SAlexander V. Chernikov *pidx = v; 175a6663252SAlexander V. Chernikov bi->items_count++; 176a6663252SAlexander V. Chernikov return (0); 177a6663252SAlexander V. Chernikov } 178a6663252SAlexander V. Chernikov 179a6663252SAlexander V. Chernikov return (1); 180a6663252SAlexander V. Chernikov } 181a6663252SAlexander V. Chernikov 182a6663252SAlexander V. Chernikov /* 183a6663252SAlexander V. Chernikov * Removes index from given set. 184a6663252SAlexander V. Chernikov * Returns 0 on success. 185a6663252SAlexander V. Chernikov */ 186a6663252SAlexander V. Chernikov int 187a6663252SAlexander V. Chernikov bitmask_free_idx(struct bitmask_head *bi, uint16_t idx) 188a6663252SAlexander V. Chernikov { 189a6663252SAlexander V. Chernikov u_long *mask; 190a6663252SAlexander V. Chernikov int i, v; 191a6663252SAlexander V. Chernikov 192a6663252SAlexander V. Chernikov if (idx == 0) 193a6663252SAlexander V. Chernikov return (1); 194a6663252SAlexander V. Chernikov 195a6663252SAlexander V. Chernikov i = idx / BLOCK_ITEMS; 196a6663252SAlexander V. Chernikov v = idx % BLOCK_ITEMS; 197a6663252SAlexander V. Chernikov 198a6663252SAlexander V. Chernikov if (i >= bi->blocks) 199a6663252SAlexander V. Chernikov return (1); 200a6663252SAlexander V. Chernikov 201a6663252SAlexander V. Chernikov mask = &bi->idx[i]; 202a6663252SAlexander V. Chernikov 203a6663252SAlexander V. Chernikov if ((*mask & ((u_long)1 << v)) != 0) 204a6663252SAlexander V. Chernikov return (1); 205a6663252SAlexander V. Chernikov 206a6663252SAlexander V. Chernikov /* Mark as free */ 207a6663252SAlexander V. Chernikov *mask |= (u_long)1 << v; 208a6663252SAlexander V. Chernikov bi->items_count--; 209a6663252SAlexander V. Chernikov 210a6663252SAlexander V. Chernikov /* Update free offset */ 211a6663252SAlexander V. Chernikov if (bi->free_off > i) 212a6663252SAlexander V. Chernikov bi->free_off = i; 213a6663252SAlexander V. Chernikov 214a6663252SAlexander V. Chernikov return (0); 215a6663252SAlexander V. Chernikov } 216