mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-07 17:02:54 +00:00
Merge pull request #4660 from manuhalo/label_manager_fixes
Label manager improvements + refactor
This commit is contained in:
commit
07a4ddf2b6
@ -29,6 +29,7 @@
|
|||||||
#include "skiplist.h"
|
#include "skiplist.h"
|
||||||
#include "workqueue.h"
|
#include "workqueue.h"
|
||||||
#include "zclient.h"
|
#include "zclient.h"
|
||||||
|
#include "mpls.h"
|
||||||
|
|
||||||
#include "bgpd/bgpd.h"
|
#include "bgpd/bgpd.h"
|
||||||
#include "bgpd/bgp_labelpool.h"
|
#include "bgpd/bgp_labelpool.h"
|
||||||
@ -391,7 +392,8 @@ void bgp_lp_get(
|
|||||||
if (lp_fifo_count(&lp->requests) > lp->pending_count) {
|
if (lp_fifo_count(&lp->requests) > lp->pending_count) {
|
||||||
if (!zclient || zclient->sock < 0)
|
if (!zclient || zclient->sock < 0)
|
||||||
return;
|
return;
|
||||||
if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE))
|
if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE,
|
||||||
|
MPLS_LABEL_BASE_ANY))
|
||||||
lp->pending_count += LP_CHUNK_SIZE;
|
lp->pending_count += LP_CHUNK_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -552,7 +554,8 @@ void bgp_lp_event_zebra_up(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
zclient_send_get_label_chunk(zclient, 0, labels_needed);
|
zclient_send_get_label_chunk(zclient, 0, labels_needed,
|
||||||
|
MPLS_LABEL_BASE_ANY);
|
||||||
lp->pending_count = labels_needed;
|
lp->pending_count = labels_needed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1660,7 +1660,8 @@ lde_get_label_chunk(void)
|
|||||||
uint32_t start, end;
|
uint32_t start, end;
|
||||||
|
|
||||||
debug_labels("getting label chunk (size %u)", CHUNK_SIZE);
|
debug_labels("getting label chunk (size %u)", CHUNK_SIZE);
|
||||||
ret = lm_get_label_chunk(zclient_sync, 0, CHUNK_SIZE, &start, &end);
|
ret = lm_get_label_chunk(zclient_sync, 0, MPLS_LABEL_BASE_ANY,
|
||||||
|
CHUNK_SIZE, &start, &end);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
log_warnx("Error getting label chunk!");
|
log_warnx("Error getting label chunk!");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -236,6 +236,9 @@ main(int argc, char *argv[])
|
|||||||
" --ctl_socket Override ctl socket path\n"
|
" --ctl_socket Override ctl socket path\n"
|
||||||
" -n, --instance Instance id\n");
|
" -n, --instance Instance id\n");
|
||||||
|
|
||||||
|
/* set default instance (to differentiate ldpd socket from lde one */
|
||||||
|
init.instance = 1;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ extern "C" {
|
|||||||
#define MPLS_LABEL_RESERVED_MAX 15
|
#define MPLS_LABEL_RESERVED_MAX 15
|
||||||
#define MPLS_LABEL_UNRESERVED_MIN 16
|
#define MPLS_LABEL_UNRESERVED_MIN 16
|
||||||
#define MPLS_LABEL_UNRESERVED_MAX 1048575
|
#define MPLS_LABEL_UNRESERVED_MAX 1048575
|
||||||
|
#define MPLS_LABEL_BASE_ANY 0
|
||||||
|
|
||||||
/* Default min and max SRGB label range */
|
/* Default min and max SRGB label range */
|
||||||
/* Even if the SRGB allows to manage different Label space between routers,
|
/* Even if the SRGB allows to manage different Label space between routers,
|
||||||
|
@ -1995,10 +1995,11 @@ int lm_label_manager_connect(struct zclient *zclient, int async)
|
|||||||
* @param zclient Zclient used to connect to label manager (zebra)
|
* @param zclient Zclient used to connect to label manager (zebra)
|
||||||
* @param keep Avoid garbage collection
|
* @param keep Avoid garbage collection
|
||||||
* @param chunk_size Amount of labels requested
|
* @param chunk_size Amount of labels requested
|
||||||
|
* @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care
|
||||||
* @result 0 on success, -1 otherwise
|
* @result 0 on success, -1 otherwise
|
||||||
*/
|
*/
|
||||||
int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||||
uint32_t chunk_size)
|
uint32_t chunk_size, uint32_t base)
|
||||||
{
|
{
|
||||||
struct stream *s;
|
struct stream *s;
|
||||||
|
|
||||||
@ -2018,6 +2019,7 @@ int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
|||||||
stream_putw(s, zclient->instance);
|
stream_putw(s, zclient->instance);
|
||||||
stream_putc(s, keep);
|
stream_putc(s, keep);
|
||||||
stream_putl(s, chunk_size);
|
stream_putl(s, chunk_size);
|
||||||
|
stream_putl(s, base);
|
||||||
|
|
||||||
/* Put length at the first point of the stream. */
|
/* Put length at the first point of the stream. */
|
||||||
stream_putw_at(s, 0, stream_get_endp(s));
|
stream_putw_at(s, 0, stream_get_endp(s));
|
||||||
@ -2038,7 +2040,7 @@ int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
|||||||
* @param end To write last assigned chunk label to
|
* @param end To write last assigned chunk label to
|
||||||
* @result 0 on success, -1 otherwise
|
* @result 0 on success, -1 otherwise
|
||||||
*/
|
*/
|
||||||
int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
int lm_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t base,
|
||||||
uint32_t chunk_size, uint32_t *start, uint32_t *end)
|
uint32_t chunk_size, uint32_t *start, uint32_t *end)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -2063,6 +2065,8 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
|||||||
stream_putc(s, keep);
|
stream_putc(s, keep);
|
||||||
/* chunk size */
|
/* chunk size */
|
||||||
stream_putl(s, chunk_size);
|
stream_putl(s, chunk_size);
|
||||||
|
/* requested chunk base */
|
||||||
|
stream_putl(s, base);
|
||||||
/* Put length at the first point of the stream. */
|
/* Put length at the first point of the stream. */
|
||||||
stream_putw_at(s, 0, stream_get_endp(s));
|
stream_putw_at(s, 0, stream_get_endp(s));
|
||||||
|
|
||||||
@ -2103,6 +2107,15 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
|||||||
"Wrong instId (%u) in get chunk response Should be %u",
|
"Wrong instId (%u) in get chunk response Should be %u",
|
||||||
instance, zclient->instance);
|
instance, zclient->instance);
|
||||||
|
|
||||||
|
/* if we requested a specific chunk and it could not be allocated, the
|
||||||
|
* response message will end here
|
||||||
|
*/
|
||||||
|
if (!STREAM_READABLE(s)) {
|
||||||
|
zlog_info("Unable to assign Label Chunk to %s instance %u",
|
||||||
|
zebra_route_string(proto), instance);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* keep */
|
/* keep */
|
||||||
response_keep = stream_getc(s);
|
response_keep = stream_getc(s);
|
||||||
/* start and end labels */
|
/* start and end labels */
|
||||||
|
@ -609,15 +609,13 @@ extern struct interface *zebra_interface_link_params_read(struct stream *s,
|
|||||||
vrf_id_t vrf_id);
|
vrf_id_t vrf_id);
|
||||||
extern size_t zebra_interface_link_params_write(struct stream *,
|
extern size_t zebra_interface_link_params_write(struct stream *,
|
||||||
struct interface *);
|
struct interface *);
|
||||||
extern int zclient_send_get_label_chunk(
|
extern int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||||
struct zclient *zclient,
|
uint32_t chunk_size, uint32_t base);
|
||||||
uint8_t keep,
|
|
||||||
uint32_t chunk_size);
|
|
||||||
|
|
||||||
extern int lm_label_manager_connect(struct zclient *zclient, int async);
|
extern int lm_label_manager_connect(struct zclient *zclient, int async);
|
||||||
extern int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
extern int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||||
uint32_t chunk_size, uint32_t *start,
|
uint32_t base, uint32_t chunk_size,
|
||||||
uint32_t *end);
|
uint32_t *start, 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_table_manager_connect(struct zclient *zclient);
|
||||||
|
@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
* Label Manager Test
|
|
||||||
*
|
|
||||||
* Copyright (C) 2017 by Bingen Eguzkitza,
|
|
||||||
* Volta Networks Inc.
|
|
||||||
*
|
|
||||||
* This file is part of FreeRangeRouting (FRR)
|
|
||||||
*
|
|
||||||
* FRR 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, or (at your option) any
|
|
||||||
* later version.
|
|
||||||
*
|
|
||||||
* FRR 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "lib/stream.h"
|
|
||||||
#include "lib/zclient.h"
|
|
||||||
|
|
||||||
#define ZSERV_PATH "/tmp/zserv.api" // TODO!!
|
|
||||||
#define KEEP 0 /* change to 1 to avoid garbage collection */
|
|
||||||
#define CHUNK_SIZE 32
|
|
||||||
|
|
||||||
struct zclient *zclient;
|
|
||||||
unsigned short instance = 1;
|
|
||||||
|
|
||||||
const char *sequence = "GGRGGGRRG";
|
|
||||||
|
|
||||||
static int zebra_send_get_label_chunk(void);
|
|
||||||
static int zebra_send_release_label_chunk(uint32_t start, uint32_t end);
|
|
||||||
|
|
||||||
static void process_next_call(uint32_t start, uint32_t end)
|
|
||||||
{
|
|
||||||
sleep(3);
|
|
||||||
if (!*sequence)
|
|
||||||
exit(0);
|
|
||||||
if (*sequence == 'G')
|
|
||||||
zebra_send_get_label_chunk();
|
|
||||||
else if (*sequence == 'R')
|
|
||||||
zebra_send_release_label_chunk(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Connect to Label Manager */
|
|
||||||
|
|
||||||
static int zebra_send_label_manager_connect()
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
printf("Connect to Label Manager\n");
|
|
||||||
|
|
||||||
ret = lm_label_manager_connect(zclient, 0);
|
|
||||||
printf("Label Manager connection result: %u \n", ret);
|
|
||||||
if (ret != 0) {
|
|
||||||
fprintf(stderr, "Error %d connecting to Label Manager %s\n",
|
|
||||||
ret, strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
process_next_call(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get Label Chunk */
|
|
||||||
|
|
||||||
static int zebra_send_get_label_chunk()
|
|
||||||
{
|
|
||||||
uint32_t start;
|
|
||||||
uint32_t end;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
printf("Ask for label chunk \n");
|
|
||||||
|
|
||||||
ret = lm_get_label_chunk(zclient, KEEP, CHUNK_SIZE, &start, &end);
|
|
||||||
if (ret != 0) {
|
|
||||||
fprintf(stderr, "Error %d requesting label chunk %s\n", ret,
|
|
||||||
strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
sequence++;
|
|
||||||
|
|
||||||
printf("Label Chunk assign: %u - %u \n", start, end);
|
|
||||||
|
|
||||||
process_next_call(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release Label Chunk */
|
|
||||||
|
|
||||||
static int zebra_send_release_label_chunk(uint32_t start, uint32_t end)
|
|
||||||
{
|
|
||||||
struct stream *s;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
printf("Release label chunk: %u - %u\n", start, end);
|
|
||||||
|
|
||||||
ret = lm_release_label_chunk(zclient, start, end);
|
|
||||||
if (ret != 0) {
|
|
||||||
fprintf(stderr, "Error releasing label chunk\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
sequence++;
|
|
||||||
|
|
||||||
process_next_call(start - CHUNK_SIZE, end - CHUNK_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void init_zclient(struct thread_master *master, char *lm_zserv_path)
|
|
||||||
{
|
|
||||||
frr_zclient_addr(&zclient_addr, &zclient_addr_len, lm_zserv_path);
|
|
||||||
|
|
||||||
zclient = zclient_new(master, &zclient_options_default);
|
|
||||||
/* zclient_init(zclient, ZEBRA_LABEL_MANAGER, 0); */
|
|
||||||
zclient->sock = -1;
|
|
||||||
zclient->redist_default = ZEBRA_ROUTE_LDP;
|
|
||||||
zclient->instance = instance;
|
|
||||||
if (zclient_socket_connect(zclient) < 0) {
|
|
||||||
printf("Error connecting synchronous zclient!\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
struct thread_master *master;
|
|
||||||
struct thread thread;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
printf("Sequence to be tested: %s\n", sequence);
|
|
||||||
|
|
||||||
master = thread_master_create(NULL);
|
|
||||||
init_zclient(master, ZSERV_PATH);
|
|
||||||
|
|
||||||
zebra_send_label_manager_connect();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
debug bgp vpn label
|
|
||||||
!
|
|
||||||
router bgp 9101
|
|
||||||
bgp router-id 10.1.1.2
|
|
||||||
neighbor 10.1.1.1 remote-as 7777
|
|
||||||
address-family ipv4 unicast
|
|
||||||
redistribute connected
|
|
||||||
exit-address-family
|
|
||||||
!
|
|
@ -1,11 +0,0 @@
|
|||||||
debug zebra events
|
|
||||||
debug zebra packet
|
|
||||||
!
|
|
||||||
interface lo
|
|
||||||
ip address 66.1.0.1/32
|
|
||||||
!
|
|
||||||
interface ce1-eth0
|
|
||||||
ip address 10.1.1.2/30
|
|
||||||
!
|
|
||||||
ip forwarding
|
|
||||||
!
|
|
@ -1,9 +0,0 @@
|
|||||||
debug bgp vpn label
|
|
||||||
!
|
|
||||||
router bgp 9102
|
|
||||||
bgp router-id 10.1.2.2
|
|
||||||
neighbor 10.1.2.1 remote-as 7777
|
|
||||||
address-family ipv4 unicast
|
|
||||||
redistribute connected
|
|
||||||
exit-address-family
|
|
||||||
!
|
|
@ -1,11 +0,0 @@
|
|||||||
debug zebra events
|
|
||||||
debug zebra packet
|
|
||||||
!
|
|
||||||
interface lo
|
|
||||||
ip address 66.1.0.2/32
|
|
||||||
!
|
|
||||||
interface ce2-eth0
|
|
||||||
ip address 10.1.2.2/30
|
|
||||||
!
|
|
||||||
ip forwarding
|
|
||||||
!
|
|
@ -1,102 +0,0 @@
|
|||||||
## Color coding:
|
|
||||||
#########################
|
|
||||||
## Main FRR: #f08080 red
|
|
||||||
## Switches: #d0e0d0 gray
|
|
||||||
## RIP: #19e3d9 Cyan
|
|
||||||
## RIPng: #fcb314 dark yellow
|
|
||||||
## OSPFv2: #32b835 Green
|
|
||||||
## OSPFv3: #19e3d9 Cyan
|
|
||||||
## ISIS IPv4 #fcb314 dark yellow
|
|
||||||
## ISIS IPv6 #9a81ec purple
|
|
||||||
## BGP IPv4 #eee3d3 beige
|
|
||||||
## BGP IPv6 #fdff00 yellow
|
|
||||||
##### Colors (see http://www.color-hex.com/)
|
|
||||||
|
|
||||||
graph template {
|
|
||||||
label="Test Topology - Label Manager proxy";
|
|
||||||
|
|
||||||
# Routers
|
|
||||||
|
|
||||||
lm [ shape=doubleoctagon,
|
|
||||||
label="label manager",
|
|
||||||
fillcolor="#f08080",
|
|
||||||
style=filled
|
|
||||||
];
|
|
||||||
ce1 [
|
|
||||||
shape=doubleoctagon,
|
|
||||||
label="ce1",
|
|
||||||
fillcolor="#f08080",
|
|
||||||
style=filled
|
|
||||||
];
|
|
||||||
ce2 [
|
|
||||||
shape=doubleoctagon
|
|
||||||
label="ce2",
|
|
||||||
fillcolor="#f08080",
|
|
||||||
style=filled
|
|
||||||
];
|
|
||||||
pe1 [
|
|
||||||
shape=doubleoctagon,
|
|
||||||
label="pe1",
|
|
||||||
fillcolor="#f08080",
|
|
||||||
style=filled
|
|
||||||
];
|
|
||||||
pe2 [
|
|
||||||
shape=doubleoctagon
|
|
||||||
label="pe2",
|
|
||||||
fillcolor="#f08080",
|
|
||||||
style=filled
|
|
||||||
];
|
|
||||||
p1 [
|
|
||||||
shape=doubleoctagon
|
|
||||||
label="p1",
|
|
||||||
fillcolor="#f08080",
|
|
||||||
style=filled
|
|
||||||
];
|
|
||||||
|
|
||||||
# Switches
|
|
||||||
|
|
||||||
s1 [
|
|
||||||
shape=oval,
|
|
||||||
label="s1\n10.1.1.0/30",
|
|
||||||
fillcolor="#d0e0d0",
|
|
||||||
style=filled
|
|
||||||
];
|
|
||||||
s2 [
|
|
||||||
shape=oval,
|
|
||||||
label="s2\n77.0.1.0/24",
|
|
||||||
fillcolor="#d0e0d0",
|
|
||||||
style=filled
|
|
||||||
];
|
|
||||||
s3 [
|
|
||||||
shape=oval,
|
|
||||||
label="s3\n77.0.2.0/24",
|
|
||||||
fillcolor="#d0e0d0",
|
|
||||||
style=filled
|
|
||||||
];
|
|
||||||
s4 [
|
|
||||||
shape=oval,
|
|
||||||
label="s4\n10.1.2.0/30",
|
|
||||||
fillcolor="#d0e0d0",
|
|
||||||
style=filled
|
|
||||||
];
|
|
||||||
|
|
||||||
# Connections
|
|
||||||
|
|
||||||
ce1 -- s1 [label="eth0\n.2"];
|
|
||||||
pe1 -- s1 [label="eth0\n.1"];
|
|
||||||
|
|
||||||
pe1 -- s2 [label="eth1\n.1"];
|
|
||||||
p1 -- s2 [label="eth0\n.2"];
|
|
||||||
|
|
||||||
pe2 -- s3 [label="eth1\n.1"];
|
|
||||||
p1 -- s3 [label="eth1\n.2"];
|
|
||||||
|
|
||||||
ce2 -- s4 [label="eth0\n.2"];
|
|
||||||
pe2 -- s4 [label="eth0\n.1"];
|
|
||||||
|
|
||||||
lm -- ce1;
|
|
||||||
lm -- pe1;
|
|
||||||
lm -- p1;
|
|
||||||
lm -- pe2;
|
|
||||||
lm -- ce2;
|
|
||||||
}
|
|
Binary file not shown.
@ -1,3 +0,0 @@
|
|||||||
debug zebra events
|
|
||||||
debug zebra packet
|
|
||||||
!
|
|
@ -1,9 +0,0 @@
|
|||||||
!
|
|
||||||
mpls ldp
|
|
||||||
router-id 7.0.0.101
|
|
||||||
address-family ipv4
|
|
||||||
discovery transport-address 7.0.0.101
|
|
||||||
interface p1-eth0
|
|
||||||
interface p1-eth1
|
|
||||||
exit-address-family
|
|
||||||
!
|
|
@ -1,7 +0,0 @@
|
|||||||
!
|
|
||||||
router ospf
|
|
||||||
ospf router-id 7.0.0.101
|
|
||||||
network 7.0.0.101/32 area 0
|
|
||||||
network 77.0.1.0/24 area 0
|
|
||||||
network 77.0.2.0/24 area 0
|
|
||||||
!
|
|
@ -1,12 +0,0 @@
|
|||||||
debug zebra events
|
|
||||||
debug zebra packet
|
|
||||||
!
|
|
||||||
interface lo
|
|
||||||
ip address 7.0.0.101/32
|
|
||||||
!
|
|
||||||
interface p1-eth0
|
|
||||||
ip address 77.0.1.2/24
|
|
||||||
!
|
|
||||||
interface p1-eth1
|
|
||||||
ip address 77.0.2.2/24
|
|
||||||
!
|
|
@ -1,26 +0,0 @@
|
|||||||
debug bgp vpn label
|
|
||||||
!
|
|
||||||
router bgp 7777
|
|
||||||
bgp router-id 7.0.0.1
|
|
||||||
neighbor 7.0.0.2 remote-as 7777
|
|
||||||
neighbor 7.0.0.2 update-source 7.0.0.1
|
|
||||||
address-family ipv4 unicast
|
|
||||||
no neighbor 7.0.0.2 activate
|
|
||||||
exit-address-family
|
|
||||||
address-family ipv4 vpn
|
|
||||||
neighbor 7.0.0.2 activate
|
|
||||||
exit-address-family
|
|
||||||
!
|
|
||||||
router bgp 7777 vrf A
|
|
||||||
bgp router-id 10.1.1.1
|
|
||||||
neighbor 10.1.1.2 remote-as 9101
|
|
||||||
address-family ipv4 unicast
|
|
||||||
label vpn export auto
|
|
||||||
rd vpn export 110:1
|
|
||||||
rt vpn both 152:100
|
|
||||||
import vpn
|
|
||||||
export vpn
|
|
||||||
redistribute connected
|
|
||||||
redistribute ospf
|
|
||||||
exit-address-family
|
|
||||||
!
|
|
@ -1,8 +0,0 @@
|
|||||||
!
|
|
||||||
mpls ldp
|
|
||||||
router-id 7.0.0.1
|
|
||||||
address-family ipv4
|
|
||||||
discovery transport-address 7.0.0.1
|
|
||||||
interface pe1-eth1
|
|
||||||
exit-address-family
|
|
||||||
!
|
|
@ -1,6 +0,0 @@
|
|||||||
!
|
|
||||||
router ospf
|
|
||||||
ospf router-id 7.0.0.1
|
|
||||||
network 77.0.0.0/16 area 0
|
|
||||||
redistribute connected
|
|
||||||
!
|
|
@ -1,14 +0,0 @@
|
|||||||
debug zebra events
|
|
||||||
debug zebra packet
|
|
||||||
!
|
|
||||||
interface lo
|
|
||||||
ip address 7.0.0.1/32
|
|
||||||
!
|
|
||||||
interface pe1-eth0 vrf A
|
|
||||||
ip address 10.1.1.1/30
|
|
||||||
!
|
|
||||||
interface pe1-eth1
|
|
||||||
ip address 77.0.1.1/24
|
|
||||||
!
|
|
||||||
ip forwarding
|
|
||||||
!
|
|
@ -1,26 +0,0 @@
|
|||||||
debug bgp vpn label
|
|
||||||
!
|
|
||||||
router bgp 7777
|
|
||||||
bgp router-id 7.0.0.2
|
|
||||||
neighbor 7.0.0.1 remote-as 7777
|
|
||||||
neighbor 7.0.0.1 update-source 7.0.0.2
|
|
||||||
address-family ipv4 unicast
|
|
||||||
no neighbor 7.0.0.1 activate
|
|
||||||
exit-address-family
|
|
||||||
address-family ipv4 vpn
|
|
||||||
neighbor 7.0.0.1 activate
|
|
||||||
exit-address-family
|
|
||||||
!
|
|
||||||
router bgp 7777 vrf A
|
|
||||||
bgp router-id 10.1.2.1
|
|
||||||
neighbor 10.1.2.2 remote-as 9102
|
|
||||||
address-family ipv4 unicast
|
|
||||||
label vpn export auto
|
|
||||||
rd vpn export 110:2
|
|
||||||
rt vpn both 152:100
|
|
||||||
import vpn
|
|
||||||
export vpn
|
|
||||||
redistribute connected
|
|
||||||
redistribute ospf
|
|
||||||
exit-address-family
|
|
||||||
!
|
|
@ -1,8 +0,0 @@
|
|||||||
!
|
|
||||||
mpls ldp
|
|
||||||
router-id 7.0.0.2
|
|
||||||
address-family ipv4
|
|
||||||
discovery transport-address 7.0.0.2
|
|
||||||
interface pe2-eth1
|
|
||||||
exit-address-family
|
|
||||||
!
|
|
@ -1,6 +0,0 @@
|
|||||||
!
|
|
||||||
router ospf
|
|
||||||
ospf router-id 7.0.0.2
|
|
||||||
network 77.0.0.0/16 area 0
|
|
||||||
redistribute connected
|
|
||||||
!
|
|
@ -1,14 +0,0 @@
|
|||||||
debug zebra events
|
|
||||||
debug zebra packet
|
|
||||||
!
|
|
||||||
interface lo
|
|
||||||
ip address 7.0.0.2/32
|
|
||||||
!
|
|
||||||
interface pe2-eth1
|
|
||||||
ip address 77.0.2.1/24
|
|
||||||
!
|
|
||||||
interface pe2-eth0 vrf A
|
|
||||||
ip address 10.1.2.1/30
|
|
||||||
!
|
|
||||||
ip forwarding
|
|
||||||
!
|
|
@ -1,205 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
#
|
|
||||||
# test_lm-proxy-topo1.py
|
|
||||||
# Part of NetDEF Topology Tests
|
|
||||||
#
|
|
||||||
# Copyright (c) 2018 by Volta Networks, Inc.
|
|
||||||
#
|
|
||||||
# Requirements, so the test is not skipped:
|
|
||||||
# - Linux kernel with VRF support
|
|
||||||
# - 'ip' command with VRF support (e.g. iproute2-ss180129 works)
|
|
||||||
# - FRR BGP daemon supporting label manager using instance id
|
|
||||||
#
|
|
||||||
# Permission to use, copy, modify, and/or distribute this software
|
|
||||||
# for any purpose with or without fee is hereby granted, provided
|
|
||||||
# that the above copyright notice and this permission notice appear
|
|
||||||
# in all copies.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
|
|
||||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
|
|
||||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
|
||||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
||||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
||||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
||||||
# OF THIS SOFTWARE.
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
# Save the Current Working Directory to find configuration files.
|
|
||||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
sys.path.append(os.path.join(CWD, '../'))
|
|
||||||
|
|
||||||
# pylint: disable=C0413
|
|
||||||
# Import topogen and topotest helpers
|
|
||||||
from lib import topotest
|
|
||||||
from lib.topogen import Topogen, TopoRouter, get_topogen
|
|
||||||
from lib.topolog import logger
|
|
||||||
|
|
||||||
# Required to instantiate the topology builder class.
|
|
||||||
from mininet.topo import Topo
|
|
||||||
|
|
||||||
vrf_name = 'A'
|
|
||||||
|
|
||||||
class NetworkTopo(Topo):
|
|
||||||
"Label Manager proxy topology"
|
|
||||||
|
|
||||||
# Relationship between routers, switches, and hosts
|
|
||||||
def build(self, *_args, **_opts):
|
|
||||||
"Build function"
|
|
||||||
|
|
||||||
tgen = get_topogen(self)
|
|
||||||
|
|
||||||
# FRR routers
|
|
||||||
|
|
||||||
for router in ['lm', 'ce1', 'pe1', 'p1', 'pe2', 'ce2']:
|
|
||||||
tgen.add_router(router);
|
|
||||||
|
|
||||||
# Connections
|
|
||||||
|
|
||||||
switch = tgen.add_switch('s1')
|
|
||||||
switch.add_link(tgen.gears['ce1'], nodeif='ce1-eth0')
|
|
||||||
switch.add_link(tgen.gears['pe1'], nodeif='pe1-eth0')
|
|
||||||
|
|
||||||
switch = tgen.add_switch('s2')
|
|
||||||
switch.add_link(tgen.gears['pe1'], nodeif='pe1-eth1')
|
|
||||||
switch.add_link(tgen.gears['p1'], nodeif='p1-eth0')
|
|
||||||
|
|
||||||
switch = tgen.add_switch('s3')
|
|
||||||
switch.add_link(tgen.gears['p1'], nodeif='p1-eth1')
|
|
||||||
switch.add_link(tgen.gears['pe2'], nodeif='pe2-eth1')
|
|
||||||
|
|
||||||
switch = tgen.add_switch('s4')
|
|
||||||
switch.add_link(tgen.gears['ce2'], nodeif='ce2-eth0')
|
|
||||||
switch.add_link(tgen.gears['pe2'], nodeif='pe2-eth0')
|
|
||||||
|
|
||||||
# Test environment handling
|
|
||||||
|
|
||||||
def vrf_destroy(router, vrf):
|
|
||||||
router.run('ip link delete dev ' + vrf)
|
|
||||||
|
|
||||||
def vrf_setup(router, eth_in, vrf, vrf_table):
|
|
||||||
cmds = ['ip link set dev lo up',
|
|
||||||
'echo 10000 > /proc/sys/net/mpls/platform_labels',
|
|
||||||
'ip link add dev ' + vrf + ' type vrf table ' + vrf_table,
|
|
||||||
'ip link set ' + vrf + ' up',
|
|
||||||
'ip link set ' + eth_in + ' vrf ' + vrf,
|
|
||||||
'echo 1 > /proc/sys/net/mpls/conf/' + vrf + '/input'
|
|
||||||
]
|
|
||||||
vrf_destroy(router, vrf)
|
|
||||||
for cmd in cmds:
|
|
||||||
logger.info('[vrf_setup] cmd: ' + cmd)
|
|
||||||
out = router.run(cmd)
|
|
||||||
if out != None and len(out) > 0:
|
|
||||||
logger.info('[vrf_setup] "{}" error: out="{}"'.format(cmd, out))
|
|
||||||
|
|
||||||
def setup_module(mod):
|
|
||||||
"pytest environment setup"
|
|
||||||
|
|
||||||
tgen = Topogen(NetworkTopo, mod.__name__)
|
|
||||||
tgen.start_topology()
|
|
||||||
|
|
||||||
router_list = tgen.routers()
|
|
||||||
|
|
||||||
# Load router configuration
|
|
||||||
|
|
||||||
ldp_id = 1
|
|
||||||
bgp_id = 101
|
|
||||||
lm_sock = '../lm/label_mgr.sock'
|
|
||||||
|
|
||||||
for rname, router in router_list.iteritems():
|
|
||||||
if rname == 'lm' :
|
|
||||||
router.load_config(
|
|
||||||
TopoRouter.RD_ZEBRA,
|
|
||||||
os.path.join(CWD, '{}/zebra.conf'.format(rname)),
|
|
||||||
'-z ' + lm_sock
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
rtype = ''.join([i for i in rname if not i.isdigit()])
|
|
||||||
|
|
||||||
router.load_config(
|
|
||||||
TopoRouter.RD_ZEBRA,
|
|
||||||
os.path.join(CWD, '{}/zebra.conf'.format(rname)),
|
|
||||||
'-l ' + lm_sock
|
|
||||||
)
|
|
||||||
|
|
||||||
if router.check_capability(TopoRouter.RD_ZEBRA, '--vrfwnetns') == False:
|
|
||||||
return pytest.skip('Skipping test: no VRF support')
|
|
||||||
|
|
||||||
if rtype == 'ce' or rtype == 'pe':
|
|
||||||
if router.check_capability(TopoRouter.RD_BGP, '--int_num') == False:
|
|
||||||
return pytest.skip('Skipping test: no BGP LM support')
|
|
||||||
router.load_config(
|
|
||||||
TopoRouter.RD_BGP,
|
|
||||||
os.path.join(CWD, '{}/bgpd.conf'.format(rname)),
|
|
||||||
'-I %d' % bgp_id
|
|
||||||
)
|
|
||||||
bgp_id += 1
|
|
||||||
|
|
||||||
if rtype == 'pe' or rtype == 'p':
|
|
||||||
router.load_config(
|
|
||||||
TopoRouter.RD_OSPF,
|
|
||||||
os.path.join(CWD, '{}/ospfd.conf'.format(rname))
|
|
||||||
)
|
|
||||||
router.load_config(
|
|
||||||
TopoRouter.RD_LDP,
|
|
||||||
os.path.join(CWD, '{}/ldpd.conf'.format(rname)),
|
|
||||||
'-n %d' % ldp_id
|
|
||||||
)
|
|
||||||
ldp_id += 1
|
|
||||||
|
|
||||||
# Prepare VRF's
|
|
||||||
|
|
||||||
router = tgen.gears['pe1']
|
|
||||||
out = router.run('ip -h 2>&1 | grep vrf | wc -l')
|
|
||||||
if int(out) == 0:
|
|
||||||
return pytest.skip('Skipping test: ip/iproute2 has no VRF support')
|
|
||||||
|
|
||||||
vrf_setup(tgen.gears['pe1'], 'pe1-eth0', vrf_name, '1')
|
|
||||||
vrf_setup(tgen.gears['pe2'], 'pe2-eth0', vrf_name, '1')
|
|
||||||
|
|
||||||
# Start routers
|
|
||||||
|
|
||||||
tgen.start_router(tgen.gears['lm'])
|
|
||||||
for rname, router in router_list.iteritems():
|
|
||||||
if rname != 'lm':
|
|
||||||
tgen.start_router(router)
|
|
||||||
|
|
||||||
def teardown_module(mod):
|
|
||||||
tgen = get_topogen()
|
|
||||||
for router in ['pe1', 'pe2']:
|
|
||||||
vrf_destroy(tgen.gears[router], vrf_name)
|
|
||||||
tgen.stop_topology()
|
|
||||||
|
|
||||||
def test_lm_proxy():
|
|
||||||
logger.info('Test: label manager (LDP and BGP)')
|
|
||||||
tgen = get_topogen()
|
|
||||||
|
|
||||||
# Skip if previous fatal error condition is raised
|
|
||||||
if tgen.routers_have_failure():
|
|
||||||
pytest.skip(tgen.errors)
|
|
||||||
|
|
||||||
cmd = 'show mpls ldp binding'
|
|
||||||
|
|
||||||
router = tgen.gears['p1']
|
|
||||||
|
|
||||||
def check_labels(router, cmd):
|
|
||||||
output = router.vtysh_cmd(cmd, isjson=False)
|
|
||||||
logger.info('chk_labels [' + cmd + ']: ' + output)
|
|
||||||
return output.count('\n')
|
|
||||||
|
|
||||||
test_func = partial(check_labels, router, cmd)
|
|
||||||
result, diff = topotest.run_and_expect(test_func, 12, count=6, wait=30)
|
|
||||||
assert result, 'wrong labels'
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
args = ["-s"] + sys.argv[1:]
|
|
||||||
sys.exit(pytest.main(args))
|
|
||||||
|
|
@ -38,297 +38,67 @@
|
|||||||
#include "zebra/zebra_router.h"
|
#include "zebra/zebra_router.h"
|
||||||
#include "zebra/label_manager.h"
|
#include "zebra/label_manager.h"
|
||||||
#include "zebra/zebra_errors.h"
|
#include "zebra/zebra_errors.h"
|
||||||
|
#include "zebra/zapi_msg.h"
|
||||||
|
|
||||||
#define CONNECTION_DELAY 5
|
#define CONNECTION_DELAY 5
|
||||||
|
|
||||||
struct label_manager lbl_mgr;
|
struct label_manager lbl_mgr;
|
||||||
|
|
||||||
extern struct zebra_privs_t zserv_privs;
|
|
||||||
|
|
||||||
DEFINE_MGROUP(LBL_MGR, "Label Manager");
|
DEFINE_MGROUP(LBL_MGR, "Label Manager");
|
||||||
DEFINE_MTYPE_STATIC(LBL_MGR, LM_CHUNK, "Label Manager Chunk");
|
DEFINE_MTYPE_STATIC(LBL_MGR, LM_CHUNK, "Label Manager Chunk");
|
||||||
|
|
||||||
/* In case this zebra daemon is not acting as label manager,
|
/* define hooks for the basic API, so that it can be specialized or served
|
||||||
* it will be a proxy to relay messages to external label manager
|
* externally
|
||||||
* This zclient thus is to connect to it
|
|
||||||
*/
|
*/
|
||||||
static struct stream *obuf;
|
|
||||||
static struct zclient *zclient;
|
|
||||||
bool lm_is_external;
|
|
||||||
|
|
||||||
static void delete_label_chunk(void *val)
|
DEFINE_HOOK(lm_client_connect,
|
||||||
|
(uint8_t proto, uint16_t instance, vrf_id_t vrf_id),
|
||||||
|
(proto, instance, vrf_id));
|
||||||
|
DEFINE_HOOK(lm_client_disconnect, (uint8_t proto, uint16_t instance),
|
||||||
|
(proto, instance));
|
||||||
|
DEFINE_HOOK(lm_get_chunk,
|
||||||
|
(struct label_manager_chunk * *lmc, uint8_t proto,
|
||||||
|
uint16_t instance, uint8_t keep, uint32_t size, uint32_t base,
|
||||||
|
vrf_id_t vrf_id),
|
||||||
|
(lmc, proto, instance, keep, size, base, vrf_id));
|
||||||
|
DEFINE_HOOK(lm_release_chunk,
|
||||||
|
(uint8_t proto, uint16_t instance, uint32_t start, uint32_t end),
|
||||||
|
(proto, instance, start, end));
|
||||||
|
DEFINE_HOOK(lm_cbs_inited, (), ());
|
||||||
|
|
||||||
|
/* define wrappers to be called in zapi_msg.c (as hooks must be called in
|
||||||
|
* source file where they were defined)
|
||||||
|
*/
|
||||||
|
void lm_client_connect_call(uint8_t proto, uint16_t instance, vrf_id_t vrf_id)
|
||||||
|
{
|
||||||
|
hook_call(lm_client_connect, proto, instance, vrf_id);
|
||||||
|
}
|
||||||
|
void lm_get_chunk_call(struct label_manager_chunk **lmc, uint8_t proto,
|
||||||
|
uint16_t instance, uint8_t keep, uint32_t size,
|
||||||
|
uint32_t base, vrf_id_t vrf_id)
|
||||||
|
{
|
||||||
|
hook_call(lm_get_chunk, lmc, proto, instance, keep, size, base, vrf_id);
|
||||||
|
}
|
||||||
|
void lm_release_chunk_call(uint8_t proto, uint16_t instance, uint32_t start,
|
||||||
|
uint32_t end)
|
||||||
|
{
|
||||||
|
hook_call(lm_release_chunk, proto, instance, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* forward declarations of the static functions to be used for some hooks */
|
||||||
|
static int label_manager_connect(uint8_t proto, uint16_t instance,
|
||||||
|
vrf_id_t vrf_id);
|
||||||
|
static int label_manager_disconnect(uint8_t proto, uint16_t instance);
|
||||||
|
static int label_manager_get_chunk(struct label_manager_chunk **lmc,
|
||||||
|
uint8_t proto, uint16_t instance,
|
||||||
|
uint8_t keep, uint32_t size, uint32_t base,
|
||||||
|
vrf_id_t vrf_id);
|
||||||
|
|
||||||
|
void delete_label_chunk(void *val)
|
||||||
{
|
{
|
||||||
XFREE(MTYPE_LM_CHUNK, val);
|
XFREE(MTYPE_LM_CHUNK, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int relay_response_back(void)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
struct stream *src, *dst;
|
|
||||||
uint16_t size = 0;
|
|
||||||
uint8_t marker;
|
|
||||||
uint8_t version;
|
|
||||||
vrf_id_t vrf_id;
|
|
||||||
uint16_t resp_cmd;
|
|
||||||
uint8_t proto;
|
|
||||||
const char *proto_str;
|
|
||||||
unsigned short instance;
|
|
||||||
struct zserv *zserv;
|
|
||||||
|
|
||||||
/* sanity */
|
|
||||||
if (!zclient || zclient->sock < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* input buffer with msg from label manager */
|
|
||||||
src = zclient->ibuf;
|
|
||||||
|
|
||||||
stream_reset(src);
|
|
||||||
|
|
||||||
/* parse header */
|
|
||||||
ret = zclient_read_header(src, zclient->sock, &size, &marker, &version,
|
|
||||||
&vrf_id, &resp_cmd);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (errno != EAGAIN)
|
|
||||||
flog_err(EC_ZEBRA_LM_RESPONSE,
|
|
||||||
"Error reading Label Manager response: %s",
|
|
||||||
strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do not relay a msg that has nothing to do with LM */
|
|
||||||
switch (resp_cmd) {
|
|
||||||
case ZEBRA_LABEL_MANAGER_CONNECT:
|
|
||||||
case ZEBRA_LABEL_MANAGER_CONNECT_ASYNC: /* should not be seen */
|
|
||||||
case ZEBRA_GET_LABEL_CHUNK:
|
|
||||||
case ZEBRA_RELEASE_LABEL_CHUNK:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
zlog_debug("Not relaying '%s' response (size %d) from LM",
|
|
||||||
zserv_command_string(resp_cmd), size);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
zlog_debug("Received '%s' response (size %d) from LM",
|
|
||||||
zserv_command_string(resp_cmd), size);
|
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Get the 'proto' field of the message */
|
|
||||||
proto = stream_getc(src);
|
|
||||||
|
|
||||||
/* Get the 'instance' field of the message */
|
|
||||||
instance = stream_getw(src);
|
|
||||||
|
|
||||||
proto_str = zebra_route_string(proto);
|
|
||||||
|
|
||||||
/* lookup the client to relay the msg to */
|
|
||||||
zserv = zserv_find_client(proto, instance);
|
|
||||||
if (!zserv) {
|
|
||||||
flog_err(
|
|
||||||
EC_ZEBRA_LM_NO_SUCH_CLIENT,
|
|
||||||
"Error relaying LM response: can't find client %s, instance %u",
|
|
||||||
proto_str, instance);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
zlog_debug("Found client to relay LM response to client %s instance %u",
|
|
||||||
proto_str, instance);
|
|
||||||
|
|
||||||
/* copy msg into output buffer */
|
|
||||||
dst = obuf;
|
|
||||||
stream_copy(dst, src);
|
|
||||||
|
|
||||||
/* send response back */
|
|
||||||
ret = writen(zserv->sock, dst->data, stream_get_endp(dst));
|
|
||||||
if (ret <= 0) {
|
|
||||||
flog_err(EC_ZEBRA_LM_RELAY_FAILED,
|
|
||||||
"Error relaying LM response to %s instance %u: %s",
|
|
||||||
proto_str, instance, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
zlog_debug("Relayed LM response (%d bytes) to %s instance %u", ret,
|
|
||||||
proto_str, instance);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_zclient_read(struct thread *t)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
zclient->t_read = NULL;
|
|
||||||
|
|
||||||
/* read response and send it back */
|
|
||||||
ret = relay_response_back();
|
|
||||||
|
|
||||||
/* re-arm read */
|
|
||||||
thread_add_read(zclient->master, lm_zclient_read, NULL,
|
|
||||||
zclient->sock, &zclient->t_read);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int reply_error(int cmd, struct zserv *zserv, vrf_id_t vrf_id)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct stream *s;
|
|
||||||
|
|
||||||
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
|
||||||
|
|
||||||
zclient_create_header(s, cmd, vrf_id);
|
|
||||||
|
|
||||||
/* proto */
|
|
||||||
stream_putc(s, zserv->proto);
|
|
||||||
/* instance */
|
|
||||||
stream_putw(s, zserv->instance);
|
|
||||||
/* result */
|
|
||||||
stream_putc(s, 1);
|
|
||||||
|
|
||||||
/* Write packet size. */
|
|
||||||
stream_putw_at(s, 0, stream_get_endp(s));
|
|
||||||
|
|
||||||
ret = writen(zserv->sock, s->data, stream_get_endp(s));
|
|
||||||
|
|
||||||
stream_free(s);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Receive a request to get or release a label chunk and forward it to external
|
|
||||||
* label manager.
|
|
||||||
*
|
|
||||||
* It's called from zserv in case it's not an actual label manager, but just a
|
|
||||||
* proxy.
|
|
||||||
*
|
|
||||||
* @param cmd Type of request (connect, get or release)
|
|
||||||
* @param zserv
|
|
||||||
* @return 0 on success, -1 otherwise
|
|
||||||
*/
|
|
||||||
int zread_relay_label_manager_request(int cmd, struct zserv *zserv,
|
|
||||||
struct stream *msg, vrf_id_t vrf_id)
|
|
||||||
{
|
|
||||||
struct stream *dst;
|
|
||||||
int ret = 0;
|
|
||||||
uint8_t proto;
|
|
||||||
const char *proto_str;
|
|
||||||
unsigned short instance;
|
|
||||||
|
|
||||||
if (zclient->sock < 0) {
|
|
||||||
flog_err(EC_ZEBRA_LM_NO_SOCKET,
|
|
||||||
"Unable to relay LM request: no socket");
|
|
||||||
reply_error(cmd, zserv, vrf_id);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* peek msg to get proto and instance id. This zebra, which acts as
|
|
||||||
* a proxy needs to have such values for each client in order to
|
|
||||||
* relay responses back to it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Get the 'proto' field of incoming msg */
|
|
||||||
proto = stream_getc(msg);
|
|
||||||
|
|
||||||
/* Get the 'instance' field of incoming msg */
|
|
||||||
instance = stream_getw(msg);
|
|
||||||
|
|
||||||
/* stringify proto */
|
|
||||||
proto_str = zebra_route_string(proto);
|
|
||||||
|
|
||||||
/* check & set client proto if unset */
|
|
||||||
if (zserv->proto && zserv->proto != proto) {
|
|
||||||
flog_warn(EC_ZEBRAING_LM_PROTO_MISMATCH,
|
|
||||||
"Client proto(%u) != msg proto(%u)", zserv->proto,
|
|
||||||
proto);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check & set client instance if unset */
|
|
||||||
if (zserv->instance && zserv->instance != instance) {
|
|
||||||
flog_err(EC_ZEBRA_LM_BAD_INSTANCE,
|
|
||||||
"Client instance(%u) != msg instance(%u)",
|
|
||||||
zserv->instance, instance);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* recall proto and instance */
|
|
||||||
zserv->instance = instance;
|
|
||||||
zserv->proto = proto;
|
|
||||||
|
|
||||||
/* in case there's any incoming message enqueued, read and forward it */
|
|
||||||
if (zserv->is_synchronous)
|
|
||||||
while (ret == 0)
|
|
||||||
ret = relay_response_back();
|
|
||||||
|
|
||||||
/* get the msg buffer used toward the 'master' Label Manager */
|
|
||||||
dst = zclient->obuf;
|
|
||||||
|
|
||||||
/* copy the message */
|
|
||||||
stream_copy(dst, msg);
|
|
||||||
|
|
||||||
/* Send request to external label manager */
|
|
||||||
ret = writen(zclient->sock, dst->data, stream_get_endp(dst));
|
|
||||||
if (ret <= 0) {
|
|
||||||
flog_err(EC_ZEBRA_LM_RELAY_FAILED,
|
|
||||||
"Error relaying LM request from %s instance %u: %s",
|
|
||||||
proto_str, instance, strerror(errno));
|
|
||||||
reply_error(cmd, zserv, vrf_id);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
zlog_debug("Relayed LM request (%d bytes) from %s instance %u", ret,
|
|
||||||
proto_str, instance);
|
|
||||||
|
|
||||||
|
|
||||||
/* Release label chunk has no response */
|
|
||||||
if (cmd == ZEBRA_RELEASE_LABEL_CHUNK)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* make sure we listen to the response */
|
|
||||||
if (!zclient->t_read)
|
|
||||||
thread_add_read(zclient->master, lm_zclient_read, NULL,
|
|
||||||
zclient->sock, &zclient->t_read);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_zclient_connect(struct thread *t)
|
|
||||||
{
|
|
||||||
zclient->t_connect = NULL;
|
|
||||||
|
|
||||||
if (zclient->sock >= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (zclient_socket_connect(zclient) < 0) {
|
|
||||||
flog_err(EC_ZEBRA_LM_CLIENT_CONNECTION_FAILED,
|
|
||||||
"Error connecting synchronous zclient!");
|
|
||||||
thread_add_timer(zrouter.master, lm_zclient_connect, zclient,
|
|
||||||
CONNECTION_DELAY, &zclient->t_connect);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make socket non-blocking */
|
|
||||||
(void)set_nonblocking(zclient->sock);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to initialize zclient in case this is not an actual
|
|
||||||
* label manager, but just a proxy to an external one.
|
|
||||||
*
|
|
||||||
* @param lm_zserv_path Path to zserv socket of external label manager
|
|
||||||
*/
|
|
||||||
static void lm_zclient_init(char *lm_zserv_path)
|
|
||||||
{
|
|
||||||
if (lm_zserv_path)
|
|
||||||
frr_zclient_addr(&zclient_addr, &zclient_addr_len,
|
|
||||||
lm_zserv_path);
|
|
||||||
|
|
||||||
/* Set default values. */
|
|
||||||
zclient = zclient_new(zrouter.master, &zclient_options_default);
|
|
||||||
zclient->privs = &zserv_privs;
|
|
||||||
zclient->sock = -1;
|
|
||||||
zclient->t_connect = NULL;
|
|
||||||
lm_zclient_connect(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release label chunks from a client.
|
* Release label chunks from a client.
|
||||||
*
|
*
|
||||||
@ -339,15 +109,16 @@ static void lm_zclient_init(char *lm_zserv_path)
|
|||||||
* @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_label_chunks(struct zserv *client)
|
int release_daemon_label_chunks(uint8_t proto, unsigned short instance)
|
||||||
{
|
{
|
||||||
uint8_t proto = client->proto;
|
|
||||||
uint16_t instance = client->instance;
|
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
struct label_manager_chunk *lmc;
|
struct label_manager_chunk *lmc;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
zlog_debug("%s: Releasing chunks for client proto %s, instance %d",
|
||||||
|
__func__, zebra_route_string(proto), instance);
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
|
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
|
||||||
if (lmc->proto == proto && lmc->instance == instance
|
if (lmc->proto == proto && lmc->instance == instance
|
||||||
&& lmc->keep == 0) {
|
&& lmc->keep == 0) {
|
||||||
@ -363,31 +134,153 @@ int release_daemon_label_chunks(struct zserv *client)
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
int lm_client_disconnect_cb(struct zserv *client)
|
||||||
* Init label manager (or proxy to an external one)
|
|
||||||
*/
|
|
||||||
void label_manager_init(char *lm_zserv_path)
|
|
||||||
{
|
{
|
||||||
/* this is an actual label manager */
|
uint8_t proto = client->proto;
|
||||||
if (!lm_zserv_path) {
|
uint16_t instance = client->instance;
|
||||||
zlog_debug("Initializing internal label manager");
|
|
||||||
lm_is_external = false;
|
|
||||||
lbl_mgr.lc_list = list_new();
|
|
||||||
lbl_mgr.lc_list->del = delete_label_chunk;
|
|
||||||
} else { /* it's acting just as a proxy */
|
|
||||||
zlog_debug("Initializing external label manager at %s",
|
|
||||||
lm_zserv_path);
|
|
||||||
lm_is_external = true;
|
|
||||||
lm_zclient_init(lm_zserv_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
obuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
hook_call(lm_client_disconnect, proto, instance);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
hook_register(zserv_client_close, release_daemon_label_chunks);
|
void lm_hooks_register(void)
|
||||||
|
{
|
||||||
|
hook_register(lm_client_connect, label_manager_connect);
|
||||||
|
hook_register(lm_client_disconnect, label_manager_disconnect);
|
||||||
|
hook_register(lm_get_chunk, label_manager_get_chunk);
|
||||||
|
hook_register(lm_release_chunk, release_label_chunk);
|
||||||
|
}
|
||||||
|
void lm_hooks_unregister(void)
|
||||||
|
{
|
||||||
|
hook_unregister(lm_client_connect, label_manager_connect);
|
||||||
|
hook_unregister(lm_client_disconnect, label_manager_disconnect);
|
||||||
|
hook_unregister(lm_get_chunk, label_manager_get_chunk);
|
||||||
|
hook_unregister(lm_release_chunk, release_label_chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Core function, assigns label cunks
|
* Init label manager (or proxy to an external one)
|
||||||
|
*/
|
||||||
|
void label_manager_init(void)
|
||||||
|
{
|
||||||
|
lbl_mgr.lc_list = list_new();
|
||||||
|
lbl_mgr.lc_list->del = delete_label_chunk;
|
||||||
|
hook_register(zserv_client_close, lm_client_disconnect_cb);
|
||||||
|
|
||||||
|
/* register default hooks for the label manager actions */
|
||||||
|
lm_hooks_register();
|
||||||
|
|
||||||
|
/* notify any external module that we are done */
|
||||||
|
hook_call(lm_cbs_inited);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* alloc and fill a label chunk */
|
||||||
|
struct label_manager_chunk *create_label_chunk(uint8_t proto,
|
||||||
|
unsigned short instance,
|
||||||
|
uint8_t keep, uint32_t start,
|
||||||
|
uint32_t end)
|
||||||
|
{
|
||||||
|
/* alloc chunk, fill it and return it */
|
||||||
|
struct label_manager_chunk *lmc =
|
||||||
|
XCALLOC(MTYPE_LM_CHUNK, sizeof(struct label_manager_chunk));
|
||||||
|
|
||||||
|
lmc->start = start;
|
||||||
|
lmc->end = end;
|
||||||
|
lmc->proto = proto;
|
||||||
|
lmc->instance = instance;
|
||||||
|
lmc->keep = keep;
|
||||||
|
|
||||||
|
return lmc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* attempt to get a specific label chunk */
|
||||||
|
static struct label_manager_chunk *
|
||||||
|
assign_specific_label_chunk(uint8_t proto, unsigned short instance,
|
||||||
|
uint8_t keep, uint32_t size, uint32_t base)
|
||||||
|
{
|
||||||
|
struct label_manager_chunk *lmc;
|
||||||
|
struct listnode *node, *next = NULL;
|
||||||
|
struct listnode *first_node = NULL;
|
||||||
|
struct listnode *last_node = NULL;
|
||||||
|
struct listnode *insert_node = NULL;
|
||||||
|
|
||||||
|
/* precompute last label from base and size */
|
||||||
|
uint32_t end = base + size - 1;
|
||||||
|
|
||||||
|
/* sanities */
|
||||||
|
if ((base < MPLS_LABEL_UNRESERVED_MIN)
|
||||||
|
|| (end > MPLS_LABEL_UNRESERVED_MAX)) {
|
||||||
|
zlog_err("Invalid LM request arguments: base: %u, size: %u",
|
||||||
|
base, size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan the existing chunks to see if the requested range of labels
|
||||||
|
* falls inside any of such chunks */
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
|
||||||
|
|
||||||
|
/* skip chunks for labels < base */
|
||||||
|
if (base > lmc->end)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* requested range is not covered by any existing, free chunk.
|
||||||
|
* Therefore, need to insert a chunk */
|
||||||
|
if ((end < lmc->start) && !first_node) {
|
||||||
|
insert_node = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!first_node)
|
||||||
|
first_node = node;
|
||||||
|
|
||||||
|
/* if chunk is used, cannot honor request */
|
||||||
|
if (lmc->proto != NO_PROTO)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (end < lmc->end) {
|
||||||
|
last_node = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* insert chunk between existing chunks */
|
||||||
|
if (insert_node) {
|
||||||
|
lmc = create_label_chunk(proto, instance, keep, base, end);
|
||||||
|
listnode_add_before(lbl_mgr.lc_list, insert_node, lmc);
|
||||||
|
return lmc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_node) {
|
||||||
|
/* get node past the last one, if there */
|
||||||
|
if (last_node)
|
||||||
|
last_node = listnextnode(last_node);
|
||||||
|
|
||||||
|
/* delete node coming after the above chunk whose labels are
|
||||||
|
* included in the previous one */
|
||||||
|
for (node = first_node; node && (node != last_node);
|
||||||
|
node = next) {
|
||||||
|
next = listnextnode(node);
|
||||||
|
list_delete_node(lbl_mgr.lc_list, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
lmc = create_label_chunk(proto, instance, keep, base, end);
|
||||||
|
if (last_node)
|
||||||
|
listnode_add_before(lbl_mgr.lc_list, last_node, lmc);
|
||||||
|
else
|
||||||
|
listnode_add(lbl_mgr.lc_list, lmc);
|
||||||
|
|
||||||
|
return lmc;
|
||||||
|
} else {
|
||||||
|
/* create a new chunk past all the existing ones and link at
|
||||||
|
* tail */
|
||||||
|
lmc = create_label_chunk(proto, instance, keep, base, end);
|
||||||
|
listnode_add(lbl_mgr.lc_list, lmc);
|
||||||
|
return lmc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core function, assigns label chunks
|
||||||
*
|
*
|
||||||
* It first searches through the list to check if there's one available
|
* It first searches through the list to check if there's one available
|
||||||
* (previously released). Otherwise it creates and assigns a new one
|
* (previously released). Otherwise it creates and assigns a new one
|
||||||
@ -395,15 +288,26 @@ void label_manager_init(char *lm_zserv_path)
|
|||||||
* @param proto Daemon protocol of client, to identify the owner
|
* @param proto Daemon protocol of client, to identify the owner
|
||||||
* @param instance Instance, to identify the owner
|
* @param instance Instance, to identify the owner
|
||||||
* @param keep If set, avoid garbage collection
|
* @param keep If set, avoid garbage collection
|
||||||
* @para size Size of the label chunk
|
* @param size Size of the label chunk
|
||||||
* @return Pointer to the assigned label chunk
|
* @param base Desired starting label of the chunk; if MPLS_LABEL_BASE_ANY it does not apply
|
||||||
|
* @return Pointer to the assigned label chunk, or NULL if the request could not be satisfied
|
||||||
*/
|
*/
|
||||||
struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
||||||
unsigned short instance,
|
unsigned short instance,
|
||||||
uint8_t keep, uint32_t size)
|
uint8_t keep, uint32_t size,
|
||||||
|
uint32_t base)
|
||||||
{
|
{
|
||||||
struct label_manager_chunk *lmc;
|
struct label_manager_chunk *lmc;
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
|
uint32_t prev_end = 0;
|
||||||
|
|
||||||
|
/* handle chunks request with a specific base label */
|
||||||
|
if (base != MPLS_LABEL_BASE_ANY)
|
||||||
|
return assign_specific_label_chunk(proto, instance, keep, size,
|
||||||
|
base);
|
||||||
|
|
||||||
|
/* appease scan-build, who gets confused by the use of macros */
|
||||||
|
assert(lbl_mgr.lc_list);
|
||||||
|
|
||||||
/* first check if there's one available */
|
/* first check if there's one available */
|
||||||
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
|
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
|
||||||
@ -414,35 +318,44 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
|||||||
lmc->keep = keep;
|
lmc->keep = keep;
|
||||||
return lmc;
|
return lmc;
|
||||||
}
|
}
|
||||||
|
/* check if we hadve a "hole" behind us that we can squeeze into
|
||||||
|
*/
|
||||||
|
if ((lmc->start > prev_end)
|
||||||
|
&& (lmc->start - prev_end >= size)) {
|
||||||
|
lmc = create_label_chunk(proto, instance, keep,
|
||||||
|
prev_end + 1, prev_end + size);
|
||||||
|
listnode_add_before(lbl_mgr.lc_list, node, lmc);
|
||||||
|
return lmc;
|
||||||
|
}
|
||||||
|
prev_end = lmc->end;
|
||||||
}
|
}
|
||||||
/* otherwise create a new one */
|
/* otherwise create a new one */
|
||||||
lmc = XCALLOC(MTYPE_LM_CHUNK, sizeof(struct label_manager_chunk));
|
uint32_t start_free;
|
||||||
|
|
||||||
if (list_isempty(lbl_mgr.lc_list))
|
if (list_isempty(lbl_mgr.lc_list))
|
||||||
lmc->start = MPLS_LABEL_UNRESERVED_MIN;
|
start_free = MPLS_LABEL_UNRESERVED_MIN;
|
||||||
else
|
else
|
||||||
lmc->start = ((struct label_manager_chunk *)listgetdata(
|
start_free = ((struct label_manager_chunk *)listgetdata(
|
||||||
listtail(lbl_mgr.lc_list)))
|
listtail(lbl_mgr.lc_list)))
|
||||||
->end
|
->end
|
||||||
+ 1;
|
+ 1;
|
||||||
if (lmc->start > MPLS_LABEL_UNRESERVED_MAX - size + 1) {
|
|
||||||
|
if (start_free > MPLS_LABEL_UNRESERVED_MAX - size + 1) {
|
||||||
flog_err(EC_ZEBRA_LM_EXHAUSTED_LABELS,
|
flog_err(EC_ZEBRA_LM_EXHAUSTED_LABELS,
|
||||||
"Reached max labels. Start: %u, size: %u", lmc->start,
|
"Reached max labels. Start: %u, size: %u", start_free,
|
||||||
size);
|
size);
|
||||||
XFREE(MTYPE_LM_CHUNK, lmc);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
lmc->end = lmc->start + size - 1;
|
|
||||||
lmc->proto = proto;
|
|
||||||
lmc->instance = instance;
|
|
||||||
lmc->keep = keep;
|
|
||||||
listnode_add(lbl_mgr.lc_list, lmc);
|
|
||||||
|
|
||||||
|
/* create chunk and link at tail */
|
||||||
|
lmc = create_label_chunk(proto, instance, keep, start_free,
|
||||||
|
start_free + size - 1);
|
||||||
|
listnode_add(lbl_mgr.lc_list, lmc);
|
||||||
return lmc;
|
return lmc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Core function, release no longer used label cunks
|
* Core function, release no longer used label chunks
|
||||||
*
|
*
|
||||||
* @param proto Daemon protocol of client, to identify the owner
|
* @param proto Daemon protocol of client, to identify the owner
|
||||||
* @param instance Instance, to identify the owner
|
* @param instance Instance, to identify the owner
|
||||||
@ -483,9 +396,59 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* default functions to be called on hooks */
|
||||||
|
static int label_manager_connect(uint8_t proto, uint16_t instance,
|
||||||
|
vrf_id_t vrf_id)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Release previous labels of same protocol and instance.
|
||||||
|
* This is done in case it restarted from an unexpected shutdown.
|
||||||
|
*/
|
||||||
|
release_daemon_label_chunks(proto, instance);
|
||||||
|
return lm_client_connect_response(proto, instance, vrf_id, 0);
|
||||||
|
}
|
||||||
|
static int label_manager_disconnect(uint8_t proto, uint16_t instance)
|
||||||
|
{
|
||||||
|
release_daemon_label_chunks(proto, instance);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static int label_manager_get_chunk(struct label_manager_chunk **lmc,
|
||||||
|
uint8_t proto, uint16_t instance,
|
||||||
|
uint8_t keep, uint32_t size, uint32_t base,
|
||||||
|
vrf_id_t vrf_id)
|
||||||
|
{
|
||||||
|
*lmc = assign_label_chunk(proto, instance, keep, size, base);
|
||||||
|
return lm_get_chunk_response(*lmc, proto, instance, vrf_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Respond to a connect request */
|
||||||
|
int lm_client_connect_response(uint8_t proto, uint16_t instance,
|
||||||
|
vrf_id_t vrf_id, uint8_t result)
|
||||||
|
{
|
||||||
|
struct zserv *client = zserv_find_client(proto, instance);
|
||||||
|
if (!client) {
|
||||||
|
zlog_err("%s: could not find client for daemon %s instance %u",
|
||||||
|
__func__, zebra_route_string(proto), instance);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return zsend_label_manager_connect_response(client, vrf_id, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Respond to a get_chunk request */
|
||||||
|
int lm_get_chunk_response(struct label_manager_chunk *lmc, uint8_t proto,
|
||||||
|
uint16_t instance, vrf_id_t vrf_id)
|
||||||
|
{
|
||||||
|
struct zserv *client = zserv_find_client(proto, instance);
|
||||||
|
if (!client) {
|
||||||
|
zlog_err("%s: could not find client for daemon %s instance %u",
|
||||||
|
__func__, zebra_route_string(proto), instance);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return zsend_assign_label_chunk_response(client, vrf_id, proto,
|
||||||
|
instance, lmc);
|
||||||
|
}
|
||||||
|
|
||||||
void label_manager_close(void)
|
void label_manager_close(void)
|
||||||
{
|
{
|
||||||
list_delete(&lbl_mgr.lc_list);
|
list_delete(&lbl_mgr.lc_list);
|
||||||
stream_free(obuf);
|
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "lib/linklist.h"
|
#include "lib/linklist.h"
|
||||||
#include "lib/thread.h"
|
#include "lib/thread.h"
|
||||||
|
#include "lib/hook.h"
|
||||||
|
|
||||||
#include "zebra/zserv.h"
|
#include "zebra/zserv.h"
|
||||||
|
|
||||||
@ -57,6 +58,54 @@ struct label_manager_chunk {
|
|||||||
uint32_t end; /* Last label of the chunk */
|
uint32_t end; /* Last label of the chunk */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* declare hooks for the basic API, so that it can be specialized or served
|
||||||
|
* externally. Also declare a hook when those functions have been registered,
|
||||||
|
* so that any external module wanting to replace those can react
|
||||||
|
*/
|
||||||
|
|
||||||
|
DECLARE_HOOK(lm_client_connect,
|
||||||
|
(uint8_t proto, uint16_t instance, vrf_id_t vrf_id),
|
||||||
|
(proto, instance, vrf_id));
|
||||||
|
DECLARE_HOOK(lm_client_disconnect, (uint8_t proto, uint16_t instance),
|
||||||
|
(proto, instance));
|
||||||
|
DECLARE_HOOK(lm_get_chunk,
|
||||||
|
(struct label_manager_chunk * *lmc, uint8_t proto,
|
||||||
|
uint16_t instance, uint8_t keep, uint32_t size, uint32_t base,
|
||||||
|
vrf_id_t vrf_id),
|
||||||
|
(lmc, proto, instance, keep, size, base, vrf_id));
|
||||||
|
DECLARE_HOOK(lm_release_chunk,
|
||||||
|
(uint8_t proto, uint16_t instance, uint32_t start, uint32_t end),
|
||||||
|
(proto, instance, start, end));
|
||||||
|
DECLARE_HOOK(lm_cbs_inited, (), ());
|
||||||
|
|
||||||
|
|
||||||
|
/* declare wrappers to be called in zapi_msg.c (as hooks must be called in
|
||||||
|
* source file where they were defined)
|
||||||
|
*/
|
||||||
|
void lm_client_connect_call(uint8_t proto, uint16_t instance, vrf_id_t vrf_id);
|
||||||
|
void lm_get_chunk_call(struct label_manager_chunk **lmc, uint8_t proto,
|
||||||
|
uint16_t instance, uint8_t keep, uint32_t size,
|
||||||
|
uint32_t base, vrf_id_t vrf_id);
|
||||||
|
void lm_release_chunk_call(uint8_t proto, uint16_t instance, uint32_t start,
|
||||||
|
uint32_t end);
|
||||||
|
|
||||||
|
/* API for an external LM to return responses for requests */
|
||||||
|
int lm_client_connect_response(uint8_t proto, uint16_t instance,
|
||||||
|
vrf_id_t vrf_id, uint8_t result);
|
||||||
|
int lm_get_chunk_response(struct label_manager_chunk *lmc, uint8_t proto,
|
||||||
|
uint16_t instance, vrf_id_t vrf_id);
|
||||||
|
|
||||||
|
/* convenience function to allocate an lmc to be consumed by the above API */
|
||||||
|
struct label_manager_chunk *create_label_chunk(uint8_t proto,
|
||||||
|
unsigned short instance,
|
||||||
|
uint8_t keep, uint32_t start,
|
||||||
|
uint32_t end);
|
||||||
|
void delete_label_chunk(void *val);
|
||||||
|
|
||||||
|
/* register/unregister callbacks for hooks */
|
||||||
|
void lm_hooks_register(void);
|
||||||
|
void lm_hooks_unregister(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main label manager struct
|
* Main label manager struct
|
||||||
* Holds a linked list of label chunks.
|
* Holds a linked list of label chunks.
|
||||||
@ -65,17 +114,15 @@ struct label_manager {
|
|||||||
struct list *lc_list;
|
struct list *lc_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool lm_is_external;
|
void label_manager_init(void);
|
||||||
|
|
||||||
int zread_relay_label_manager_request(int cmd, struct zserv *zserv,
|
|
||||||
struct stream *msg, vrf_id_t vrf_id);
|
|
||||||
void label_manager_init(char *lm_zserv_path);
|
|
||||||
struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
||||||
unsigned short instance,
|
unsigned short instance,
|
||||||
uint8_t keep, uint32_t size);
|
uint8_t keep, uint32_t size,
|
||||||
|
uint32_t base);
|
||||||
int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
|
int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
|
||||||
uint32_t end);
|
uint32_t end);
|
||||||
int release_daemon_label_chunks(struct zserv *client);
|
int lm_client_disconnect_cb(struct zserv *client);
|
||||||
|
int release_daemon_label_chunks(uint8_t proto, unsigned short instance);
|
||||||
void label_manager_close(void);
|
void label_manager_close(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
11
zebra/main.c
11
zebra/main.c
@ -92,7 +92,6 @@ struct option longopts[] = {
|
|||||||
{"keep_kernel", no_argument, NULL, 'k'},
|
{"keep_kernel", no_argument, NULL, 'k'},
|
||||||
{"socket", required_argument, NULL, 'z'},
|
{"socket", required_argument, NULL, 'z'},
|
||||||
{"ecmp", required_argument, NULL, 'e'},
|
{"ecmp", required_argument, NULL, 'e'},
|
||||||
{"label_socket", no_argument, NULL, 'l'},
|
|
||||||
{"retain", no_argument, NULL, 'r'},
|
{"retain", no_argument, NULL, 'r'},
|
||||||
{"vrfdefaultname", required_argument, NULL, 'o'},
|
{"vrfdefaultname", required_argument, NULL, 'o'},
|
||||||
{"graceful_restart", required_argument, NULL, 'K'},
|
{"graceful_restart", required_argument, NULL, 'K'},
|
||||||
@ -252,8 +251,6 @@ int main(int argc, char **argv)
|
|||||||
// int batch_mode = 0;
|
// int batch_mode = 0;
|
||||||
char *zserv_path = NULL;
|
char *zserv_path = NULL;
|
||||||
char *vrf_default_name_configured = NULL;
|
char *vrf_default_name_configured = NULL;
|
||||||
/* Socket to external label manager */
|
|
||||||
char *lblmgr_path = NULL;
|
|
||||||
struct sockaddr_storage dummy;
|
struct sockaddr_storage dummy;
|
||||||
socklen_t dummylen;
|
socklen_t dummylen;
|
||||||
#if defined(HANDLE_ZAPI_FUZZING)
|
#if defined(HANDLE_ZAPI_FUZZING)
|
||||||
@ -270,7 +267,7 @@ int main(int argc, char **argv)
|
|||||||
frr_preinit(&zebra_di, argc, argv);
|
frr_preinit(&zebra_di, argc, argv);
|
||||||
|
|
||||||
frr_opt_add(
|
frr_opt_add(
|
||||||
"baz:e:l:o:rK:"
|
"baz:e:o:rK:"
|
||||||
#ifdef HAVE_NETLINK
|
#ifdef HAVE_NETLINK
|
||||||
"s:n"
|
"s:n"
|
||||||
#endif
|
#endif
|
||||||
@ -286,7 +283,6 @@ int main(int argc, char **argv)
|
|||||||
" -a, --allow_delete Allow other processes to delete zebra routes\n"
|
" -a, --allow_delete Allow other processes to delete zebra routes\n"
|
||||||
" -z, --socket Set path of zebra socket\n"
|
" -z, --socket Set path of zebra socket\n"
|
||||||
" -e, --ecmp Specify ECMP to use.\n"
|
" -e, --ecmp Specify ECMP to use.\n"
|
||||||
" -l, --label_socket Socket to external label manager\n"
|
|
||||||
" -r, --retain When program terminates, retain added route by zebra.\n"
|
" -r, --retain When program terminates, retain added route by zebra.\n"
|
||||||
" -o, --vrfdefaultname Set default VRF name.\n"
|
" -o, --vrfdefaultname Set default VRF name.\n"
|
||||||
" -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n"
|
" -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n"
|
||||||
@ -341,9 +337,6 @@ int main(int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'l':
|
|
||||||
lblmgr_path = optarg;
|
|
||||||
break;
|
|
||||||
case 'r':
|
case 'r':
|
||||||
retain_mode = 1;
|
retain_mode = 1;
|
||||||
break;
|
break;
|
||||||
@ -451,7 +444,7 @@ int main(int argc, char **argv)
|
|||||||
zserv_start(zserv_path);
|
zserv_start(zserv_path);
|
||||||
|
|
||||||
/* Init label manager */
|
/* Init label manager */
|
||||||
label_manager_init(lblmgr_path);
|
label_manager_init();
|
||||||
|
|
||||||
/* RNH init */
|
/* RNH init */
|
||||||
zebra_rnh_init();
|
zebra_rnh_init();
|
||||||
|
@ -57,7 +57,6 @@
|
|||||||
#include "zebra/rtadv.h"
|
#include "zebra/rtadv.h"
|
||||||
#include "zebra/zebra_mpls.h"
|
#include "zebra/zebra_mpls.h"
|
||||||
#include "zebra/zebra_mroute.h"
|
#include "zebra/zebra_mroute.h"
|
||||||
#include "zebra/label_manager.h"
|
|
||||||
#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"
|
||||||
@ -928,20 +927,20 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Send response to a get label chunk request to client */
|
/* Send response to a get label chunk request to client */
|
||||||
static int zsend_assign_label_chunk_response(struct zserv *client,
|
int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id,
|
||||||
vrf_id_t vrf_id,
|
uint8_t proto, uint16_t instance,
|
||||||
struct label_manager_chunk *lmc)
|
struct label_manager_chunk *lmc)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
||||||
|
|
||||||
zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id);
|
zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id);
|
||||||
|
/* proto */
|
||||||
|
stream_putc(s, proto);
|
||||||
|
/* instance */
|
||||||
|
stream_putw(s, instance);
|
||||||
|
|
||||||
if (lmc) {
|
if (lmc) {
|
||||||
/* proto */
|
|
||||||
stream_putc(s, lmc->proto);
|
|
||||||
/* instance */
|
|
||||||
stream_putw(s, lmc->instance);
|
|
||||||
/* keep */
|
/* keep */
|
||||||
stream_putc(s, lmc->keep);
|
stream_putc(s, lmc->keep);
|
||||||
/* start and end labels */
|
/* start and end labels */
|
||||||
@ -958,9 +957,8 @@ static int zsend_assign_label_chunk_response(struct zserv *client,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Send response to a label manager connect request to client */
|
/* Send response to a label manager connect request to client */
|
||||||
static int zsend_label_manager_connect_response(struct zserv *client,
|
int zsend_label_manager_connect_response(struct zserv *client, vrf_id_t vrf_id,
|
||||||
vrf_id_t vrf_id,
|
unsigned short result)
|
||||||
unsigned short result)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
||||||
@ -1896,27 +1894,16 @@ static void zread_label_manager_connect(struct zserv *client,
|
|||||||
flog_err(EC_ZEBRA_TM_WRONG_PROTO,
|
flog_err(EC_ZEBRA_TM_WRONG_PROTO,
|
||||||
"client %d has wrong protocol %s", client->sock,
|
"client %d has wrong protocol %s", client->sock,
|
||||||
zebra_route_string(proto));
|
zebra_route_string(proto));
|
||||||
if (client->is_synchronous)
|
zsend_label_manager_connect_response(client, vrf_id, 1);
|
||||||
zsend_label_manager_connect_response(client, vrf_id, 1);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
zlog_notice("client %d with vrf %u instance %u connected as %s",
|
|
||||||
client->sock, vrf_id, instance, zebra_route_string(proto));
|
/* recall proto and instance in this socket */
|
||||||
client->proto = proto;
|
client->proto = proto;
|
||||||
client->instance = instance;
|
client->instance = instance;
|
||||||
|
|
||||||
/*
|
/* call hook for connection using wrapper */
|
||||||
* Release previous labels of same protocol and instance.
|
lm_client_connect_call(proto, instance, vrf_id);
|
||||||
* This is done in case it restarted from an unexpected shutdown.
|
|
||||||
*/
|
|
||||||
release_daemon_label_chunks(client);
|
|
||||||
|
|
||||||
zlog_debug(
|
|
||||||
" Label Manager client connected: sock %d, proto %s, vrf %u instance %u",
|
|
||||||
client->sock, zebra_route_string(proto), vrf_id, instance);
|
|
||||||
/* send response back */
|
|
||||||
if (client->is_synchronous)
|
|
||||||
zsend_label_manager_connect_response(client, vrf_id, 0);
|
|
||||||
|
|
||||||
stream_failure:
|
stream_failure:
|
||||||
return;
|
return;
|
||||||
@ -1927,8 +1914,8 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
|
|||||||
{
|
{
|
||||||
struct stream *s;
|
struct stream *s;
|
||||||
uint8_t keep;
|
uint8_t keep;
|
||||||
uint32_t size;
|
uint32_t size, base;
|
||||||
struct label_manager_chunk *lmc;
|
struct label_manager_chunk *lmc = NULL;
|
||||||
uint8_t proto;
|
uint8_t proto;
|
||||||
unsigned short instance;
|
unsigned short instance;
|
||||||
|
|
||||||
@ -1940,8 +1927,11 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
|
|||||||
STREAM_GETW(s, instance);
|
STREAM_GETW(s, instance);
|
||||||
STREAM_GETC(s, keep);
|
STREAM_GETC(s, keep);
|
||||||
STREAM_GETL(s, size);
|
STREAM_GETL(s, size);
|
||||||
|
STREAM_GETL(s, base);
|
||||||
|
|
||||||
|
/* call hook to get a chunk using wrapper */
|
||||||
|
lm_get_chunk_call(&lmc, proto, instance, keep, size, base, vrf_id);
|
||||||
|
|
||||||
lmc = assign_label_chunk(proto, instance, keep, size);
|
|
||||||
if (!lmc)
|
if (!lmc)
|
||||||
flog_err(
|
flog_err(
|
||||||
EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK,
|
EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK,
|
||||||
@ -1951,8 +1941,6 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
|
|||||||
zlog_debug("Assigned Label Chunk %u - %u to %s instance %u",
|
zlog_debug("Assigned Label Chunk %u - %u to %s instance %u",
|
||||||
lmc->start, lmc->end,
|
lmc->start, lmc->end,
|
||||||
zebra_route_string(proto), instance);
|
zebra_route_string(proto), instance);
|
||||||
/* send response back */
|
|
||||||
zsend_assign_label_chunk_response(client, vrf_id, lmc);
|
|
||||||
|
|
||||||
stream_failure:
|
stream_failure:
|
||||||
return;
|
return;
|
||||||
@ -1974,33 +1962,23 @@ static void zread_release_label_chunk(struct zserv *client, struct stream *msg)
|
|||||||
STREAM_GETL(s, start);
|
STREAM_GETL(s, start);
|
||||||
STREAM_GETL(s, end);
|
STREAM_GETL(s, end);
|
||||||
|
|
||||||
release_label_chunk(proto, instance, start, end);
|
/* call hook to release a chunk using wrapper */
|
||||||
|
lm_release_chunk_call(proto, instance, start, end);
|
||||||
|
|
||||||
stream_failure:
|
stream_failure:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zread_label_manager_request(ZAPI_HANDLER_ARGS)
|
static void zread_label_manager_request(ZAPI_HANDLER_ARGS)
|
||||||
{
|
{
|
||||||
/* to avoid sending other messages like ZERBA_INTERFACE_UP */
|
if (hdr->command == ZEBRA_LABEL_MANAGER_CONNECT
|
||||||
client->is_synchronous = hdr->command ==
|
|| hdr->command == ZEBRA_LABEL_MANAGER_CONNECT_ASYNC)
|
||||||
ZEBRA_LABEL_MANAGER_CONNECT;
|
zread_label_manager_connect(client, msg, zvrf_id(zvrf));
|
||||||
|
|
||||||
/* external label manager */
|
|
||||||
if (lm_is_external)
|
|
||||||
zread_relay_label_manager_request(hdr->command, client, msg,
|
|
||||||
zvrf_id(zvrf));
|
|
||||||
/* this is a label manager */
|
|
||||||
else {
|
else {
|
||||||
if (hdr->command == ZEBRA_LABEL_MANAGER_CONNECT ||
|
if (hdr->command == ZEBRA_GET_LABEL_CHUNK)
|
||||||
hdr->command == ZEBRA_LABEL_MANAGER_CONNECT_ASYNC)
|
zread_get_label_chunk(client, msg, zvrf_id(zvrf));
|
||||||
zread_label_manager_connect(client, msg, zvrf_id(zvrf));
|
else if (hdr->command == ZEBRA_RELEASE_LABEL_CHUNK)
|
||||||
else {
|
zread_release_label_chunk(client, msg);
|
||||||
if (hdr->command == ZEBRA_GET_LABEL_CHUNK)
|
|
||||||
zread_get_label_chunk(client, msg,
|
|
||||||
zvrf_id(zvrf));
|
|
||||||
else if (hdr->command == ZEBRA_RELEASE_LABEL_CHUNK)
|
|
||||||
zread_release_label_chunk(client, msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
#include "zebra/zserv.h"
|
#include "zebra/zserv.h"
|
||||||
#include "zebra/zebra_pbr.h"
|
#include "zebra/zebra_pbr.h"
|
||||||
#include "zebra/zebra_errors.h"
|
#include "zebra/zebra_errors.h"
|
||||||
|
#include "zebra/label_manager.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -90,6 +92,14 @@ extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
|
|||||||
const unsigned int nexthop_num);
|
const unsigned int nexthop_num);
|
||||||
|
|
||||||
extern void zsend_capabilities_all_clients(void);
|
extern void zsend_capabilities_all_clients(void);
|
||||||
|
extern int zsend_assign_label_chunk_response(struct zserv *client,
|
||||||
|
vrf_id_t vrf_id, uint8_t proto,
|
||||||
|
uint16_t instance,
|
||||||
|
struct label_manager_chunk *lmc);
|
||||||
|
extern int zsend_label_manager_connect_response(struct zserv *client,
|
||||||
|
vrf_id_t vrf_id,
|
||||||
|
unsigned short result);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -535,28 +535,6 @@ static int zserv_process_messages(struct thread *thread)
|
|||||||
|
|
||||||
int zserv_send_message(struct zserv *client, struct stream *msg)
|
int zserv_send_message(struct zserv *client, struct stream *msg)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* This is a somewhat poorly named variable added with Zebra's portion
|
|
||||||
* of the label manager. That component does not use the regular
|
|
||||||
* zserv/zapi_msg interface for handling its messages, as the client
|
|
||||||
* itself runs in-process. Instead it uses synchronous writes on the
|
|
||||||
* zserv client's socket directly in the zread* handlers for its
|
|
||||||
* message types. Furthermore, it cannot handle the usual messages
|
|
||||||
* Zebra sends (such as those for interface changes) and so has added
|
|
||||||
* this flag and check here as a hack to suppress all messages that it
|
|
||||||
* does not explicitly know about.
|
|
||||||
*
|
|
||||||
* In any case this needs to be cleaned up at some point.
|
|
||||||
*
|
|
||||||
* See also:
|
|
||||||
* zread_label_manager_request
|
|
||||||
* zsend_label_manager_connect_response
|
|
||||||
* zsend_assign_label_chunk_response
|
|
||||||
* ...
|
|
||||||
*/
|
|
||||||
if (client->is_synchronous)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&client->obuf_mtx);
|
pthread_mutex_lock(&client->obuf_mtx);
|
||||||
{
|
{
|
||||||
stream_fifo_push(client->obuf_fifo, msg);
|
stream_fifo_push(client->obuf_fifo, msg);
|
||||||
@ -710,9 +688,6 @@ static struct zserv *zserv_client_create(int sock)
|
|||||||
}
|
}
|
||||||
client->ridinfo = vrf_bitmap_init();
|
client->ridinfo = vrf_bitmap_init();
|
||||||
|
|
||||||
/* by default, it's not a synchronous client */
|
|
||||||
client->is_synchronous = 0;
|
|
||||||
|
|
||||||
/* Add this client to linked list. */
|
/* Add this client to linked list. */
|
||||||
listnode_add(zrouter.client_list, client);
|
listnode_add(zrouter.client_list, client);
|
||||||
|
|
||||||
|
@ -98,7 +98,6 @@ struct zserv {
|
|||||||
/* client's protocol */
|
/* client's protocol */
|
||||||
uint8_t proto;
|
uint8_t proto;
|
||||||
uint16_t instance;
|
uint16_t instance;
|
||||||
uint8_t is_synchronous;
|
|
||||||
|
|
||||||
/* Statistics */
|
/* Statistics */
|
||||||
uint32_t redist_v4_add_cnt;
|
uint32_t redist_v4_add_cnt;
|
||||||
|
Loading…
Reference in New Issue
Block a user