Merge pull request #1824 from pguibert6WIND/table_manager

Table manager for zebra
This commit is contained in:
Donald Sharp 2018-03-29 12:09:15 -04:00 committed by GitHub
commit 465cd0eb94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 700 additions and 7 deletions

View File

@ -970,6 +970,64 @@ static int bgp_table_map_apply(struct route_map *map, struct prefix *p,
return 0; 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, void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
struct bgp_info *info, struct bgp *bgp, afi_t afi, struct bgp_info *info, struct bgp *bgp, afi_t afi,
safi_t safi) safi_t safi)

View File

@ -24,7 +24,10 @@
#include "vxlan.h" #include "vxlan.h"
extern void bgp_zebra_init(struct thread_master *master); extern void bgp_zebra_init(struct thread_master *master);
extern void bgp_zebra_init_tm_connect(void);
extern void bgp_zebra_destroy(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 int bgp_if_update_all(void);
extern void bgp_config_write_maxpaths(struct vty *, struct bgp *, afi_t, extern void bgp_config_write_maxpaths(struct vty *, struct bgp *, afi_t,
safi_t); safi_t);

View File

@ -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); bgp_recalculate_afi_safi_bestpaths(bgp, afi, SAFI_UNICAST);
} }
if (safi == SAFI_FLOWSPEC) {
/* connect to table manager */
bgp_zebra_init_tm_connect();
}
return ret; return ret;
} }

View File

@ -965,6 +965,9 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_RULE_ADD), DESC_ENTRY(ZEBRA_RULE_ADD),
DESC_ENTRY(ZEBRA_RULE_DELETE), DESC_ENTRY(ZEBRA_RULE_DELETE),
DESC_ENTRY(ZEBRA_RULE_NOTIFY_OWNER), 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 #undef DESC_ENTRY

View File

@ -2123,6 +2123,168 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
return 0; 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) int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
{ {
struct stream *s; struct stream *s;

View File

@ -132,6 +132,9 @@ typedef enum {
ZEBRA_RULE_ADD, ZEBRA_RULE_ADD,
ZEBRA_RULE_DELETE, ZEBRA_RULE_DELETE,
ZEBRA_RULE_NOTIFY_OWNER, ZEBRA_RULE_NOTIFY_OWNER,
ZEBRA_TABLE_MANAGER_CONNECT,
ZEBRA_GET_TABLE_CHUNK,
ZEBRA_RELEASE_TABLE_CHUNK,
} zebra_message_types_t; } zebra_message_types_t;
struct redist_proto { struct redist_proto {
@ -538,6 +541,12 @@ extern int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
uint32_t *end); uint32_t *end);
extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start, extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
uint32_t end); 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, extern int zebra_send_pw(struct zclient *zclient, int command,
struct zapi_pw *pw); struct zapi_pw *pw);
extern void zebra_read_pw_status_update(int command, struct zclient *zclient, extern void zebra_read_pw_status_update(int command, struct zclient *zclient,

View File

@ -433,7 +433,8 @@ typedef enum {
SAFI_ENCAP = 4, SAFI_ENCAP = 4,
SAFI_EVPN = 5, SAFI_EVPN = 5,
SAFI_LABELED_UNICAST = 6, SAFI_LABELED_UNICAST = 6,
SAFI_MAX = 7 SAFI_FLOWSPEC = 7,
SAFI_MAX = 8
} safi_t; } safi_t;
/* /*

View File

@ -363,7 +363,7 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
* @param instance Instance, to identify the owner * @param instance Instance, to identify the owner
* @return Number of chunks released * @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 listnode *node;
struct label_manager_chunk *lmc; struct label_manager_chunk *lmc;

View File

@ -69,7 +69,7 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
uint8_t keep, uint32_t size); uint8_t keep, uint32_t size);
int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start, int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
uint32_t end); 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); void label_manager_close(void);
#endif /* _LABEL_MANAGER_H */ #endif /* _LABEL_MANAGER_H */

View File

@ -70,6 +70,7 @@ zebra_zebra_SOURCES = \
zebra/zserv.c \ zebra/zserv.c \
zebra/zebra_netns_id.c \ zebra/zebra_netns_id.c \
zebra/zebra_netns_notify.c \ zebra/zebra_netns_notify.c \
zebra/table_manager.c \
# end # end
zebra/zebra_vty_clippy.c: $(CLIPPY_DEPS) zebra/zebra_vty_clippy.c: $(CLIPPY_DEPS)
@ -113,6 +114,7 @@ noinst_HEADERS += \
zebra/zserv.h \ zebra/zserv.h \
zebra/zebra_netns_id.h \ zebra/zebra_netns_id.h \
zebra/zebra_netns_notify.h \ zebra/zebra_netns_notify.h \
zebra/table_manager.h \
# end # end
zebra_zebra_irdp_la_SOURCES = \ zebra_zebra_irdp_la_SOURCES = \

235
zebra/table_manager.c Normal file
View 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
View 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 */

View File

@ -38,6 +38,7 @@
#include "zebra_netns_id.h" #include "zebra_netns_id.h"
#include "zebra_pbr.h" #include "zebra_pbr.h"
#include "rib.h" #include "rib.h"
#include "table_manager.h"
extern struct zebra_privs_t zserv_privs; 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); interface_list(zns);
route_read(zns); route_read(zns);
/* Initiate Table Manager per ZNS */
table_manager_enable(ns_id);
return 0; return 0;
} }
@ -259,6 +263,8 @@ int zebra_ns_disable(ns_id_t ns_id, void **info)
kernel_terminate(zns); kernel_terminate(zns);
table_manager_disable(zns->ns_id);
zns->ns_id = NS_DEFAULT; zns->ns_id = NS_DEFAULT;
return 0; return 0;

View File

@ -122,8 +122,8 @@ static int zebra_vrf_enable(struct vrf *vrf)
/* Inform clients that the VRF is now active. This is an /* Inform clients that the VRF is now active. This is an
* add for the clients. * add for the clients.
*/ */
zebra_vrf_add_update(zvrf);
zebra_vrf_add_update(zvrf);
/* Allocate tables */ /* Allocate tables */
for (afi = AFI_IP; afi <= AFI_IP6; afi++) { for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)

View File

@ -61,6 +61,7 @@
#include "zebra/zebra_vxlan.h" #include "zebra/zebra_vxlan.h"
#include "zebra/rt.h" #include "zebra/rt.h"
#include "zebra/zebra_pbr.h" #include "zebra/zebra_pbr.h"
#include "zebra/table_manager.h"
/* Event list of zebra. */ /* Event list of zebra. */
enum event { ZEBRA_READ, ZEBRA_WRITE }; enum event { ZEBRA_READ, ZEBRA_WRITE };
@ -2186,6 +2187,60 @@ stream_failure:
return; 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, static void zread_label_manager_connect(struct zserv *client,
struct stream *msg, vrf_id_t vrf_id) 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. Release previous labels of same protocol and instance.
This is done in case it restarted from an unexpected shutdown. This is done in case it restarted from an unexpected shutdown.
*/ */
release_daemon_chunks(proto, instance); release_daemon_label_chunks(proto, instance);
zlog_debug( zlog_debug(
" Label Manager client connected: sock %d, proto %s, vrf %u instance %u", " Label Manager client connected: sock %d, proto %s, vrf %u instance %u",
@ -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) static void zread_pseudowire(ZAPI_HANDLER_ARGS)
{ {
struct stream *s; struct stream *s;
@ -2627,6 +2768,9 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_PW_UNSET] = zread_pseudowire, [ZEBRA_PW_UNSET] = zread_pseudowire,
[ZEBRA_RULE_ADD] = zread_rule, [ZEBRA_RULE_ADD] = zread_rule,
[ZEBRA_RULE_DELETE] = 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, 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); zebra_client_close_cleanup_rnh(client);
/* Release Label Manager chunks */ /* 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. */ /* Cleanup any FECs registered by this client. */
zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT), zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT),