mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-03 08:46:07 +00:00

This commit introduces lib/id_alloc, which has facilities for both an ID number allocator, and less efficient ID holding pools. The pools are meant to be a temporary holding area for ID numbers meant to be re-used, and are implemented as a linked-list stack. The allocator itself is much more efficient with memory. Based on sizeof values on my 64 bit desktop, the allocator requires around 155 KiB per million IDs tracked. IDs are ultimately tracked in a bit-map split into many "pages." The allocator tracks a list of pages that have free bits, and which sections of each page have free IDs, so there isn't any scanning required to find a free ID. (The library utility ffs, or "Find First Set," is generally a single CPU instruction.) At the moment, totally empty pages will not be freed, so the memory utilization of this allocator will remain at the high water mark. The initial intended use case is for BGP's TX Addpath IDs to be pulled from an allocator that tracks which IDs are in use, rather than a free running counter. The allocator reserves ID #0 as a sentinel value for an invalid ID numbers, and BGP will want ID #1 reserved as well. To support this, the allocator allows for IDs to be explicitly reserved, though be aware this is only practical to use with low numbered IDs because the allocator must allocate pages in order. Signed-off-by Mitchell Skiba <mskiba@amazon.com>
91 lines
2.6 KiB
C
91 lines
2.6 KiB
C
/*
|
|
* FRR ID Number Allocator
|
|
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; see the file COPYING; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#ifndef _ZEBRA_ID_ALLOC_H
|
|
#define _ZEBRA_ID_ALLOC_H
|
|
|
|
#include <strings.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
|
|
#define IDALLOC_INVALID 0
|
|
|
|
#define IDALLOC_DIR_BITS 8
|
|
#define IDALLOC_SUBDIR_BITS 7
|
|
#define IDALLOC_PAGE_BITS 7
|
|
#define IDALLOC_WORD_BITS 5
|
|
#define IDALLOC_OFFSET_BITS 5
|
|
|
|
#define IDALLOC_DIR_COUNT (1 << IDALLOC_DIR_BITS)
|
|
#define IDALLOC_SUBDIR_COUNT (1 << IDALLOC_SUBDIR_BITS)
|
|
#define IDALLOC_PAGE_COUNT (1 << IDALLOC_PAGE_BITS)
|
|
#define IDALLOC_WORD_COUNT (1 << IDALLOC_WORD_BITS)
|
|
|
|
struct id_alloc_page {
|
|
/* Bitmask of allocations. 1s indicates the ID is already allocated. */
|
|
uint32_t allocated_mask[IDALLOC_WORD_COUNT];
|
|
|
|
/* Bitmask for free space in allocated_mask. 1s indicate whole 32 bit
|
|
* section is full.
|
|
*/
|
|
uint32_t full_word_mask;
|
|
|
|
/* The ID that bit 0 in allocated_mask corresponds to. */
|
|
uint32_t base_value;
|
|
|
|
struct id_alloc_page
|
|
*next_has_free; /* Next page with at least one bit open */
|
|
};
|
|
|
|
struct id_alloc_subdir {
|
|
struct id_alloc_page *sublevels[IDALLOC_PAGE_COUNT];
|
|
};
|
|
|
|
struct id_alloc_dir {
|
|
struct id_alloc_subdir *sublevels[IDALLOC_SUBDIR_COUNT];
|
|
};
|
|
|
|
struct id_alloc {
|
|
struct id_alloc_dir *sublevels[IDALLOC_DIR_COUNT];
|
|
|
|
struct id_alloc_page *has_free;
|
|
|
|
char *name;
|
|
|
|
uint32_t allocated, capacity;
|
|
};
|
|
|
|
struct id_alloc_pool {
|
|
struct id_alloc_pool *next;
|
|
uint32_t id;
|
|
};
|
|
|
|
void idalloc_free(struct id_alloc *alloc, uint32_t id);
|
|
void idalloc_free_to_pool(struct id_alloc_pool **pool_ptr, uint32_t id);
|
|
void idalloc_drain_pool(struct id_alloc *alloc,
|
|
struct id_alloc_pool **pool_ptr);
|
|
uint32_t idalloc_allocate(struct id_alloc *alloc);
|
|
uint32_t idalloc_allocate_prefer_pool(struct id_alloc *alloc,
|
|
struct id_alloc_pool **pool_ptr);
|
|
uint32_t idalloc_reserve(struct id_alloc *alloc, uint32_t id);
|
|
struct id_alloc *idalloc_new(const char *name);
|
|
void idalloc_destroy(struct id_alloc *alloc);
|
|
|
|
#endif
|