mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-03 11:01:48 +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 "workqueue.h"
|
||||
#include "zclient.h"
|
||||
#include "mpls.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_labelpool.h"
|
||||
@ -391,7 +392,8 @@ void bgp_lp_get(
|
||||
if (lp_fifo_count(&lp->requests) > lp->pending_count) {
|
||||
if (!zclient || zclient->sock < 0)
|
||||
return;
|
||||
if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE))
|
||||
if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE,
|
||||
MPLS_LABEL_BASE_ANY))
|
||||
lp->pending_count += LP_CHUNK_SIZE;
|
||||
}
|
||||
}
|
||||
@ -552,7 +554,8 @@ void bgp_lp_event_zebra_up(void)
|
||||
return;
|
||||
}
|
||||
|
||||
zclient_send_get_label_chunk(zclient, 0, labels_needed);
|
||||
zclient_send_get_label_chunk(zclient, 0, labels_needed,
|
||||
MPLS_LABEL_BASE_ANY);
|
||||
lp->pending_count = labels_needed;
|
||||
|
||||
/*
|
||||
|
@ -1660,7 +1660,8 @@ lde_get_label_chunk(void)
|
||||
uint32_t start, end;
|
||||
|
||||
debug_labels("getting label chunk (size %u)", CHUNK_SIZE);
|
||||
ret = lm_get_label_chunk(zclient_sync, 0, CHUNK_SIZE, &start, &end);
|
||||
ret = lm_get_label_chunk(zclient_sync, 0, MPLS_LABEL_BASE_ANY,
|
||||
CHUNK_SIZE, &start, &end);
|
||||
if (ret < 0) {
|
||||
log_warnx("Error getting label chunk!");
|
||||
return -1;
|
||||
|
@ -236,6 +236,9 @@ main(int argc, char *argv[])
|
||||
" --ctl_socket Override ctl socket path\n"
|
||||
" -n, --instance Instance id\n");
|
||||
|
||||
/* set default instance (to differentiate ldpd socket from lde one */
|
||||
init.instance = 1;
|
||||
|
||||
while (1) {
|
||||
int opt;
|
||||
|
||||
|
@ -54,6 +54,7 @@ extern "C" {
|
||||
#define MPLS_LABEL_RESERVED_MAX 15
|
||||
#define MPLS_LABEL_UNRESERVED_MIN 16
|
||||
#define MPLS_LABEL_UNRESERVED_MAX 1048575
|
||||
#define MPLS_LABEL_BASE_ANY 0
|
||||
|
||||
/* Default min and max SRGB label range */
|
||||
/* Even if the SRGB allows to manage different Label space between routers,
|
||||
|
@ -1995,10 +1995,11 @@ int lm_label_manager_connect(struct zclient *zclient, int async)
|
||||
* @param zclient Zclient used to connect to label manager (zebra)
|
||||
* @param keep Avoid garbage collection
|
||||
* @param chunk_size Amount of labels requested
|
||||
* @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care
|
||||
* @result 0 on success, -1 otherwise
|
||||
*/
|
||||
int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
uint32_t chunk_size)
|
||||
uint32_t chunk_size, uint32_t base)
|
||||
{
|
||||
struct stream *s;
|
||||
|
||||
@ -2018,6 +2019,7 @@ int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
stream_putw(s, zclient->instance);
|
||||
stream_putc(s, keep);
|
||||
stream_putl(s, chunk_size);
|
||||
stream_putl(s, base);
|
||||
|
||||
/* Put length at the first point of the stream. */
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
@ -2038,7 +2040,7 @@ int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
* @param end To write last assigned chunk label to
|
||||
* @result 0 on success, -1 otherwise
|
||||
*/
|
||||
int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
int lm_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t base,
|
||||
uint32_t chunk_size, uint32_t *start, uint32_t *end)
|
||||
{
|
||||
int ret;
|
||||
@ -2063,6 +2065,8 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
stream_putc(s, keep);
|
||||
/* chunk size */
|
||||
stream_putl(s, chunk_size);
|
||||
/* requested chunk base */
|
||||
stream_putl(s, base);
|
||||
/* Put length at the first point of the stream. */
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
@ -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",
|
||||
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 */
|
||||
response_keep = stream_getc(s);
|
||||
/* start and end labels */
|
||||
|
@ -609,15 +609,13 @@ extern struct interface *zebra_interface_link_params_read(struct stream *s,
|
||||
vrf_id_t vrf_id);
|
||||
extern size_t zebra_interface_link_params_write(struct stream *,
|
||||
struct interface *);
|
||||
extern int zclient_send_get_label_chunk(
|
||||
struct zclient *zclient,
|
||||
uint8_t keep,
|
||||
uint32_t chunk_size);
|
||||
extern int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
uint32_t chunk_size, uint32_t base);
|
||||
|
||||
extern int lm_label_manager_connect(struct zclient *zclient, int async);
|
||||
extern int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
|
||||
uint32_t chunk_size, uint32_t *start,
|
||||
uint32_t *end);
|
||||
uint32_t base, uint32_t chunk_size,
|
||||
uint32_t *start, uint32_t *end);
|
||||
extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
|
||||
uint32_t end);
|
||||
extern int tm_table_manager_connect(struct zclient *zclient);
|
||||
|
@ -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/label_manager.h"
|
||||
#include "zebra/zebra_errors.h"
|
||||
#include "zebra/zapi_msg.h"
|
||||
|
||||
#define CONNECTION_DELAY 5
|
||||
|
||||
struct label_manager lbl_mgr;
|
||||
|
||||
extern struct zebra_privs_t zserv_privs;
|
||||
|
||||
DEFINE_MGROUP(LBL_MGR, "Label Manager");
|
||||
DEFINE_MTYPE_STATIC(LBL_MGR, LM_CHUNK, "Label Manager Chunk");
|
||||
|
||||
/* In case this zebra daemon is not acting as label manager,
|
||||
* it will be a proxy to relay messages to external label manager
|
||||
* This zclient thus is to connect to it
|
||||
/* define hooks for the basic API, so that it can be specialized or served
|
||||
* externally
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
@ -339,15 +109,16 @@ static void lm_zclient_init(char *lm_zserv_path)
|
||||
* @param instance Instance, to identify the owner
|
||||
* @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 label_manager_chunk *lmc;
|
||||
int count = 0;
|
||||
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)) {
|
||||
if (lmc->proto == proto && lmc->instance == instance
|
||||
&& lmc->keep == 0) {
|
||||
@ -363,31 +134,153 @@ int release_daemon_label_chunks(struct zserv *client)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init label manager (or proxy to an external one)
|
||||
*/
|
||||
void label_manager_init(char *lm_zserv_path)
|
||||
int lm_client_disconnect_cb(struct zserv *client)
|
||||
{
|
||||
/* this is an actual label manager */
|
||||
if (!lm_zserv_path) {
|
||||
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);
|
||||
}
|
||||
uint8_t proto = client->proto;
|
||||
uint16_t instance = client->instance;
|
||||
|
||||
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
|
||||
* (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 instance Instance, to identify the owner
|
||||
* @param keep If set, avoid garbage collection
|
||||
* @para size Size of the label chunk
|
||||
* @return Pointer to the assigned label chunk
|
||||
* @param size Size of the label chunk
|
||||
* @param base Desired starting label of the chunk; if MPLS_LABEL_BASE_ANY it does not apply
|
||||
* @return Pointer to the assigned label chunk, or NULL if the request could not be satisfied
|
||||
*/
|
||||
struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
||||
unsigned short instance,
|
||||
uint8_t keep, uint32_t size)
|
||||
uint8_t keep, uint32_t size,
|
||||
uint32_t base)
|
||||
{
|
||||
struct label_manager_chunk *lmc;
|
||||
struct listnode *node;
|
||||
uint32_t prev_end = 0;
|
||||
|
||||
/* handle chunks request with a specific base label */
|
||||
if (base != MPLS_LABEL_BASE_ANY)
|
||||
return assign_specific_label_chunk(proto, instance, keep, size,
|
||||
base);
|
||||
|
||||
/* appease scan-build, who gets confused by the use of macros */
|
||||
assert(lbl_mgr.lc_list);
|
||||
|
||||
/* first check if there's one available */
|
||||
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
|
||||
@ -414,35 +318,44 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
||||
lmc->keep = keep;
|
||||
return lmc;
|
||||
}
|
||||
/* check if we hadve a "hole" behind us that we can squeeze into
|
||||
*/
|
||||
if ((lmc->start > prev_end)
|
||||
&& (lmc->start - prev_end >= size)) {
|
||||
lmc = create_label_chunk(proto, instance, keep,
|
||||
prev_end + 1, prev_end + size);
|
||||
listnode_add_before(lbl_mgr.lc_list, node, lmc);
|
||||
return lmc;
|
||||
}
|
||||
prev_end = lmc->end;
|
||||
}
|
||||
/* otherwise create a new one */
|
||||
lmc = XCALLOC(MTYPE_LM_CHUNK, sizeof(struct label_manager_chunk));
|
||||
uint32_t start_free;
|
||||
|
||||
if (list_isempty(lbl_mgr.lc_list))
|
||||
lmc->start = MPLS_LABEL_UNRESERVED_MIN;
|
||||
start_free = MPLS_LABEL_UNRESERVED_MIN;
|
||||
else
|
||||
lmc->start = ((struct label_manager_chunk *)listgetdata(
|
||||
start_free = ((struct label_manager_chunk *)listgetdata(
|
||||
listtail(lbl_mgr.lc_list)))
|
||||
->end
|
||||
+ 1;
|
||||
if (lmc->start > MPLS_LABEL_UNRESERVED_MAX - size + 1) {
|
||||
|
||||
if (start_free > MPLS_LABEL_UNRESERVED_MAX - size + 1) {
|
||||
flog_err(EC_ZEBRA_LM_EXHAUSTED_LABELS,
|
||||
"Reached max labels. Start: %u, size: %u", lmc->start,
|
||||
"Reached max labels. Start: %u, size: %u", start_free,
|
||||
size);
|
||||
XFREE(MTYPE_LM_CHUNK, lmc);
|
||||
return NULL;
|
||||
}
|
||||
lmc->end = lmc->start + size - 1;
|
||||
lmc->proto = proto;
|
||||
lmc->instance = instance;
|
||||
lmc->keep = keep;
|
||||
listnode_add(lbl_mgr.lc_list, lmc);
|
||||
|
||||
/* create chunk and link at tail */
|
||||
lmc = create_label_chunk(proto, instance, keep, start_free,
|
||||
start_free + size - 1);
|
||||
listnode_add(lbl_mgr.lc_list, lmc);
|
||||
return lmc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core function, release no longer used label cunks
|
||||
* Core function, release no longer used label chunks
|
||||
*
|
||||
* @param proto Daemon protocol of client, to identify the owner
|
||||
* @param instance Instance, to identify the owner
|
||||
@ -483,9 +396,59 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
|
||||
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)
|
||||
{
|
||||
list_delete(&lbl_mgr.lc_list);
|
||||
stream_free(obuf);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include "lib/linklist.h"
|
||||
#include "lib/thread.h"
|
||||
#include "lib/hook.h"
|
||||
|
||||
#include "zebra/zserv.h"
|
||||
|
||||
@ -57,6 +58,54 @@ struct label_manager_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
|
||||
* Holds a linked list of label chunks.
|
||||
@ -65,17 +114,15 @@ struct label_manager {
|
||||
struct list *lc_list;
|
||||
};
|
||||
|
||||
bool lm_is_external;
|
||||
|
||||
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);
|
||||
void label_manager_init(void);
|
||||
struct label_manager_chunk *assign_label_chunk(uint8_t proto,
|
||||
unsigned short instance,
|
||||
uint8_t keep, uint32_t size);
|
||||
uint8_t keep, uint32_t size,
|
||||
uint32_t base);
|
||||
int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
|
||||
uint32_t end);
|
||||
int release_daemon_label_chunks(struct zserv *client);
|
||||
int lm_client_disconnect_cb(struct zserv *client);
|
||||
int release_daemon_label_chunks(uint8_t proto, unsigned short instance);
|
||||
void label_manager_close(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
11
zebra/main.c
11
zebra/main.c
@ -92,7 +92,6 @@ struct option longopts[] = {
|
||||
{"keep_kernel", no_argument, NULL, 'k'},
|
||||
{"socket", required_argument, NULL, 'z'},
|
||||
{"ecmp", required_argument, NULL, 'e'},
|
||||
{"label_socket", no_argument, NULL, 'l'},
|
||||
{"retain", no_argument, NULL, 'r'},
|
||||
{"vrfdefaultname", required_argument, NULL, 'o'},
|
||||
{"graceful_restart", required_argument, NULL, 'K'},
|
||||
@ -252,8 +251,6 @@ int main(int argc, char **argv)
|
||||
// int batch_mode = 0;
|
||||
char *zserv_path = NULL;
|
||||
char *vrf_default_name_configured = NULL;
|
||||
/* Socket to external label manager */
|
||||
char *lblmgr_path = NULL;
|
||||
struct sockaddr_storage dummy;
|
||||
socklen_t dummylen;
|
||||
#if defined(HANDLE_ZAPI_FUZZING)
|
||||
@ -270,7 +267,7 @@ int main(int argc, char **argv)
|
||||
frr_preinit(&zebra_di, argc, argv);
|
||||
|
||||
frr_opt_add(
|
||||
"baz:e:l:o:rK:"
|
||||
"baz:e:o:rK:"
|
||||
#ifdef HAVE_NETLINK
|
||||
"s:n"
|
||||
#endif
|
||||
@ -286,7 +283,6 @@ int main(int argc, char **argv)
|
||||
" -a, --allow_delete Allow other processes to delete zebra routes\n"
|
||||
" -z, --socket Set path of zebra socket\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"
|
||||
" -o, --vrfdefaultname Set default VRF name.\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);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
lblmgr_path = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
retain_mode = 1;
|
||||
break;
|
||||
@ -451,7 +444,7 @@ int main(int argc, char **argv)
|
||||
zserv_start(zserv_path);
|
||||
|
||||
/* Init label manager */
|
||||
label_manager_init(lblmgr_path);
|
||||
label_manager_init();
|
||||
|
||||
/* RNH init */
|
||||
zebra_rnh_init();
|
||||
|
@ -57,7 +57,6 @@
|
||||
#include "zebra/rtadv.h"
|
||||
#include "zebra/zebra_mpls.h"
|
||||
#include "zebra/zebra_mroute.h"
|
||||
#include "zebra/label_manager.h"
|
||||
#include "zebra/zebra_vxlan.h"
|
||||
#include "zebra/rt.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 */
|
||||
static int zsend_assign_label_chunk_response(struct zserv *client,
|
||||
vrf_id_t vrf_id,
|
||||
struct label_manager_chunk *lmc)
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
||||
|
||||
zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id);
|
||||
/* proto */
|
||||
stream_putc(s, proto);
|
||||
/* instance */
|
||||
stream_putw(s, instance);
|
||||
|
||||
if (lmc) {
|
||||
/* proto */
|
||||
stream_putc(s, lmc->proto);
|
||||
/* instance */
|
||||
stream_putw(s, lmc->instance);
|
||||
/* keep */
|
||||
stream_putc(s, lmc->keep);
|
||||
/* 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 */
|
||||
static int zsend_label_manager_connect_response(struct zserv *client,
|
||||
vrf_id_t vrf_id,
|
||||
unsigned short result)
|
||||
int zsend_label_manager_connect_response(struct zserv *client, vrf_id_t vrf_id,
|
||||
unsigned short result)
|
||||
{
|
||||
int ret;
|
||||
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,
|
||||
"client %d has wrong protocol %s", client->sock,
|
||||
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;
|
||||
}
|
||||
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->instance = instance;
|
||||
|
||||
/*
|
||||
* Release previous labels of same protocol and instance.
|
||||
* 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);
|
||||
/* call hook for connection using wrapper */
|
||||
lm_client_connect_call(proto, instance, vrf_id);
|
||||
|
||||
stream_failure:
|
||||
return;
|
||||
@ -1927,8 +1914,8 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
|
||||
{
|
||||
struct stream *s;
|
||||
uint8_t keep;
|
||||
uint32_t size;
|
||||
struct label_manager_chunk *lmc;
|
||||
uint32_t size, base;
|
||||
struct label_manager_chunk *lmc = NULL;
|
||||
uint8_t proto;
|
||||
unsigned short instance;
|
||||
|
||||
@ -1940,8 +1927,11 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
|
||||
STREAM_GETW(s, instance);
|
||||
STREAM_GETC(s, keep);
|
||||
STREAM_GETL(s, size);
|
||||
STREAM_GETL(s, base);
|
||||
|
||||
/* 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)
|
||||
flog_err(
|
||||
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",
|
||||
lmc->start, lmc->end,
|
||||
zebra_route_string(proto), instance);
|
||||
/* send response back */
|
||||
zsend_assign_label_chunk_response(client, vrf_id, lmc);
|
||||
|
||||
stream_failure:
|
||||
return;
|
||||
@ -1974,33 +1962,23 @@ static void zread_release_label_chunk(struct zserv *client, struct stream *msg)
|
||||
STREAM_GETL(s, start);
|
||||
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:
|
||||
return;
|
||||
}
|
||||
|
||||
static void zread_label_manager_request(ZAPI_HANDLER_ARGS)
|
||||
{
|
||||
/* to avoid sending other messages like ZERBA_INTERFACE_UP */
|
||||
client->is_synchronous = hdr->command ==
|
||||
ZEBRA_LABEL_MANAGER_CONNECT;
|
||||
|
||||
/* external label manager */
|
||||
if (lm_is_external)
|
||||
zread_relay_label_manager_request(hdr->command, client, msg,
|
||||
zvrf_id(zvrf));
|
||||
/* this is a label manager */
|
||||
if (hdr->command == ZEBRA_LABEL_MANAGER_CONNECT
|
||||
|| hdr->command == ZEBRA_LABEL_MANAGER_CONNECT_ASYNC)
|
||||
zread_label_manager_connect(client, msg, zvrf_id(zvrf));
|
||||
else {
|
||||
if (hdr->command == ZEBRA_LABEL_MANAGER_CONNECT ||
|
||||
hdr->command == ZEBRA_LABEL_MANAGER_CONNECT_ASYNC)
|
||||
zread_label_manager_connect(client, msg, zvrf_id(zvrf));
|
||||
else {
|
||||
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);
|
||||
}
|
||||
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/zebra_pbr.h"
|
||||
#include "zebra/zebra_errors.h"
|
||||
#include "zebra/label_manager.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -90,6 +92,14 @@ extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
|
||||
const unsigned int nexthop_num);
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -535,28 +535,6 @@ static int zserv_process_messages(struct thread *thread)
|
||||
|
||||
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);
|
||||
{
|
||||
stream_fifo_push(client->obuf_fifo, msg);
|
||||
@ -710,9 +688,6 @@ static struct zserv *zserv_client_create(int sock)
|
||||
}
|
||||
client->ridinfo = vrf_bitmap_init();
|
||||
|
||||
/* by default, it's not a synchronous client */
|
||||
client->is_synchronous = 0;
|
||||
|
||||
/* Add this client to linked list. */
|
||||
listnode_add(zrouter.client_list, client);
|
||||
|
||||
|
@ -98,7 +98,6 @@ struct zserv {
|
||||
/* client's protocol */
|
||||
uint8_t proto;
|
||||
uint16_t instance;
|
||||
uint8_t is_synchronous;
|
||||
|
||||
/* Statistics */
|
||||
uint32_t redist_v4_add_cnt;
|
||||
|
Loading…
Reference in New Issue
Block a user