Merge pull request #4660 from manuhalo/label_manager_fixes

Label manager improvements + refactor
This commit is contained in:
Renato Westphal 2019-07-12 17:09:33 -03:00 committed by GitHub
commit 07a4ddf2b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 404 additions and 1053 deletions

View File

@ -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;
/*

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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 */

View File

@ -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);

View File

@ -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;
}

View File

@ -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
!

View File

@ -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
!

View File

@ -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
!

View File

@ -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
!

View File

@ -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;
}

View File

@ -1,3 +0,0 @@
debug zebra events
debug zebra packet
!

View File

@ -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
!

View File

@ -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
!

View File

@ -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
!

View File

@ -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
!

View File

@ -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
!

View File

@ -1,6 +0,0 @@
!
router ospf
ospf router-id 7.0.0.1
network 77.0.0.0/16 area 0
redistribute connected
!

View File

@ -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
!

View File

@ -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
!

View File

@ -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
!

View File

@ -1,6 +0,0 @@
!
router ospf
ospf router-id 7.0.0.2
network 77.0.0.0/16 area 0
redistribute connected
!

View File

@ -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
!

View File

@ -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))

View File

@ -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);
}

View File

@ -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

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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);

View File

@ -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;