mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-02 17:01:49 +00:00
lib, zebra: support label chunk requests for SRGB
For SRGB, we need to support chunk requests starting at a specific point in the label space, rather than just asking for any sufficiently large chunk. To this purpose, we extend the label manager api to request a chunk with a base value; if the base is set to 0, the label manager will behave as it currently does, i.e. fetching the first free chunk big enough to satisfy the request. update all the existing calls to get chunks from the label manager so that they use MPLS_LABEL_BASE_ANY as the base for the requested chunk Signed-off-by: Emanuele Di Pascale <emanuele@voltanet.io>
This commit is contained in:
parent
a7001650c8
commit
0e3b6a926a
@ -29,6 +29,7 @@
|
||||
#include "skiplist.h"
|
||||
#include "workqueue.h"
|
||||
#include "zclient.h"
|
||||
#include "mpls.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_labelpool.h"
|
||||
@ -391,7 +392,8 @@ void bgp_lp_get(
|
||||
if (lp_fifo_count(&lp->requests) > lp->pending_count) {
|
||||
if (!zclient || zclient->sock < 0)
|
||||
return;
|
||||
if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE))
|
||||
if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE,
|
||||
MPLS_LABEL_BASE_ANY))
|
||||
lp->pending_count += LP_CHUNK_SIZE;
|
||||
}
|
||||
}
|
||||
@ -552,7 +554,8 @@ void bgp_lp_event_zebra_up(void)
|
||||
return;
|
||||
}
|
||||
|
||||
zclient_send_get_label_chunk(zclient, 0, labels_needed);
|
||||
zclient_send_get_label_chunk(zclient, 0, labels_needed,
|
||||
MPLS_LABEL_BASE_ANY);
|
||||
lp->pending_count = labels_needed;
|
||||
|
||||
/*
|
||||
|
@ -1660,7 +1660,8 @@ lde_get_label_chunk(void)
|
||||
uint32_t start, end;
|
||||
|
||||
debug_labels("getting label chunk (size %u)", CHUNK_SIZE);
|
||||
ret = lm_get_label_chunk(zclient_sync, 0, CHUNK_SIZE, &start, &end);
|
||||
ret = lm_get_label_chunk(zclient_sync, 0, MPLS_LABEL_BASE_ANY,
|
||||
CHUNK_SIZE, &start, &end);
|
||||
if (ret < 0) {
|
||||
log_warnx("Error getting label chunk!");
|
||||
return -1;
|
||||
|
@ -54,6 +54,7 @@ extern "C" {
|
||||
#define MPLS_LABEL_RESERVED_MAX 15
|
||||
#define MPLS_LABEL_UNRESERVED_MIN 16
|
||||
#define MPLS_LABEL_UNRESERVED_MAX 1048575
|
||||
#define MPLS_LABEL_BASE_ANY 0
|
||||
|
||||
/* Default min and max SRGB label range */
|
||||
/* Even if the SRGB allows to manage different Label space between routers,
|
||||
|
@ -1995,10 +1995,11 @@ int lm_label_manager_connect(struct zclient *zclient, int async)
|
||||
* @param zclient Zclient used to connect to label manager (zebra)
|
||||
* @param keep Avoid garbage collection
|
||||
* @param chunk_size Amount of labels requested
|
||||
* @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care
|
||||
* @result 0 on success, -1 otherwise
|
||||
*/
|
||||
int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
uint32_t chunk_size)
|
||||
uint32_t chunk_size, uint32_t base)
|
||||
{
|
||||
struct stream *s;
|
||||
|
||||
@ -2018,6 +2019,7 @@ int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
stream_putw(s, zclient->instance);
|
||||
stream_putc(s, keep);
|
||||
stream_putl(s, chunk_size);
|
||||
stream_putl(s, base);
|
||||
|
||||
/* Put length at the first point of the stream. */
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
@ -2038,7 +2040,7 @@ int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
* @param end To write last assigned chunk label to
|
||||
* @result 0 on success, -1 otherwise
|
||||
*/
|
||||
int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
int lm_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t base,
|
||||
uint32_t chunk_size, uint32_t *start, uint32_t *end)
|
||||
{
|
||||
int ret;
|
||||
@ -2063,6 +2065,8 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
stream_putc(s, keep);
|
||||
/* chunk size */
|
||||
stream_putl(s, chunk_size);
|
||||
/* requested chunk base */
|
||||
stream_putl(s, base);
|
||||
/* Put length at the first point of the stream. */
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
|
@ -609,15 +609,13 @@ extern struct interface *zebra_interface_link_params_read(struct stream *s,
|
||||
vrf_id_t vrf_id);
|
||||
extern size_t zebra_interface_link_params_write(struct stream *,
|
||||
struct interface *);
|
||||
extern int zclient_send_get_label_chunk(
|
||||
struct zclient *zclient,
|
||||
uint8_t keep,
|
||||
uint32_t chunk_size);
|
||||
extern int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
uint32_t chunk_size, uint32_t base);
|
||||
|
||||
extern int lm_label_manager_connect(struct zclient *zclient, int async);
|
||||
extern int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
uint32_t chunk_size, uint32_t *start,
|
||||
uint32_t *end);
|
||||
uint32_t base, uint32_t chunk_size,
|
||||
uint32_t *start, uint32_t *end);
|
||||
extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
|
||||
uint32_t end);
|
||||
extern int tm_table_manager_connect(struct zclient *zclient);
|
||||
|
@ -80,7 +80,8 @@ static int zebra_send_get_label_chunk()
|
||||
|
||||
printf("Ask for label chunk \n");
|
||||
|
||||
ret = lm_get_label_chunk(zclient, KEEP, CHUNK_SIZE, &start, &end);
|
||||
ret = lm_get_label_chunk(zclient, KEEP, MPLS_LABEL_BASE_ANY, CHUNK_SIZE,
|
||||
&start, &end);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error %d requesting label chunk %s\n", ret,
|
||||
strerror(errno));
|
||||
|
@ -386,8 +386,112 @@ void label_manager_init(char *lm_zserv_path)
|
||||
hook_register(zserv_client_close, release_daemon_label_chunks);
|
||||
}
|
||||
|
||||
/* alloc and fill a label chunk */
|
||||
static struct label_manager_chunk *
|
||||
create_label_chunk(uint8_t proto, unsigned short instance, uint8_t keep,
|
||||
uint32_t start, uint32_t end)
|
||||
{
|
||||
/* alloc chunk, fill it and return it */
|
||||
struct label_manager_chunk *lmc =
|
||||
XCALLOC(MTYPE_LM_CHUNK, sizeof(struct label_manager_chunk));
|
||||
|
||||
lmc->start = start;
|
||||
lmc->end = end;
|
||||
lmc->proto = proto;
|
||||
lmc->instance = instance;
|
||||
lmc->keep = keep;
|
||||
|
||||
return lmc;
|
||||
}
|
||||
|
||||
/* attempt to get a specific label chunk */
|
||||
struct label_manager_chunk *
|
||||
assign_specific_label_chunk(uint8_t proto, unsigned short instance,
|
||||
uint8_t keep, uint32_t size, uint32_t base)
|
||||
{
|
||||
struct label_manager_chunk *lmc;
|
||||
struct listnode *node, *next = NULL;
|
||||
struct listnode *first_node = NULL;
|
||||
struct listnode *last_node = NULL;
|
||||
struct listnode *insert_node = NULL;
|
||||
|
||||
/* precompute last label from base and size */
|
||||
uint32_t end = base + size - 1;
|
||||
|
||||
/* sanities */
|
||||
if ((base < MPLS_LABEL_UNRESERVED_MIN)
|
||||
|| (end > MPLS_LABEL_UNRESERVED_MAX)) {
|
||||
zlog_err("Invalid LM request arguments: base: %u, size: %u",
|
||||
base, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Scan the existing chunks to see if the requested range of labels
|
||||
* falls inside any of such chunks */
|
||||
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
|
||||
|
||||
/* skip chunks for labels < base */
|
||||
if (base > lmc->end)
|
||||
continue;
|
||||
|
||||
/* requested range is not covered by any existing, free chunk.
|
||||
* Therefore, need to insert a chunk */
|
||||
if ((end < lmc->start) && !first_node) {
|
||||
insert_node = node;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!first_node)
|
||||
first_node = node;
|
||||
|
||||
/* if chunk is used, cannot honor request */
|
||||
if (lmc->proto != NO_PROTO)
|
||||
return NULL;
|
||||
|
||||
if (end < lmc->end) {
|
||||
last_node = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* insert chunk between existing chunks */
|
||||
if (insert_node) {
|
||||
lmc = create_label_chunk(proto, instance, keep, base, end);
|
||||
listnode_add_before(lbl_mgr.lc_list, insert_node, lmc);
|
||||
return lmc;
|
||||
}
|
||||
|
||||
if (first_node) {
|
||||
/* get node past the last one, if there */
|
||||
if (last_node)
|
||||
last_node = listnextnode(last_node);
|
||||
|
||||
/* delete node coming after the above chunk whose labels are
|
||||
* included in the previous one */
|
||||
for (node = first_node; node && (node != last_node);
|
||||
node = next) {
|
||||
next = listnextnode(node);
|
||||
list_delete_node(lbl_mgr.lc_list, node);
|
||||
}
|
||||
|
||||
lmc = create_label_chunk(proto, instance, keep, base, end);
|
||||
if (last_node)
|
||||
listnode_add_before(lbl_mgr.lc_list, last_node, lmc);
|
||||
else
|
||||
listnode_add(lbl_mgr.lc_list, lmc);
|
||||
|
||||
return lmc;
|
||||
} else {
|
||||
/* create a new chunk past all the existing ones and link at
|
||||
* tail */
|
||||
lmc = create_label_chunk(proto, instance, keep, base, end);
|
||||
listnode_add(lbl_mgr.lc_list, lmc);
|
||||
return lmc;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Core function, assigns label cunks
|
||||
* Core function, assigns label chunks
|
||||
*
|
||||
* It first searches through the list to check if there's one available
|
||||
* (previously released). Otherwise it creates and assigns a new one
|
||||
@ -395,15 +499,26 @@ void label_manager_init(char *lm_zserv_path)
|
||||
* @param proto Daemon protocol of client, to identify the owner
|
||||
* @param instance Instance, to identify the owner
|
||||
* @param keep If set, avoid garbage collection
|
||||
* @para size Size of the label chunk
|
||||
* @return Pointer to the assigned label chunk
|
||||
* @param size Size of the label chunk
|
||||
* @param base Desired starting label of the chunk; if MPLS_LABEL_BASE_ANY it does not apply
|
||||
* @return Pointer to the assigned label chunk, or NULL if the request could not be satisfied
|
||||
*/
|
||||
struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
||||
unsigned short instance,
|
||||
uint8_t keep, uint32_t size)
|
||||
uint8_t keep, uint32_t size,
|
||||
uint32_t base)
|
||||
{
|
||||
struct label_manager_chunk *lmc;
|
||||
struct listnode *node;
|
||||
uint32_t prev_end = 0;
|
||||
|
||||
/* handle chunks request with a specific base label */
|
||||
if (base != MPLS_LABEL_BASE_ANY)
|
||||
return assign_specific_label_chunk(proto, instance, keep, size,
|
||||
base);
|
||||
|
||||
/* appease scan-build, who gets confused by the use of macros */
|
||||
assert(lbl_mgr.lc_list);
|
||||
|
||||
/* first check if there's one available */
|
||||
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
|
||||
@ -414,35 +529,44 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
||||
lmc->keep = keep;
|
||||
return lmc;
|
||||
}
|
||||
/* check if we hadve a "hole" behind us that we can squeeze into
|
||||
*/
|
||||
if ((lmc->start > prev_end)
|
||||
&& (lmc->start - prev_end >= size)) {
|
||||
lmc = create_label_chunk(proto, instance, keep,
|
||||
prev_end + 1, prev_end + size);
|
||||
listnode_add_before(lbl_mgr.lc_list, node, lmc);
|
||||
return lmc;
|
||||
}
|
||||
prev_end = lmc->end;
|
||||
}
|
||||
/* otherwise create a new one */
|
||||
lmc = XCALLOC(MTYPE_LM_CHUNK, sizeof(struct label_manager_chunk));
|
||||
uint32_t start_free;
|
||||
|
||||
if (list_isempty(lbl_mgr.lc_list))
|
||||
lmc->start = MPLS_LABEL_UNRESERVED_MIN;
|
||||
start_free = MPLS_LABEL_UNRESERVED_MIN;
|
||||
else
|
||||
lmc->start = ((struct label_manager_chunk *)listgetdata(
|
||||
start_free = ((struct label_manager_chunk *)listgetdata(
|
||||
listtail(lbl_mgr.lc_list)))
|
||||
->end
|
||||
+ 1;
|
||||
if (lmc->start > MPLS_LABEL_UNRESERVED_MAX - size + 1) {
|
||||
|
||||
if (start_free > MPLS_LABEL_UNRESERVED_MAX - size + 1) {
|
||||
flog_err(EC_ZEBRA_LM_EXHAUSTED_LABELS,
|
||||
"Reached max labels. Start: %u, size: %u", lmc->start,
|
||||
"Reached max labels. Start: %u, size: %u", start_free,
|
||||
size);
|
||||
XFREE(MTYPE_LM_CHUNK, lmc);
|
||||
return NULL;
|
||||
}
|
||||
lmc->end = lmc->start + size - 1;
|
||||
lmc->proto = proto;
|
||||
lmc->instance = instance;
|
||||
lmc->keep = keep;
|
||||
listnode_add(lbl_mgr.lc_list, lmc);
|
||||
|
||||
/* create chunk and link at tail */
|
||||
lmc = create_label_chunk(proto, instance, keep, start_free,
|
||||
start_free + size - 1);
|
||||
listnode_add(lbl_mgr.lc_list, lmc);
|
||||
return lmc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core function, release no longer used label cunks
|
||||
* Core function, release no longer used label chunks
|
||||
*
|
||||
* @param proto Daemon protocol of client, to identify the owner
|
||||
* @param instance Instance, to identify the owner
|
||||
|
@ -72,7 +72,8 @@ int zread_relay_label_manager_request(int cmd, struct zserv *zserv,
|
||||
void label_manager_init(char *lm_zserv_path);
|
||||
struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
||||
unsigned short instance,
|
||||
uint8_t keep, uint32_t size);
|
||||
uint8_t keep, uint32_t size,
|
||||
uint32_t base);
|
||||
int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
|
||||
uint32_t end);
|
||||
int release_daemon_label_chunks(struct zserv *client);
|
||||
|
@ -1927,7 +1927,7 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
|
||||
{
|
||||
struct stream *s;
|
||||
uint8_t keep;
|
||||
uint32_t size;
|
||||
uint32_t size, base;
|
||||
struct label_manager_chunk *lmc;
|
||||
uint8_t proto;
|
||||
unsigned short instance;
|
||||
@ -1940,8 +1940,9 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
|
||||
STREAM_GETW(s, instance);
|
||||
STREAM_GETC(s, keep);
|
||||
STREAM_GETL(s, size);
|
||||
STREAM_GETL(s, base);
|
||||
|
||||
lmc = assign_label_chunk(proto, instance, keep, size);
|
||||
lmc = assign_label_chunk(proto, instance, keep, size, base);
|
||||
if (!lmc)
|
||||
flog_err(
|
||||
EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK,
|
||||
|
Loading…
Reference in New Issue
Block a user