mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-03 10:54:56 +00:00
Merge pull request #1824 from pguibert6WIND/table_manager
Table manager for zebra
This commit is contained in:
commit
465cd0eb94
@ -970,6 +970,64 @@ static int bgp_table_map_apply(struct route_map *map, struct prefix *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct thread *bgp_tm_thread_connect;
|
||||
static bool bgp_tm_status_connected;
|
||||
|
||||
static int bgp_zebra_tm_connect(struct thread *t)
|
||||
{
|
||||
struct zclient *zclient;
|
||||
int delay = 10, ret = 0;
|
||||
|
||||
zclient = THREAD_ARG(t);
|
||||
if (bgp_tm_status_connected && zclient->sock > 0)
|
||||
delay = 60;
|
||||
else {
|
||||
bgp_tm_status_connected = false;
|
||||
ret = tm_table_manager_connect(zclient);
|
||||
}
|
||||
if (ret < 0) {
|
||||
zlog_warn("Error connecting to table manager!");
|
||||
bgp_tm_status_connected = false;
|
||||
} else {
|
||||
if (!bgp_tm_status_connected)
|
||||
zlog_debug("Connecting to table manager. Success");
|
||||
bgp_tm_status_connected = true;
|
||||
}
|
||||
thread_add_timer(bm->master, bgp_zebra_tm_connect, zclient, delay,
|
||||
&bgp_tm_thread_connect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bgp_zebra_init_tm_connect(void)
|
||||
{
|
||||
int delay = 1;
|
||||
|
||||
/* if already set, do nothing
|
||||
*/
|
||||
if (bgp_tm_thread_connect != NULL)
|
||||
return;
|
||||
bgp_tm_status_connected = false;
|
||||
thread_add_timer(bm->master, bgp_zebra_tm_connect, zclient, delay,
|
||||
&bgp_tm_thread_connect);
|
||||
}
|
||||
|
||||
int bgp_zebra_get_table_range(uint32_t chunk_size,
|
||||
uint32_t *start, uint32_t *end)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!bgp_tm_status_connected)
|
||||
return -1;
|
||||
ret = tm_get_table_chunk(zclient, chunk_size, start, end);
|
||||
if (ret < 0) {
|
||||
zlog_err("BGP: Error getting table chunk %u", chunk_size);
|
||||
return -1;
|
||||
}
|
||||
zlog_info("BGP: Table Manager returns range from chunk %u is [%u %u]",
|
||||
chunk_size, *start, *end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
||||
struct bgp_info *info, struct bgp *bgp, afi_t afi,
|
||||
safi_t safi)
|
||||
|
@ -24,7 +24,10 @@
|
||||
#include "vxlan.h"
|
||||
|
||||
extern void bgp_zebra_init(struct thread_master *master);
|
||||
extern void bgp_zebra_init_tm_connect(void);
|
||||
extern void bgp_zebra_destroy(void);
|
||||
extern int bgp_zebra_get_table_range(uint32_t chunk_size,
|
||||
uint32_t *start, uint32_t *end);
|
||||
extern int bgp_if_update_all(void);
|
||||
extern void bgp_config_write_maxpaths(struct vty *, struct bgp *, afi_t,
|
||||
safi_t);
|
||||
|
@ -1973,6 +1973,10 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi)
|
||||
bgp_recalculate_afi_safi_bestpaths(bgp, afi, SAFI_UNICAST);
|
||||
}
|
||||
|
||||
if (safi == SAFI_FLOWSPEC) {
|
||||
/* connect to table manager */
|
||||
bgp_zebra_init_tm_connect();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -965,6 +965,9 @@ static const struct zebra_desc_table command_types[] = {
|
||||
DESC_ENTRY(ZEBRA_RULE_ADD),
|
||||
DESC_ENTRY(ZEBRA_RULE_DELETE),
|
||||
DESC_ENTRY(ZEBRA_RULE_NOTIFY_OWNER),
|
||||
DESC_ENTRY(ZEBRA_TABLE_MANAGER_CONNECT),
|
||||
DESC_ENTRY(ZEBRA_GET_TABLE_CHUNK),
|
||||
DESC_ENTRY(ZEBRA_RELEASE_TABLE_CHUNK),
|
||||
};
|
||||
#undef DESC_ENTRY
|
||||
|
||||
|
162
lib/zclient.c
162
lib/zclient.c
@ -2123,6 +2123,168 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to table manager in a syncronous way
|
||||
*
|
||||
* It first writes the request to zcient output buffer and then
|
||||
* immediately reads the answer from the input buffer.
|
||||
*
|
||||
* @param zclient Zclient used to connect to table manager (zebra)
|
||||
* @result Result of response
|
||||
*/
|
||||
int tm_table_manager_connect(struct zclient *zclient)
|
||||
{
|
||||
int ret;
|
||||
struct stream *s;
|
||||
uint8_t result;
|
||||
|
||||
if (zclient_debug)
|
||||
zlog_debug("Connecting to Table Manager");
|
||||
|
||||
if (zclient->sock < 0)
|
||||
return -1;
|
||||
|
||||
/* send request */
|
||||
s = zclient->obuf;
|
||||
stream_reset(s);
|
||||
zclient_create_header(s, ZEBRA_TABLE_MANAGER_CONNECT, VRF_DEFAULT);
|
||||
|
||||
/* proto */
|
||||
stream_putc(s, zclient->redist_default);
|
||||
/* instance */
|
||||
stream_putw(s, zclient->instance);
|
||||
|
||||
/* Put length at the first point of the stream. */
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
ret = zclient_send_message(zclient);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
if (zclient_debug)
|
||||
zlog_debug("%s: Table manager connect request sent",
|
||||
__func__);
|
||||
|
||||
/* read response */
|
||||
if (zclient_read_sync_response(zclient, ZEBRA_TABLE_MANAGER_CONNECT)
|
||||
!= 0)
|
||||
return -1;
|
||||
|
||||
/* result */
|
||||
s = zclient->ibuf;
|
||||
STREAM_GETC(s, result);
|
||||
if (zclient_debug)
|
||||
zlog_debug(
|
||||
"%s: Table Manager connect response received, result %u",
|
||||
__func__, result);
|
||||
|
||||
return (int)result;
|
||||
stream_failure:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to request a table chunk in a syncronous way
|
||||
*
|
||||
* It first writes the request to zclient output buffer and then
|
||||
* immediately reads the answer from the input buffer.
|
||||
*
|
||||
* @param zclient Zclient used to connect to table manager (zebra)
|
||||
* @param chunk_size Amount of table requested
|
||||
* @param start to write first assigned chunk table RT ID to
|
||||
* @param end To write last assigned chunk table RT ID to
|
||||
* @result 0 on success, -1 otherwise
|
||||
*/
|
||||
int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
|
||||
uint32_t *start, uint32_t *end)
|
||||
{
|
||||
int ret;
|
||||
struct stream *s;
|
||||
|
||||
if (zclient_debug)
|
||||
zlog_debug("Getting Table Chunk");
|
||||
|
||||
if (zclient->sock < 0)
|
||||
return -1;
|
||||
|
||||
/* send request */
|
||||
s = zclient->obuf;
|
||||
stream_reset(s);
|
||||
zclient_create_header(s, ZEBRA_GET_TABLE_CHUNK, VRF_DEFAULT);
|
||||
/* chunk size */
|
||||
stream_putl(s, chunk_size);
|
||||
/* Put length at the first point of the stream. */
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
ret = writen(zclient->sock, s->data, stream_get_endp(s));
|
||||
if (ret < 0) {
|
||||
zlog_err("%s: can't write to zclient->sock", __func__);
|
||||
close(zclient->sock);
|
||||
zclient->sock = -1;
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
zlog_err("%s: zclient->sock connection closed", __func__);
|
||||
close(zclient->sock);
|
||||
zclient->sock = -1;
|
||||
return -1;
|
||||
}
|
||||
if (zclient_debug)
|
||||
zlog_debug("%s: Table chunk request (%d bytes) sent", __func__,
|
||||
ret);
|
||||
|
||||
/* read response */
|
||||
if (zclient_read_sync_response(zclient, ZEBRA_GET_TABLE_CHUNK) != 0)
|
||||
return -1;
|
||||
|
||||
s = zclient->ibuf;
|
||||
/* start and end table IDs */
|
||||
STREAM_GETL(s, *start);
|
||||
STREAM_GETL(s, *end);
|
||||
|
||||
if (zclient_debug)
|
||||
zlog_debug("Table Chunk assign: %u - %u ", *start, *end);
|
||||
|
||||
stream_failure:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to release a table chunk
|
||||
*
|
||||
* @param zclient Zclient used to connect to table manager (zebra)
|
||||
* @param start First label of table
|
||||
* @param end Last label of chunk
|
||||
* @result 0 on success, -1 otherwise
|
||||
*/
|
||||
int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
|
||||
uint32_t end)
|
||||
{
|
||||
struct stream *s;
|
||||
|
||||
if (zclient_debug)
|
||||
zlog_debug("Releasing Table Chunk");
|
||||
|
||||
if (zclient->sock < 0)
|
||||
return -1;
|
||||
|
||||
/* send request */
|
||||
s = zclient->obuf;
|
||||
stream_reset(s);
|
||||
zclient_create_header(s, ZEBRA_RELEASE_TABLE_CHUNK, VRF_DEFAULT);
|
||||
|
||||
/* start */
|
||||
stream_putl(s, start);
|
||||
/* end */
|
||||
stream_putl(s, end);
|
||||
|
||||
/* Put length at the first point of the stream. */
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
return zclient_send_message(zclient);
|
||||
}
|
||||
|
||||
|
||||
int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
|
||||
{
|
||||
struct stream *s;
|
||||
|
@ -132,6 +132,9 @@ typedef enum {
|
||||
ZEBRA_RULE_ADD,
|
||||
ZEBRA_RULE_DELETE,
|
||||
ZEBRA_RULE_NOTIFY_OWNER,
|
||||
ZEBRA_TABLE_MANAGER_CONNECT,
|
||||
ZEBRA_GET_TABLE_CHUNK,
|
||||
ZEBRA_RELEASE_TABLE_CHUNK,
|
||||
} zebra_message_types_t;
|
||||
|
||||
struct redist_proto {
|
||||
@ -538,6 +541,12 @@ extern int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
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);
|
||||
extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
|
||||
uint32_t *start, uint32_t *end);
|
||||
extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
|
||||
uint32_t end);
|
||||
|
||||
extern int zebra_send_pw(struct zclient *zclient, int command,
|
||||
struct zapi_pw *pw);
|
||||
extern void zebra_read_pw_status_update(int command, struct zclient *zclient,
|
||||
|
@ -433,7 +433,8 @@ typedef enum {
|
||||
SAFI_ENCAP = 4,
|
||||
SAFI_EVPN = 5,
|
||||
SAFI_LABELED_UNICAST = 6,
|
||||
SAFI_MAX = 7
|
||||
SAFI_FLOWSPEC = 7,
|
||||
SAFI_MAX = 8
|
||||
} safi_t;
|
||||
|
||||
/*
|
||||
|
@ -363,7 +363,7 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
|
||||
* @param instance Instance, to identify the owner
|
||||
* @return Number of chunks released
|
||||
*/
|
||||
int release_daemon_chunks(uint8_t proto, unsigned short instance)
|
||||
int release_daemon_label_chunks(uint8_t proto, unsigned short instance)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct label_manager_chunk *lmc;
|
||||
|
@ -69,7 +69,7 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
||||
uint8_t keep, uint32_t size);
|
||||
int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
|
||||
uint32_t end);
|
||||
int release_daemon_chunks(uint8_t proto, unsigned short instance);
|
||||
int release_daemon_label_chunks(uint8_t proto, unsigned short instance);
|
||||
void label_manager_close(void);
|
||||
|
||||
#endif /* _LABEL_MANAGER_H */
|
||||
|
@ -70,6 +70,7 @@ zebra_zebra_SOURCES = \
|
||||
zebra/zserv.c \
|
||||
zebra/zebra_netns_id.c \
|
||||
zebra/zebra_netns_notify.c \
|
||||
zebra/table_manager.c \
|
||||
# end
|
||||
|
||||
zebra/zebra_vty_clippy.c: $(CLIPPY_DEPS)
|
||||
@ -113,6 +114,7 @@ noinst_HEADERS += \
|
||||
zebra/zserv.h \
|
||||
zebra/zebra_netns_id.h \
|
||||
zebra/zebra_netns_notify.h \
|
||||
zebra/table_manager.h \
|
||||
# end
|
||||
|
||||
zebra_zebra_irdp_la_SOURCES = \
|
||||
|
235
zebra/table_manager.c
Normal file
235
zebra/table_manager.c
Normal file
@ -0,0 +1,235 @@
|
||||
/* zebra table Manager for routing table identifier management
|
||||
* Copyright (C) 2018 6WIND
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "zebra.h"
|
||||
#include "zserv.h"
|
||||
#include "lib/log.h"
|
||||
#include "lib/memory.h"
|
||||
#include "lib/table.h"
|
||||
#include "lib/network.h"
|
||||
#include "lib/stream.h"
|
||||
#include "lib/zclient.h"
|
||||
#include "lib/libfrr.h"
|
||||
#include "lib/vrf.h"
|
||||
|
||||
#include "zebra_vrf.h"
|
||||
#include "label_manager.h" /* for NO_PROTO */
|
||||
#include "table_manager.h"
|
||||
|
||||
/* routing table identifiers
|
||||
*
|
||||
*/
|
||||
#ifdef SUNOS_5
|
||||
/* SunOS
|
||||
*/
|
||||
#else
|
||||
#if !defined(GNU_LINUX) && !defined(SUNOS_5)
|
||||
/* BSD systems
|
||||
*/
|
||||
#else
|
||||
/* Linux Systems
|
||||
*/
|
||||
#define RT_TABLE_ID_LOCAL 255
|
||||
#define RT_TABLE_ID_MAIN 254
|
||||
#define RT_TABLE_ID_DEFAULT 253
|
||||
#define RT_TABLE_ID_COMPAT 252
|
||||
#define RT_TABLE_ID_UNSPEC 0
|
||||
#endif /* !def(GNU_LINUX) && !defined(SUNOS_5) */
|
||||
#endif /* SUNOS_5 */
|
||||
#define RT_TABLE_ID_UNRESERVED_MIN 1
|
||||
#define RT_TABLE_ID_UNRESERVED_MAX 0xffffffff
|
||||
|
||||
struct table_manager tbl_mgr;
|
||||
|
||||
DEFINE_MGROUP(TABLE_MGR, "Table Manager");
|
||||
DEFINE_MTYPE_STATIC(TABLE_MGR, TM_CHUNK, "Table Manager Chunk");
|
||||
|
||||
static void delete_table_chunk(void *val)
|
||||
{
|
||||
XFREE(MTYPE_TM_CHUNK, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init table manager
|
||||
*/
|
||||
void table_manager_enable(ns_id_t ns_id)
|
||||
{
|
||||
if (ns_id != NS_DEFAULT)
|
||||
return;
|
||||
tbl_mgr.lc_list = list_new();
|
||||
tbl_mgr.lc_list->del = delete_table_chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core function, assigns table 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
|
||||
* @para size Size of the table chunk
|
||||
* @return Pointer to the assigned table chunk
|
||||
*/
|
||||
struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
|
||||
uint32_t size)
|
||||
{
|
||||
struct table_manager_chunk *tmc;
|
||||
struct listnode *node;
|
||||
uint32_t start;
|
||||
|
||||
/* first check if there's one available */
|
||||
for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
|
||||
if (tmc->proto == NO_PROTO
|
||||
&& tmc->end - tmc->start + 1 == size) {
|
||||
tmc->proto = proto;
|
||||
tmc->instance = instance;
|
||||
return tmc;
|
||||
}
|
||||
}
|
||||
/* otherwise create a new one */
|
||||
tmc = XCALLOC(MTYPE_TM_CHUNK, sizeof(struct table_manager_chunk));
|
||||
if (!tmc)
|
||||
return NULL;
|
||||
|
||||
/* table RT IDs range are [1;252] and [256;0xffffffff]
|
||||
* - check if the requested range can be within the first range,
|
||||
* otherwise elect second one
|
||||
* - TODO : vrf-lites have their own table identifier.
|
||||
* In that case, table_id should be removed from the table range.
|
||||
*/
|
||||
if (list_isempty(tbl_mgr.lc_list))
|
||||
start = RT_TABLE_ID_UNRESERVED_MIN;
|
||||
else
|
||||
start = ((struct table_manager_chunk *)listgetdata(
|
||||
listtail(tbl_mgr.lc_list)))->end + 1;
|
||||
|
||||
#ifdef SUNOS_5
|
||||
/* SunOS
|
||||
*/
|
||||
#else
|
||||
#if !defined(GNU_LINUX) && !defined(SUNOS_5)
|
||||
/* BSD systems
|
||||
*/
|
||||
#else
|
||||
/* Linux Systems
|
||||
*/
|
||||
/* if not enough room space between MIN and COMPAT,
|
||||
* then begin after LOCAL
|
||||
*/
|
||||
if (start < RT_TABLE_ID_COMPAT && (size >
|
||||
RT_TABLE_ID_COMPAT
|
||||
- RT_TABLE_ID_UNRESERVED_MIN))
|
||||
start = RT_TABLE_ID_LOCAL + 1;
|
||||
#endif /* !def(GNU_LINUX) && !defined(SUNOS_5) */
|
||||
#endif /* SUNOS_5 */
|
||||
tmc->start = start;
|
||||
if (RT_TABLE_ID_UNRESERVED_MAX - size + 1 < start) {
|
||||
zlog_err("Reached max table id. Start/Size %u/%u",
|
||||
start, size);
|
||||
XFREE(MTYPE_TM_CHUNK, tmc);
|
||||
return NULL;
|
||||
}
|
||||
tmc->end = tmc->start + size - 1;
|
||||
tmc->proto = proto;
|
||||
tmc->instance = instance;
|
||||
listnode_add(tbl_mgr.lc_list, tmc);
|
||||
|
||||
return tmc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core function, release no longer used table chunks
|
||||
*
|
||||
* @param proto Daemon protocol of client, to identify the owner
|
||||
* @param instance Instance, to identify the owner
|
||||
* @param start First table RT ID of the chunk
|
||||
* @param end Last table RT ID of the chunk
|
||||
* @return 0 on success, -1 otherwise
|
||||
*/
|
||||
int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
|
||||
uint32_t end)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct table_manager_chunk *tmc;
|
||||
int ret = -1;
|
||||
|
||||
/* check that size matches */
|
||||
zlog_debug("Releasing table chunk: %u - %u", start, end);
|
||||
/* find chunk and disown */
|
||||
for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
|
||||
if (tmc->start != start)
|
||||
continue;
|
||||
if (tmc->end != end)
|
||||
continue;
|
||||
if (tmc->proto != proto || tmc->instance != instance) {
|
||||
zlog_err("%s: Daemon mismatch!!", __func__);
|
||||
continue;
|
||||
}
|
||||
tmc->proto = NO_PROTO;
|
||||
tmc->instance = 0;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
if (ret != 0)
|
||||
zlog_err("%s: Table chunk not released!!", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release table 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_table_chunks(uint8_t proto, uint16_t instance)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct table_manager_chunk *tmc;
|
||||
int count = 0;
|
||||
int ret;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
|
||||
if (tmc->proto == proto && tmc->instance == instance) {
|
||||
ret = release_table_chunk(tmc->proto, tmc->instance,
|
||||
tmc->start, tmc->end);
|
||||
if (ret == 0)
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
zlog_debug("%s: Released %d table chunks", __func__, count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void table_manager_disable(ns_id_t ns_id)
|
||||
{
|
||||
if (ns_id != NS_DEFAULT)
|
||||
return;
|
||||
list_delete_and_null(&tbl_mgr.lc_list);
|
||||
}
|
63
zebra/table_manager.h
Normal file
63
zebra/table_manager.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* zebra table Manager for routing table identifier management
|
||||
* Copyright (C) 2018 6WIND
|
||||
*
|
||||
* 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 _TABLE_MANAGER_H
|
||||
#define _TABLE_MANAGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lib/linklist.h"
|
||||
#include "lib/thread.h"
|
||||
|
||||
/*
|
||||
* Table chunk struct
|
||||
* Client daemon which the chunk belongs to can be identified by either
|
||||
* proto (daemon protocol) + instance + VRF.
|
||||
* If the client then passes a non-empty value to keep field when it requests
|
||||
* for chunks, the chunks won't be garbage collected and the client will be
|
||||
* responsible of its release.
|
||||
* Otherwise, if the keep field is not set (value 0) for the chunk, it will be
|
||||
* automatically released when the client disconnects or when it reconnects
|
||||
* (in case it died unexpectedly, we can know it's the same because it will have
|
||||
* the same proto and instance values)
|
||||
*/
|
||||
struct table_manager_chunk {
|
||||
vrf_id_t vrf_id;
|
||||
uint8_t proto;
|
||||
uint16_t instance;
|
||||
uint32_t start; /* First table RT ID of the chunk */
|
||||
uint32_t end; /* Last table RT ID of the chunk */
|
||||
};
|
||||
|
||||
/*
|
||||
* Main table manager struct
|
||||
* Holds a linked list of table chunks.
|
||||
*/
|
||||
struct table_manager {
|
||||
struct list *lc_list;
|
||||
};
|
||||
|
||||
void table_manager_enable(ns_id_t ns_id);
|
||||
struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
|
||||
uint32_t size);
|
||||
int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
|
||||
uint32_t end);
|
||||
int release_daemon_table_chunks(uint8_t proto, uint16_t instance);
|
||||
void table_manager_disable(ns_id_t ns_id);
|
||||
|
||||
#endif /* _TABLE_MANAGER_H */
|
@ -38,6 +38,7 @@
|
||||
#include "zebra_netns_id.h"
|
||||
#include "zebra_pbr.h"
|
||||
#include "rib.h"
|
||||
#include "table_manager.h"
|
||||
|
||||
extern struct zebra_privs_t zserv_privs;
|
||||
|
||||
@ -147,6 +148,9 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
|
||||
interface_list(zns);
|
||||
route_read(zns);
|
||||
|
||||
/* Initiate Table Manager per ZNS */
|
||||
table_manager_enable(ns_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -259,6 +263,8 @@ int zebra_ns_disable(ns_id_t ns_id, void **info)
|
||||
|
||||
kernel_terminate(zns);
|
||||
|
||||
table_manager_disable(zns->ns_id);
|
||||
|
||||
zns->ns_id = NS_DEFAULT;
|
||||
|
||||
return 0;
|
||||
|
@ -122,8 +122,8 @@ static int zebra_vrf_enable(struct vrf *vrf)
|
||||
/* Inform clients that the VRF is now active. This is an
|
||||
* add for the clients.
|
||||
*/
|
||||
zebra_vrf_add_update(zvrf);
|
||||
|
||||
zebra_vrf_add_update(zvrf);
|
||||
/* Allocate tables */
|
||||
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
||||
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
|
||||
|
153
zebra/zserv.c
153
zebra/zserv.c
@ -61,6 +61,7 @@
|
||||
#include "zebra/zebra_vxlan.h"
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
#include "zebra/table_manager.h"
|
||||
|
||||
/* Event list of zebra. */
|
||||
enum event { ZEBRA_READ, ZEBRA_WRITE };
|
||||
@ -2186,6 +2187,60 @@ stream_failure:
|
||||
return;
|
||||
}
|
||||
|
||||
static int zsend_table_manager_connect_response(struct zserv *client,
|
||||
vrf_id_t vrf_id, uint16_t result)
|
||||
{
|
||||
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
||||
|
||||
zclient_create_header(s, ZEBRA_TABLE_MANAGER_CONNECT, vrf_id);
|
||||
|
||||
/* result */
|
||||
stream_putc(s, result);
|
||||
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
return zebra_server_send_message(client, s);
|
||||
}
|
||||
|
||||
/* Send response to a table manager connect request to client */
|
||||
static void zread_table_manager_connect(struct zserv *client,
|
||||
struct stream *msg,
|
||||
vrf_id_t vrf_id)
|
||||
{
|
||||
struct stream *s;
|
||||
uint8_t proto;
|
||||
uint16_t instance;
|
||||
|
||||
s = msg;
|
||||
|
||||
/* Get data. */
|
||||
STREAM_GETC(s, proto);
|
||||
STREAM_GETW(s, instance);
|
||||
|
||||
/* accept only dynamic routing protocols */
|
||||
if ((proto >= ZEBRA_ROUTE_MAX) || (proto <= ZEBRA_ROUTE_STATIC)) {
|
||||
zlog_err("client %d has wrong protocol %s", client->sock,
|
||||
zebra_route_string(proto));
|
||||
zsend_table_manager_connect_response(client, vrf_id, 1);
|
||||
return;
|
||||
}
|
||||
zlog_notice("client %d with vrf %u instance %u connected as %s",
|
||||
client->sock, vrf_id, instance, zebra_route_string(proto));
|
||||
client->proto = proto;
|
||||
client->instance = instance;
|
||||
|
||||
/*
|
||||
* Release previous labels of same protocol and instance.
|
||||
* This is done in case it restarted from an unexpected shutdown.
|
||||
*/
|
||||
release_daemon_table_chunks(proto, instance);
|
||||
|
||||
zsend_table_manager_connect_response(client, vrf_id, 0);
|
||||
|
||||
stream_failure:
|
||||
return;
|
||||
}
|
||||
|
||||
static void zread_label_manager_connect(struct zserv *client,
|
||||
struct stream *msg, vrf_id_t vrf_id)
|
||||
{
|
||||
@ -2217,7 +2272,7 @@ static void zread_label_manager_connect(struct zserv *client,
|
||||
Release previous labels of same protocol and instance.
|
||||
This is done in case it restarted from an unexpected shutdown.
|
||||
*/
|
||||
release_daemon_chunks(proto, instance);
|
||||
release_daemon_label_chunks(proto, instance);
|
||||
|
||||
zlog_debug(
|
||||
" Label Manager client connected: sock %d, proto %s, vrf %u instance %u",
|
||||
@ -2225,7 +2280,7 @@ static void zread_label_manager_connect(struct zserv *client,
|
||||
/* send response back */
|
||||
zsend_label_manager_connect_response(client, vrf_id, 0);
|
||||
|
||||
stream_failure:
|
||||
stream_failure:
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2305,6 +2360,92 @@ static void zread_label_manager_request(ZAPI_HANDLER_ARGS)
|
||||
}
|
||||
}
|
||||
|
||||
/* Send response to a get table chunk request to client */
|
||||
static int zsend_assign_table_chunk_response(struct zserv *client,
|
||||
vrf_id_t vrf_id,
|
||||
struct table_manager_chunk *tmc)
|
||||
{
|
||||
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
||||
|
||||
zclient_create_header(s, ZEBRA_GET_TABLE_CHUNK, vrf_id);
|
||||
|
||||
if (tmc) {
|
||||
/* start and end labels */
|
||||
stream_putl(s, tmc->start);
|
||||
stream_putl(s, tmc->end);
|
||||
}
|
||||
|
||||
/* Write packet size. */
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
return zebra_server_send_message(client, s);
|
||||
}
|
||||
|
||||
static void zread_get_table_chunk(struct zserv *client, struct stream *msg,
|
||||
vrf_id_t vrf_id)
|
||||
{
|
||||
struct stream *s;
|
||||
uint32_t size;
|
||||
struct table_manager_chunk *tmc;
|
||||
|
||||
/* Get input stream. */
|
||||
s = msg;
|
||||
|
||||
/* Get data. */
|
||||
STREAM_GETL(s, size);
|
||||
|
||||
tmc = assign_table_chunk(client->proto, client->instance, size);
|
||||
if (!tmc)
|
||||
zlog_err("%s: Unable to assign Table Chunk of size %u",
|
||||
__func__, size);
|
||||
else
|
||||
zlog_debug("Assigned Table Chunk %u - %u", tmc->start,
|
||||
tmc->end);
|
||||
/* send response back */
|
||||
zsend_assign_table_chunk_response(client, vrf_id, tmc);
|
||||
|
||||
stream_failure:
|
||||
return;
|
||||
}
|
||||
|
||||
static void zread_release_table_chunk(struct zserv *client, struct stream *msg)
|
||||
{
|
||||
struct stream *s;
|
||||
uint32_t start, end;
|
||||
|
||||
/* Get input stream. */
|
||||
s = msg;
|
||||
|
||||
/* Get data. */
|
||||
STREAM_GETL(s, start);
|
||||
STREAM_GETL(s, end);
|
||||
|
||||
release_table_chunk(client->proto, client->instance, start, end);
|
||||
|
||||
stream_failure:
|
||||
return;
|
||||
}
|
||||
|
||||
static void zread_table_manager_request(ZAPI_HANDLER_ARGS)
|
||||
{
|
||||
/* to avoid sending other messages like ZERBA_INTERFACE_UP */
|
||||
if (hdr->command == ZEBRA_TABLE_MANAGER_CONNECT)
|
||||
zread_table_manager_connect(client, msg, zvrf_id(zvrf));
|
||||
else {
|
||||
/* Sanity: don't allow 'unidentified' requests */
|
||||
if (!client->proto) {
|
||||
zlog_err(
|
||||
"Got table request from an unidentified client");
|
||||
return;
|
||||
}
|
||||
if (hdr->command == ZEBRA_GET_TABLE_CHUNK)
|
||||
zread_get_table_chunk(client, msg,
|
||||
zvrf_id(zvrf));
|
||||
else if (hdr->command == ZEBRA_RELEASE_TABLE_CHUNK)
|
||||
zread_release_table_chunk(client, msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void zread_pseudowire(ZAPI_HANDLER_ARGS)
|
||||
{
|
||||
struct stream *s;
|
||||
@ -2627,6 +2768,9 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
|
||||
[ZEBRA_PW_UNSET] = zread_pseudowire,
|
||||
[ZEBRA_RULE_ADD] = zread_rule,
|
||||
[ZEBRA_RULE_DELETE] = zread_rule,
|
||||
[ZEBRA_TABLE_MANAGER_CONNECT] = zread_table_manager_request,
|
||||
[ZEBRA_GET_TABLE_CHUNK] = zread_table_manager_request,
|
||||
[ZEBRA_RELEASE_TABLE_CHUNK] = zread_table_manager_request,
|
||||
};
|
||||
|
||||
static inline void zserv_handle_commands(struct zserv *client,
|
||||
@ -2658,7 +2802,10 @@ static void zebra_client_free(struct zserv *client)
|
||||
zebra_client_close_cleanup_rnh(client);
|
||||
|
||||
/* Release Label Manager chunks */
|
||||
release_daemon_chunks(client->proto, client->instance);
|
||||
release_daemon_label_chunks(client->proto, client->instance);
|
||||
|
||||
/* Release Table Manager chunks */
|
||||
release_daemon_table_chunks(client->proto, client->instance);
|
||||
|
||||
/* Cleanup any FECs registered by this client. */
|
||||
zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT),
|
||||
|
Loading…
Reference in New Issue
Block a user