2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2020-12-09 10:52:17 +01:00
|
|
|
/*
|
|
|
|
* Zebra SRv6 definitions
|
|
|
|
* Copyright (C) 2020 Hiroki Shirokura, LINE Corporation
|
|
|
|
* Copyright (C) 2020 Masakazu Asama
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "network.h"
|
|
|
|
#include "prefix.h"
|
|
|
|
#include "stream.h"
|
|
|
|
#include "srv6.h"
|
|
|
|
#include "zebra/debug.h"
|
|
|
|
#include "zebra/zapi_msg.h"
|
|
|
|
#include "zebra/zserv.h"
|
|
|
|
#include "zebra/zebra_router.h"
|
|
|
|
#include "zebra/zebra_srv6.h"
|
|
|
|
#include "zebra/zebra_errors.h"
|
2023-12-07 18:31:37 +01:00
|
|
|
#include "zebra/ge_netlink.h"
|
2020-12-09 10:52:17 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
|
|
|
|
|
|
DEFINE_MGROUP(SRV6_MGR, "SRv6 Manager");
|
|
|
|
DEFINE_MTYPE_STATIC(SRV6_MGR, SRV6M_CHUNK, "SRv6 Manager Chunk");
|
2024-03-22 18:19:36 +01:00
|
|
|
DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_BLOCK, "SRv6 SID block");
|
|
|
|
DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_FUNC, "SRv6 SID function");
|
|
|
|
DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_USID_WLIB,
|
|
|
|
"SRv6 uSID Wide LIB information");
|
2024-03-23 13:42:19 +01:00
|
|
|
DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID, "SRv6 SID");
|
|
|
|
DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_CTX, "SRv6 SID context");
|
2020-12-09 10:52:17 +01:00
|
|
|
|
|
|
|
/* define hooks for the basic API, so that it can be specialized or served
|
|
|
|
* externally
|
|
|
|
*/
|
|
|
|
|
|
|
|
DEFINE_HOOK(srv6_manager_client_connect,
|
|
|
|
(struct zserv *client, vrf_id_t vrf_id),
|
|
|
|
(client, vrf_id));
|
|
|
|
DEFINE_HOOK(srv6_manager_client_disconnect,
|
|
|
|
(struct zserv *client), (client));
|
|
|
|
DEFINE_HOOK(srv6_manager_get_chunk,
|
|
|
|
(struct srv6_locator **loc,
|
|
|
|
struct zserv *client,
|
|
|
|
const char *locator_name,
|
|
|
|
vrf_id_t vrf_id),
|
|
|
|
(loc, client, locator_name, vrf_id));
|
|
|
|
DEFINE_HOOK(srv6_manager_release_chunk,
|
|
|
|
(struct zserv *client,
|
|
|
|
const char *locator_name,
|
|
|
|
vrf_id_t vrf_id),
|
|
|
|
(client, locator_name, vrf_id));
|
|
|
|
|
2024-03-23 15:50:24 +01:00
|
|
|
DEFINE_HOOK(srv6_manager_get_locator,
|
|
|
|
(struct srv6_locator **locator, struct zserv *client,
|
|
|
|
const char *locator_name),
|
|
|
|
(locator, client, locator_name));
|
|
|
|
|
2020-12-09 10:52:17 +01:00
|
|
|
/* define wrappers to be called in zapi_msg.c (as hooks must be called in
|
|
|
|
* source file where they were defined)
|
|
|
|
*/
|
|
|
|
|
|
|
|
void srv6_manager_client_connect_call(struct zserv *client, vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
hook_call(srv6_manager_client_connect, client, vrf_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void srv6_manager_get_locator_chunk_call(struct srv6_locator **loc,
|
|
|
|
struct zserv *client,
|
|
|
|
const char *locator_name,
|
|
|
|
vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
hook_call(srv6_manager_get_chunk, loc, client, locator_name, vrf_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void srv6_manager_release_locator_chunk_call(struct zserv *client,
|
|
|
|
const char *locator_name,
|
|
|
|
vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
hook_call(srv6_manager_release_chunk, client, locator_name, vrf_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
int srv6_manager_client_disconnect_cb(struct zserv *client)
|
|
|
|
{
|
|
|
|
hook_call(srv6_manager_client_disconnect, client);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-03-23 15:50:24 +01:00
|
|
|
void srv6_manager_get_locator_call(struct srv6_locator **locator,
|
|
|
|
struct zserv *client,
|
|
|
|
const char *locator_name)
|
|
|
|
{
|
|
|
|
hook_call(srv6_manager_get_locator, locator, client, locator_name);
|
|
|
|
}
|
|
|
|
|
2020-12-09 10:52:17 +01:00
|
|
|
static int zebra_srv6_cleanup(struct zserv *client)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-03-23 13:42:19 +01:00
|
|
|
/* --- Zebra SRv6 SID context management functions -------------------------- */
|
|
|
|
|
|
|
|
struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void)
|
|
|
|
{
|
|
|
|
struct zebra_srv6_sid_ctx *ctx = NULL;
|
|
|
|
|
|
|
|
ctx = XCALLOC(MTYPE_ZEBRA_SRV6_SID_CTX,
|
|
|
|
sizeof(struct zebra_srv6_sid_ctx));
|
|
|
|
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_ZEBRA_SRV6_SID_CTX, ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free an SRv6 SID context.
|
|
|
|
*
|
|
|
|
* @param val SRv6 SID context to be freed
|
|
|
|
*/
|
|
|
|
void delete_zebra_srv6_sid_ctx(void *val)
|
|
|
|
{
|
|
|
|
zebra_srv6_sid_ctx_free((struct zebra_srv6_sid_ctx *)val);
|
|
|
|
}
|
|
|
|
|
2024-06-06 17:23:11 +02:00
|
|
|
/* --- Zebra SRv6 SID format management functions --------------------------- */
|
|
|
|
|
2024-03-26 08:53:55 +01:00
|
|
|
void srv6_sid_format_register(struct srv6_sid_format *format)
|
2024-06-06 17:23:11 +02:00
|
|
|
{
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
|
|
|
|
|
|
|
/* Ensure that the format is registered only once */
|
2024-03-26 08:53:55 +01:00
|
|
|
assert(!srv6_sid_format_lookup(format->name));
|
2024-06-06 17:23:11 +02:00
|
|
|
|
|
|
|
listnode_add(srv6->sid_formats, format);
|
|
|
|
}
|
|
|
|
|
2024-03-26 08:53:55 +01:00
|
|
|
void srv6_sid_format_unregister(struct srv6_sid_format *format)
|
2024-06-06 17:23:11 +02:00
|
|
|
{
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
|
|
|
|
|
|
|
listnode_delete(srv6->sid_formats, format);
|
|
|
|
}
|
|
|
|
|
2024-03-26 08:53:55 +01:00
|
|
|
struct srv6_sid_format *srv6_sid_format_lookup(const char *name)
|
2024-06-06 17:23:11 +02:00
|
|
|
{
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
2024-03-22 15:56:15 +01:00
|
|
|
struct srv6_sid_format *format;
|
2024-06-06 17:23:11 +02:00
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format))
|
|
|
|
if (!strncmp(name, format->name, sizeof(format->name)))
|
|
|
|
return format;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-03-22 19:31:01 +01:00
|
|
|
/*
|
|
|
|
* Called to change the SID format of a locator.
|
|
|
|
*
|
|
|
|
* After switching the locator to a different format, the SIDs allocated
|
|
|
|
* from the locator may no longer be valid; we need to notify the
|
|
|
|
* interested zclient that the locator has changed, so that the
|
|
|
|
* zclients can withdraw/uninstall the old SIDs, allocate/advertise/program
|
|
|
|
* the new SIDs.
|
|
|
|
*/
|
|
|
|
void zebra_srv6_locator_format_set(struct srv6_locator *locator,
|
|
|
|
struct srv6_sid_format *format)
|
|
|
|
{
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
|
|
|
struct zebra_srv6_sid_block *block_old, *block_new;
|
|
|
|
struct prefix_ipv6 block_pfx_new;
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
struct zebra_srv6_sid_ctx *ctx;
|
|
|
|
|
|
|
|
if (!locator)
|
|
|
|
return;
|
|
|
|
|
|
|
|
locator->sid_format = format;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_PACKET)
|
|
|
|
zlog_debug("%s: Locator %s format has changed, old=%s new=%s",
|
|
|
|
__func__, locator->name,
|
|
|
|
locator->sid_format ? ((struct srv6_sid_format *)
|
|
|
|
locator->sid_format)
|
|
|
|
->name
|
|
|
|
: NULL,
|
|
|
|
format ? format->name : NULL);
|
|
|
|
|
|
|
|
/* Notify zclients that the locator is no longer valid */
|
|
|
|
zebra_notify_srv6_locator_delete(locator);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) {
|
|
|
|
if (!ctx->sid || ctx->sid->locator != locator)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ctx->sid)
|
|
|
|
zebra_srv6_sid_free(ctx->sid);
|
|
|
|
|
|
|
|
listnode_delete(srv6->sids, ctx);
|
|
|
|
zebra_srv6_sid_ctx_free(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_PACKET)
|
|
|
|
zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_DEL notification to zclients",
|
|
|
|
__func__, locator->name);
|
|
|
|
|
|
|
|
/* Release the current parent block */
|
|
|
|
block_old = locator->sid_block;
|
|
|
|
if (block_old) {
|
|
|
|
block_old->refcnt--;
|
|
|
|
if (block_old->refcnt == 0) {
|
|
|
|
listnode_delete(srv6->sid_blocks, block_old);
|
|
|
|
zebra_srv6_sid_block_free(block_old);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
locator->sid_block = NULL;
|
|
|
|
|
|
|
|
block_pfx_new = locator->prefix;
|
|
|
|
if (format)
|
|
|
|
block_pfx_new.prefixlen = format->block_len;
|
|
|
|
else
|
|
|
|
block_pfx_new.prefixlen = locator->block_bits_length;
|
|
|
|
apply_mask(&block_pfx_new);
|
|
|
|
|
|
|
|
/* Allocate the new parent block */
|
|
|
|
block_new = zebra_srv6_sid_block_lookup(&block_pfx_new);
|
|
|
|
if (!block_new) {
|
|
|
|
block_new = zebra_srv6_sid_block_alloc(format, &block_pfx_new);
|
|
|
|
listnode_add(srv6->sid_blocks, block_new);
|
|
|
|
}
|
|
|
|
|
|
|
|
block_new->refcnt++;
|
|
|
|
locator->sid_block = block_new;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_PACKET)
|
|
|
|
zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_ADD notification to zclients",
|
|
|
|
__func__, locator->name);
|
|
|
|
|
|
|
|
/* Notify zclients about the updated locator */
|
|
|
|
zebra_srv6_locator_add(locator);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called when a SID format is modified by the user.
|
|
|
|
*
|
|
|
|
* After modifying a SID format, the SIDs that are using that format may no
|
|
|
|
* longer be valid.
|
|
|
|
* This function walks through the list of locators that are using the SID format
|
|
|
|
* and notifies the zclients that the locator has changed, so that the zclients
|
|
|
|
* can withdraw/uninstall the old SIDs, allocate/program/advertise the new SIDs.
|
|
|
|
*/
|
|
|
|
void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format)
|
|
|
|
{
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
|
|
|
struct srv6_locator *locator;
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
struct zebra_srv6_sid_ctx *ctx;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_PACKET)
|
|
|
|
zlog_debug("%s: SID format %s has changed. Notifying zclients.",
|
|
|
|
__func__, format->name);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) {
|
|
|
|
if (locator->sid_format == format) {
|
|
|
|
if (IS_ZEBRA_DEBUG_PACKET)
|
|
|
|
zlog_debug("%s: Locator %s has changed because its format (%s) has been modified. Notifying zclients.",
|
|
|
|
__func__, locator->name,
|
|
|
|
format->name);
|
|
|
|
|
|
|
|
/* Notify zclients that the locator is no longer valid */
|
|
|
|
zebra_notify_srv6_locator_delete(locator);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) {
|
|
|
|
if (!ctx->sid || ctx->sid->locator != locator)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ctx->sid)
|
|
|
|
zebra_srv6_sid_free(ctx->sid);
|
|
|
|
|
|
|
|
listnode_delete(srv6->sids, ctx);
|
|
|
|
zebra_srv6_sid_ctx_free(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Notify zclients about the updated locator */
|
|
|
|
zebra_notify_srv6_locator_add(locator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-06 17:23:11 +02:00
|
|
|
/*
|
|
|
|
* Helper function to create the SRv6 compressed format `usid-f3216`.
|
|
|
|
*/
|
2024-03-22 15:56:15 +01:00
|
|
|
static struct srv6_sid_format *create_srv6_sid_format_usid_f3216(void)
|
2024-06-06 17:23:11 +02:00
|
|
|
{
|
2024-03-22 15:56:15 +01:00
|
|
|
struct srv6_sid_format *format = NULL;
|
2024-06-06 17:23:11 +02:00
|
|
|
|
2024-03-26 08:53:55 +01:00
|
|
|
format = srv6_sid_format_alloc(SRV6_SID_FORMAT_USID_F3216_NAME);
|
2024-06-06 17:23:11 +02:00
|
|
|
|
|
|
|
format->type = SRV6_SID_FORMAT_TYPE_USID;
|
|
|
|
|
|
|
|
/* Define block/node/function length */
|
2024-03-26 08:53:55 +01:00
|
|
|
format->block_len = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN;
|
|
|
|
format->node_len = SRV6_SID_FORMAT_USID_F3216_NODE_LEN;
|
|
|
|
format->function_len = SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN;
|
|
|
|
format->argument_len = SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN;
|
2024-06-06 17:23:11 +02:00
|
|
|
|
|
|
|
/* Define the ranges from which the SID function can be allocated */
|
2024-03-26 08:53:55 +01:00
|
|
|
format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START;
|
|
|
|
format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START;
|
|
|
|
format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END;
|
|
|
|
format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START;
|
|
|
|
format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END;
|
|
|
|
format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START;
|
2024-06-06 17:23:11 +02:00
|
|
|
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Helper function to create the SRv6 uncompressed format.
|
|
|
|
*/
|
2024-03-22 15:56:15 +01:00
|
|
|
static struct srv6_sid_format *create_srv6_sid_format_uncompressed(void)
|
2024-06-06 17:23:11 +02:00
|
|
|
{
|
2024-03-22 15:56:15 +01:00
|
|
|
struct srv6_sid_format *format = NULL;
|
2024-06-06 17:23:11 +02:00
|
|
|
|
2024-03-26 08:53:55 +01:00
|
|
|
format = srv6_sid_format_alloc(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME);
|
2024-06-06 17:23:11 +02:00
|
|
|
|
2024-03-26 08:53:55 +01:00
|
|
|
format->type = SRV6_SID_FORMAT_TYPE_UNCOMPRESSED;
|
2024-06-06 17:23:11 +02:00
|
|
|
|
|
|
|
/* Define block/node/function length */
|
2024-03-26 08:53:55 +01:00
|
|
|
format->block_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN;
|
|
|
|
format->node_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN;
|
|
|
|
format->function_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN;
|
|
|
|
format->argument_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN;
|
2024-06-06 17:23:11 +02:00
|
|
|
|
|
|
|
/* Define the ranges from which the SID function can be allocated */
|
|
|
|
format->config.uncompressed.explicit_start =
|
2024-03-26 08:53:55 +01:00
|
|
|
SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START;
|
2024-06-06 17:23:11 +02:00
|
|
|
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
2024-03-22 18:19:36 +01:00
|
|
|
/* --- Zebra SRv6 SID function management functions ---------------------------- */
|
|
|
|
|
|
|
|
uint32_t *zebra_srv6_sid_func_alloc(uint32_t func)
|
|
|
|
{
|
|
|
|
uint32_t *sid_func_ptr;
|
|
|
|
|
|
|
|
sid_func_ptr = XCALLOC(MTYPE_ZEBRA_SRV6_SID_FUNC, sizeof(uint32_t));
|
|
|
|
*sid_func_ptr = func;
|
|
|
|
|
|
|
|
return sid_func_ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_srv6_sid_func_free(uint32_t *func)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_ZEBRA_SRV6_SID_FUNC, func);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free an SRv6 SID function.
|
|
|
|
*
|
|
|
|
* @param val SRv6 SID function to be freed
|
|
|
|
*/
|
|
|
|
void delete_zebra_srv6_sid_func(void *val)
|
|
|
|
{
|
|
|
|
zebra_srv6_sid_func_free((uint32_t *)val);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --- Zebra SRv6 SID block management functions ---------------------------- */
|
|
|
|
|
|
|
|
static struct zebra_srv6_sid_block *zebra_srv6_sid_block_alloc_internal(void)
|
|
|
|
{
|
|
|
|
struct zebra_srv6_sid_block *block = NULL;
|
|
|
|
|
|
|
|
block = XCALLOC(MTYPE_ZEBRA_SRV6_SID_BLOCK,
|
|
|
|
sizeof(struct zebra_srv6_sid_block));
|
|
|
|
|
|
|
|
return block;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct zebra_srv6_sid_block *
|
|
|
|
zebra_srv6_sid_block_alloc(struct srv6_sid_format *format,
|
|
|
|
struct prefix_ipv6 *prefix)
|
|
|
|
{
|
|
|
|
struct zebra_srv6_sid_block *block;
|
|
|
|
|
|
|
|
block = zebra_srv6_sid_block_alloc_internal();
|
|
|
|
block->sid_format = format;
|
|
|
|
block->prefix = *prefix;
|
|
|
|
|
|
|
|
if (format) {
|
|
|
|
if (format->type == SRV6_SID_FORMAT_TYPE_USID) {
|
|
|
|
uint32_t wlib_start, wlib_end, func;
|
|
|
|
|
|
|
|
/* Init uSID LIB */
|
|
|
|
block->u.usid.lib.func_allocated = list_new();
|
|
|
|
block->u.usid.lib.func_allocated->del =
|
|
|
|
delete_zebra_srv6_sid_func;
|
|
|
|
block->u.usid.lib.func_released = list_new();
|
|
|
|
block->u.usid.lib.func_released->del =
|
|
|
|
delete_zebra_srv6_sid_func;
|
|
|
|
block->u.usid.lib.first_available_func =
|
|
|
|
format->config.usid.lib_start;
|
|
|
|
|
|
|
|
/* Init uSID Wide LIB */
|
|
|
|
wlib_start = block->sid_format->config.usid.wlib_start;
|
|
|
|
wlib_end = block->sid_format->config.usid.wlib_end;
|
|
|
|
block->u.usid.wide_lib =
|
|
|
|
XCALLOC(MTYPE_ZEBRA_SRV6_USID_WLIB,
|
|
|
|
(wlib_end - wlib_start + 1) *
|
|
|
|
sizeof(struct wide_lib));
|
|
|
|
for (func = 0; func < wlib_end - wlib_start + 1;
|
|
|
|
func++) {
|
|
|
|
block->u.usid.wide_lib[func].func_allocated =
|
|
|
|
list_new();
|
|
|
|
block->u.usid.wide_lib[func].func_allocated->del =
|
|
|
|
delete_zebra_srv6_sid_func;
|
|
|
|
block->u.usid.wide_lib[func].func_released =
|
|
|
|
list_new();
|
|
|
|
block->u.usid.wide_lib[func].func_released->del =
|
|
|
|
delete_zebra_srv6_sid_func;
|
|
|
|
block->u.usid.wide_lib[func].func = func;
|
|
|
|
}
|
|
|
|
} else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) {
|
|
|
|
block->u.uncompressed.func_allocated = list_new();
|
|
|
|
block->u.uncompressed.func_allocated->del =
|
|
|
|
delete_zebra_srv6_sid_func;
|
|
|
|
block->u.uncompressed.func_released = list_new();
|
|
|
|
block->u.uncompressed.func_released->del =
|
|
|
|
delete_zebra_srv6_sid_func;
|
|
|
|
block->u.uncompressed.first_available_func =
|
|
|
|
SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN;
|
|
|
|
} else {
|
|
|
|
/* We should never arrive here */
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
block->u.uncompressed.func_allocated = list_new();
|
|
|
|
block->u.uncompressed.func_allocated->del =
|
|
|
|
delete_zebra_srv6_sid_func;
|
|
|
|
block->u.uncompressed.func_released = list_new();
|
|
|
|
block->u.uncompressed.func_released->del =
|
|
|
|
delete_zebra_srv6_sid_func;
|
|
|
|
block->u.uncompressed.first_available_func = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return block;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block)
|
|
|
|
{
|
|
|
|
if (block->sid_format) {
|
|
|
|
if (block->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) {
|
|
|
|
uint32_t wlib_start, wlib_end, func;
|
|
|
|
|
|
|
|
/* Free uSID LIB */
|
|
|
|
list_delete(&block->u.usid.lib.func_allocated);
|
|
|
|
list_delete(&block->u.usid.lib.func_released);
|
|
|
|
|
|
|
|
/* Free uSID Wide LIB */
|
|
|
|
wlib_start = block->sid_format->config.usid.wlib_start;
|
|
|
|
wlib_end = block->sid_format->config.usid.wlib_end;
|
|
|
|
for (func = 0; func < wlib_end - wlib_start + 1;
|
|
|
|
func++) {
|
|
|
|
list_delete(&block->u.usid.wide_lib[func]
|
|
|
|
.func_allocated);
|
|
|
|
list_delete(&block->u.usid.wide_lib[func]
|
|
|
|
.func_released);
|
|
|
|
}
|
|
|
|
XFREE(MTYPE_ZEBRA_SRV6_USID_WLIB,
|
|
|
|
block->u.usid.wide_lib);
|
|
|
|
} else if (block->sid_format->type ==
|
|
|
|
SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) {
|
|
|
|
list_delete(&block->u.uncompressed.func_allocated);
|
|
|
|
list_delete(&block->u.uncompressed.func_released);
|
|
|
|
} else {
|
|
|
|
/* We should never arrive here */
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
list_delete(&block->u.uncompressed.func_allocated);
|
|
|
|
list_delete(&block->u.uncompressed.func_released);
|
|
|
|
}
|
|
|
|
|
|
|
|
XFREE(MTYPE_ZEBRA_SRV6_SID_BLOCK, block);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free an SRv6 SID block.
|
|
|
|
*
|
|
|
|
* @param val SRv6 SID block to be freed
|
|
|
|
*/
|
|
|
|
void delete_zebra_srv6_sid_block(void *val)
|
|
|
|
{
|
|
|
|
zebra_srv6_sid_block_free((struct zebra_srv6_sid_block *)val);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct zebra_srv6_sid_block *
|
|
|
|
zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix)
|
|
|
|
{
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
|
|
|
struct zebra_srv6_sid_block *block;
|
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, block))
|
|
|
|
if (prefix_match(prefix, &block->prefix))
|
|
|
|
return block;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-03-23 13:42:19 +01:00
|
|
|
/* --- Zebra SRv6 SID management functions ---------------------------------- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Alloc and fill an SRv6 SID.
|
|
|
|
*
|
|
|
|
* @param ctx Context associated with the SID to be created
|
|
|
|
* @param sid_value IPv6 address associated with the SID to be created
|
|
|
|
* @param locator Parent locator of the SID to be created
|
|
|
|
* @param sid_block Block from which the SID value has been allocated
|
|
|
|
* @param sid_func Function part of the SID to be created
|
|
|
|
* @param alloc_mode Allocation mode of the Function (dynamic vs explicit)
|
|
|
|
* @return The requested SID
|
|
|
|
*/
|
|
|
|
struct zebra_srv6_sid *
|
|
|
|
zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value,
|
|
|
|
struct srv6_locator *locator,
|
|
|
|
struct zebra_srv6_sid_block *sid_block, uint32_t sid_func,
|
|
|
|
enum srv6_sid_alloc_mode alloc_mode)
|
|
|
|
{
|
|
|
|
struct zebra_srv6_sid *sid;
|
|
|
|
|
|
|
|
if (!ctx || !sid_value)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
sid = XCALLOC(MTYPE_ZEBRA_SRV6_SID, sizeof(struct zebra_srv6_sid));
|
|
|
|
sid->ctx = ctx;
|
|
|
|
sid->value = *sid_value;
|
|
|
|
sid->locator = locator;
|
|
|
|
sid->block = sid_block;
|
|
|
|
sid->func = sid_func;
|
|
|
|
sid->alloc_mode = alloc_mode;
|
|
|
|
sid->client_list = list_new();
|
|
|
|
|
|
|
|
return sid;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_srv6_sid_free(struct zebra_srv6_sid *sid)
|
|
|
|
{
|
|
|
|
list_delete(&sid->client_list);
|
|
|
|
XFREE(MTYPE_ZEBRA_SRV6_SID, sid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free an SRv6 SID.
|
|
|
|
*
|
|
|
|
* @param val SRv6 SID to be freed
|
|
|
|
*/
|
|
|
|
void delete_zebra_srv6_sid(void *val)
|
|
|
|
{
|
|
|
|
zebra_srv6_sid_free((struct zebra_srv6_sid *)val);
|
|
|
|
}
|
|
|
|
|
2020-12-09 10:52:17 +01:00
|
|
|
void zebra_srv6_locator_add(struct srv6_locator *locator)
|
|
|
|
{
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
|
|
|
struct srv6_locator *tmp;
|
2021-09-05 12:05:53 +02:00
|
|
|
struct listnode *node;
|
|
|
|
struct zserv *client;
|
2020-12-09 10:52:17 +01:00
|
|
|
|
|
|
|
tmp = zebra_srv6_locator_lookup(locator->name);
|
|
|
|
if (!tmp)
|
|
|
|
listnode_add(srv6->locators, locator);
|
2021-09-05 12:05:53 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Notify new locator info to zclients.
|
|
|
|
*
|
|
|
|
* The srv6 locators and their prefixes are managed by zserv(zebra).
|
|
|
|
* And an actual configuration the srv6 sid in the srv6 locator is done
|
|
|
|
* by zclient(bgpd, isisd, etc). The configuration of each locator
|
|
|
|
* allocation and specify it by zserv and zclient should be
|
|
|
|
* asynchronous. For that, zclient should be received the event via
|
|
|
|
* ZAPI when a srv6 locator is added on zebra.
|
|
|
|
* Basically, in SRv6, adding/removing SRv6 locators is performed less
|
|
|
|
* frequently than adding rib entries, so a broad to all zclients will
|
|
|
|
* not degrade the overall performance of FRRouting.
|
|
|
|
*/
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
|
|
|
|
zsend_zebra_srv6_locator_add(client, locator);
|
2020-12-09 10:52:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_srv6_locator_delete(struct srv6_locator *locator)
|
|
|
|
{
|
2021-09-05 12:05:53 +02:00
|
|
|
struct listnode *n;
|
|
|
|
struct srv6_locator_chunk *c;
|
2020-12-09 10:52:17 +01:00
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
2021-09-05 12:05:53 +02:00
|
|
|
struct zserv *client;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Notify deleted locator info to zclients if needed.
|
|
|
|
*
|
|
|
|
* zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
|
|
|
|
* uses it for its own purpose. For example, in the case of BGP L3VPN,
|
|
|
|
* the SID assigned to vpn unicast rib will be given.
|
|
|
|
* And when the locator is deleted by zserv(zebra), those SIDs need to
|
|
|
|
* be withdrawn. The zclient must initiate the withdrawal of the SIDs
|
|
|
|
* by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
|
|
|
|
* owner of each chunk.
|
|
|
|
*/
|
|
|
|
for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) {
|
|
|
|
if (c->proto == ZEBRA_ROUTE_SYSTEM)
|
|
|
|
continue;
|
|
|
|
client = zserv_find_client(c->proto, c->instance);
|
|
|
|
if (!client) {
|
|
|
|
zlog_warn(
|
|
|
|
"%s: Not found zclient(proto=%u, instance=%u).",
|
|
|
|
__func__, c->proto, c->instance);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
zsend_zebra_srv6_locator_delete(client, locator);
|
|
|
|
}
|
2021-02-24 11:47:05 +01:00
|
|
|
|
2020-12-09 10:52:17 +01:00
|
|
|
listnode_delete(srv6->locators, locator);
|
2022-08-23 22:40:47 +02:00
|
|
|
srv6_locator_free(locator);
|
2020-12-09 10:52:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
struct srv6_locator *zebra_srv6_locator_lookup(const char *name)
|
|
|
|
{
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
|
|
|
struct srv6_locator *locator;
|
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator))
|
|
|
|
if (!strncmp(name, locator->name, SRV6_LOCNAME_SIZE))
|
|
|
|
return locator;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-10-29 01:28:30 +02:00
|
|
|
void zebra_notify_srv6_locator_add(struct srv6_locator *locator)
|
|
|
|
{
|
|
|
|
struct listnode *node;
|
|
|
|
struct zserv *client;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Notify new locator info to zclients.
|
|
|
|
*
|
|
|
|
* The srv6 locators and their prefixes are managed by zserv(zebra).
|
|
|
|
* And an actual configuration the srv6 sid in the srv6 locator is done
|
|
|
|
* by zclient(bgpd, isisd, etc). The configuration of each locator
|
|
|
|
* allocation and specify it by zserv and zclient should be
|
|
|
|
* asynchronous. For that, zclient should be received the event via
|
|
|
|
* ZAPI when a srv6 locator is added on zebra.
|
|
|
|
* Basically, in SRv6, adding/removing SRv6 locators is performed less
|
|
|
|
* frequently than adding rib entries, so a broad to all zclients will
|
|
|
|
* not degrade the overall performance of FRRouting.
|
|
|
|
*/
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
|
|
|
|
zsend_zebra_srv6_locator_add(client, locator);
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_notify_srv6_locator_delete(struct srv6_locator *locator)
|
|
|
|
{
|
|
|
|
struct listnode *n;
|
|
|
|
struct srv6_locator_chunk *c;
|
|
|
|
struct zserv *client;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Notify deleted locator info to zclients if needed.
|
|
|
|
*
|
|
|
|
* zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
|
|
|
|
* uses it for its own purpose. For example, in the case of BGP L3VPN,
|
|
|
|
* the SID assigned to vpn unicast rib will be given.
|
|
|
|
* And when the locator is deleted by zserv(zebra), those SIDs need to
|
|
|
|
* be withdrawn. The zclient must initiate the withdrawal of the SIDs
|
|
|
|
* by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
|
|
|
|
* owner of each chunk.
|
|
|
|
*/
|
|
|
|
for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) {
|
|
|
|
if (c->proto == ZEBRA_ROUTE_SYSTEM)
|
|
|
|
continue;
|
|
|
|
client = zserv_find_client(c->proto, c->instance);
|
|
|
|
if (!client) {
|
|
|
|
zlog_warn("Not found zclient(proto=%u, instance=%u).",
|
|
|
|
c->proto, c->instance);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
zsend_zebra_srv6_locator_delete(client, locator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-12 18:03:10 +01:00
|
|
|
struct zebra_srv6 srv6;
|
|
|
|
|
2020-12-09 10:52:17 +01:00
|
|
|
struct zebra_srv6 *zebra_srv6_get_default(void)
|
|
|
|
{
|
|
|
|
static bool first_execution = true;
|
2024-03-22 15:56:15 +01:00
|
|
|
struct srv6_sid_format *format_usidf3216;
|
|
|
|
struct srv6_sid_format *format_uncompressed;
|
2020-12-09 10:52:17 +01:00
|
|
|
|
|
|
|
if (first_execution) {
|
|
|
|
first_execution = false;
|
|
|
|
srv6.locators = list_new();
|
2024-06-06 17:23:11 +02:00
|
|
|
|
|
|
|
/* Initialize list of SID formats */
|
|
|
|
srv6.sid_formats = list_new();
|
2024-03-22 15:56:15 +01:00
|
|
|
srv6.sid_formats->del = delete_srv6_sid_format;
|
2024-06-06 17:23:11 +02:00
|
|
|
|
|
|
|
/* Create SID format `usid-f3216` */
|
|
|
|
format_usidf3216 = create_srv6_sid_format_usid_f3216();
|
2024-03-26 08:53:55 +01:00
|
|
|
srv6_sid_format_register(format_usidf3216);
|
2024-06-06 17:23:11 +02:00
|
|
|
|
|
|
|
/* Create SID format `uncompressed` */
|
|
|
|
format_uncompressed = create_srv6_sid_format_uncompressed();
|
2024-03-26 08:53:55 +01:00
|
|
|
srv6_sid_format_register(format_uncompressed);
|
2024-03-22 18:19:36 +01:00
|
|
|
|
2024-03-23 13:42:19 +01:00
|
|
|
/* Init list to store SRv6 SIDs */
|
|
|
|
srv6.sids = list_new();
|
|
|
|
srv6.sids->del = delete_zebra_srv6_sid_ctx;
|
|
|
|
|
2024-03-22 18:19:36 +01:00
|
|
|
/* Init list to store SRv6 SID blocks */
|
|
|
|
srv6.sid_blocks = list_new();
|
|
|
|
srv6.sid_blocks->del = delete_zebra_srv6_sid_block;
|
2020-12-09 10:52:17 +01:00
|
|
|
}
|
|
|
|
return &srv6;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Core function, assigns srv6-locator chunks
|
|
|
|
*
|
|
|
|
* It first searches through the list to check if there's one available
|
|
|
|
* (previously released). Otherwise it creates and assigns a new one
|
|
|
|
*
|
|
|
|
* @param proto Daemon protocol of client, to identify the owner
|
|
|
|
* @param instance Instance, to identify the owner
|
|
|
|
* @param session_id SessionID of client
|
|
|
|
* @param name Name of SRv6-locator
|
|
|
|
* @return Pointer to the assigned srv6-locator chunk,
|
|
|
|
* or NULL if the request could not be satisfied
|
|
|
|
*/
|
|
|
|
static struct srv6_locator *
|
|
|
|
assign_srv6_locator_chunk(uint8_t proto,
|
|
|
|
uint16_t instance,
|
|
|
|
uint32_t session_id,
|
|
|
|
const char *locator_name)
|
|
|
|
{
|
|
|
|
bool chunk_found = false;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
struct srv6_locator *loc = NULL;
|
|
|
|
struct srv6_locator_chunk *chunk = NULL;
|
|
|
|
|
|
|
|
loc = zebra_srv6_locator_lookup(locator_name);
|
|
|
|
if (!loc) {
|
|
|
|
zlog_info("%s: locator %s was not found",
|
|
|
|
__func__, locator_name);
|
2021-09-05 12:06:29 +02:00
|
|
|
return NULL;
|
2020-12-09 10:52:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
|
2021-06-07 20:26:25 +02:00
|
|
|
if (chunk->proto != NO_PROTO && chunk->proto != proto)
|
2020-12-09 10:52:17 +01:00
|
|
|
continue;
|
|
|
|
chunk_found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!chunk_found) {
|
|
|
|
zlog_info("%s: locator is already owned", __func__);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
chunk->proto = proto;
|
2021-06-07 20:26:25 +02:00
|
|
|
chunk->instance = instance;
|
|
|
|
chunk->session_id = session_id;
|
2020-12-09 10:52:17 +01:00
|
|
|
return loc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator **loc,
|
|
|
|
struct zserv *client,
|
|
|
|
const char *locator_name,
|
|
|
|
vrf_id_t vrf_id)
|
|
|
|
{
|
2021-02-24 11:47:05 +01:00
|
|
|
int ret = 0;
|
|
|
|
|
2020-12-09 10:52:17 +01:00
|
|
|
*loc = assign_srv6_locator_chunk(client->proto, client->instance,
|
|
|
|
client->session_id, locator_name);
|
|
|
|
|
|
|
|
if (!*loc)
|
|
|
|
zlog_err("Unable to assign locator chunk to %s instance %u",
|
|
|
|
zebra_route_string(client->proto), client->instance);
|
|
|
|
else if (IS_ZEBRA_DEBUG_PACKET)
|
|
|
|
zlog_info("Assigned locator chunk %s to %s instance %u",
|
|
|
|
(*loc)->name, zebra_route_string(client->proto),
|
|
|
|
client->instance);
|
|
|
|
|
2021-02-24 12:28:59 +01:00
|
|
|
if (*loc && (*loc)->status_up)
|
2020-12-09 10:52:17 +01:00
|
|
|
ret = zsend_srv6_manager_get_locator_chunk_response(client,
|
|
|
|
vrf_id,
|
|
|
|
*loc);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Core function, release no longer used srv6-locator chunks
|
|
|
|
*
|
|
|
|
* @param proto Daemon protocol of client, to identify the owner
|
|
|
|
* @param instance Instance, to identify the owner
|
|
|
|
* @param session_id Zclient session ID, to identify the zclient session
|
|
|
|
* @param locator_name SRv6-locator name, to identify the actual locator
|
|
|
|
* @return 0 on success, -1 otherwise
|
|
|
|
*/
|
|
|
|
static int release_srv6_locator_chunk(uint8_t proto, uint16_t instance,
|
|
|
|
uint32_t session_id,
|
|
|
|
const char *locator_name)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
struct listnode *node;
|
|
|
|
struct srv6_locator_chunk *chunk;
|
|
|
|
struct srv6_locator *loc = NULL;
|
|
|
|
|
|
|
|
loc = zebra_srv6_locator_lookup(locator_name);
|
2021-02-24 11:47:05 +01:00
|
|
|
if (!loc)
|
2020-12-09 10:52:17 +01:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_PACKET)
|
|
|
|
zlog_debug("%s: Releasing srv6-locator on %s", __func__,
|
|
|
|
locator_name);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
|
|
|
|
if (chunk->proto != proto ||
|
|
|
|
chunk->instance != instance ||
|
|
|
|
chunk->session_id != session_id)
|
|
|
|
continue;
|
|
|
|
chunk->proto = NO_PROTO;
|
|
|
|
chunk->instance = 0;
|
|
|
|
chunk->session_id = 0;
|
|
|
|
chunk->keep = 0;
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret != 0)
|
|
|
|
flog_err(EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK,
|
|
|
|
"%s: SRv6 locator chunk not released", __func__);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int zebra_srv6_manager_release_locator_chunk(struct zserv *client,
|
|
|
|
const char *locator_name,
|
|
|
|
vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
if (vrf_id != VRF_DEFAULT) {
|
|
|
|
zlog_err("SRv6 locator doesn't support vrf");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return release_srv6_locator_chunk(client->proto, client->instance,
|
|
|
|
client->session_id, locator_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Release srv6-locator chunks from a client.
|
|
|
|
*
|
|
|
|
* Called on client disconnection or reconnection. It only releases chunks
|
|
|
|
* with empty keep value.
|
|
|
|
*
|
|
|
|
* @param proto Daemon protocol of client, to identify the owner
|
|
|
|
* @param instance Instance, to identify the owner
|
|
|
|
* @return Number of chunks released
|
|
|
|
*/
|
|
|
|
int release_daemon_srv6_locator_chunks(struct zserv *client)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int count = 0;
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
|
|
|
struct listnode *loc_node;
|
|
|
|
struct listnode *chunk_node;
|
|
|
|
struct srv6_locator *loc;
|
|
|
|
struct srv6_locator_chunk *chunk;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_PACKET)
|
|
|
|
zlog_debug("%s: Releasing chunks for client proto %s, instance %d, session %u",
|
|
|
|
__func__, zebra_route_string(client->proto),
|
|
|
|
client->instance, client->session_id);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(srv6->locators, loc_node, loc)) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, chunk)) {
|
|
|
|
if (chunk->proto == client->proto &&
|
|
|
|
chunk->instance == client->instance &&
|
|
|
|
chunk->session_id == client->session_id &&
|
|
|
|
chunk->keep == 0) {
|
|
|
|
ret = release_srv6_locator_chunk(
|
|
|
|
chunk->proto, chunk->instance,
|
|
|
|
chunk->session_id, loc->name);
|
|
|
|
if (ret == 0)
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_PACKET)
|
|
|
|
zlog_debug("%s: Released %d srv6-locator chunks",
|
|
|
|
__func__, count);
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2022-11-03 08:40:23 +01:00
|
|
|
void zebra_srv6_encap_src_addr_set(struct in6_addr *encap_src_addr)
|
|
|
|
{
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
|
|
|
|
|
|
|
if (!encap_src_addr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
memcpy(&srv6->encap_src_addr, encap_src_addr, sizeof(struct in6_addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_srv6_encap_src_addr_unset(void)
|
|
|
|
{
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
|
|
|
|
|
|
|
memset(&srv6->encap_src_addr, 0, sizeof(struct in6_addr));
|
|
|
|
}
|
|
|
|
|
2024-03-23 15:50:24 +01:00
|
|
|
/**
|
|
|
|
* Handle a get SRv6 Locator request received from a client.
|
|
|
|
*
|
|
|
|
* It looks up the requested locator and send it to the client.
|
|
|
|
*
|
|
|
|
* @param locator SRv6 locator returned by this function
|
|
|
|
* @param client The client that sent the Get SRv6 Locator request
|
|
|
|
* @param locator_name Name of the locator to look up
|
|
|
|
*
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
|
|
|
static int srv6_manager_get_srv6_locator_internal(struct srv6_locator **locator,
|
|
|
|
struct zserv *client,
|
|
|
|
const char *locator_name)
|
|
|
|
{
|
|
|
|
*locator = zebra_srv6_locator_lookup(locator_name);
|
|
|
|
if (!*locator)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return zsend_zebra_srv6_locator_add(client, *locator);
|
|
|
|
}
|
|
|
|
|
2023-12-12 18:03:10 +01:00
|
|
|
void zebra_srv6_terminate(void)
|
|
|
|
{
|
|
|
|
struct srv6_locator *locator;
|
2024-03-22 15:56:15 +01:00
|
|
|
struct srv6_sid_format *format;
|
2024-03-22 18:19:36 +01:00
|
|
|
struct zebra_srv6_sid_block *block;
|
2024-03-23 13:42:19 +01:00
|
|
|
struct zebra_srv6_sid_ctx *sid_ctx;
|
2023-12-12 18:03:10 +01:00
|
|
|
|
2024-06-06 17:23:11 +02:00
|
|
|
if (srv6.locators) {
|
|
|
|
while (listcount(srv6.locators)) {
|
|
|
|
locator = listnode_head(srv6.locators);
|
2023-12-12 18:03:10 +01:00
|
|
|
|
2024-06-06 17:23:11 +02:00
|
|
|
listnode_delete(srv6.locators, locator);
|
|
|
|
srv6_locator_free(locator);
|
|
|
|
}
|
2023-12-12 18:03:10 +01:00
|
|
|
|
2024-06-06 17:23:11 +02:00
|
|
|
list_delete(&srv6.locators);
|
2023-12-12 18:03:10 +01:00
|
|
|
}
|
|
|
|
|
2024-03-23 13:42:19 +01:00
|
|
|
/* Free SRv6 SIDs */
|
|
|
|
if (srv6.sids) {
|
|
|
|
while (listcount(srv6.sids)) {
|
|
|
|
sid_ctx = listnode_head(srv6.sids);
|
|
|
|
|
|
|
|
listnode_delete(srv6.sids, sid_ctx);
|
|
|
|
zebra_srv6_sid_ctx_free(sid_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
list_delete(&srv6.sids);
|
|
|
|
}
|
|
|
|
|
2024-03-22 18:19:36 +01:00
|
|
|
/* Free SRv6 SID blocks */
|
|
|
|
if (srv6.sid_blocks) {
|
|
|
|
while (listcount(srv6.sid_blocks)) {
|
|
|
|
block = listnode_head(srv6.sid_blocks);
|
|
|
|
|
|
|
|
listnode_delete(srv6.sid_blocks, block);
|
|
|
|
zebra_srv6_sid_block_free(block);
|
|
|
|
}
|
|
|
|
|
|
|
|
list_delete(&srv6.sid_blocks);
|
|
|
|
}
|
|
|
|
|
2024-06-06 17:23:11 +02:00
|
|
|
/* Free SRv6 SID formats */
|
|
|
|
if (srv6.sid_formats) {
|
|
|
|
while (listcount(srv6.sid_formats)) {
|
|
|
|
format = listnode_head(srv6.sid_formats);
|
|
|
|
|
2024-03-26 08:53:55 +01:00
|
|
|
srv6_sid_format_unregister(format);
|
2024-03-22 15:56:15 +01:00
|
|
|
srv6_sid_format_free(format);
|
2024-06-06 17:23:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
list_delete(&srv6.sid_formats);
|
|
|
|
}
|
2023-12-12 18:03:10 +01:00
|
|
|
}
|
|
|
|
|
2020-12-09 10:52:17 +01:00
|
|
|
void zebra_srv6_init(void)
|
|
|
|
{
|
|
|
|
hook_register(zserv_client_close, zebra_srv6_cleanup);
|
|
|
|
hook_register(srv6_manager_get_chunk,
|
|
|
|
zebra_srv6_manager_get_locator_chunk);
|
|
|
|
hook_register(srv6_manager_release_chunk,
|
|
|
|
zebra_srv6_manager_release_locator_chunk);
|
2024-03-23 15:50:24 +01:00
|
|
|
|
|
|
|
hook_register(srv6_manager_get_locator,
|
|
|
|
srv6_manager_get_srv6_locator_internal);
|
2020-12-09 10:52:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool zebra_srv6_is_enable(void)
|
|
|
|
{
|
|
|
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
|
|
|
|
|
|
|
return listcount(srv6->locators);
|
|
|
|
}
|