Merge pull request #18417 from AndriiFullroot/VyOS_T7226

ldpd: Option for disabled LDP hello message during TCP
This commit is contained in:
Russ White 2025-04-29 11:11:35 -04:00 committed by GitHub
commit a710f4bdb7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 422 additions and 2 deletions

View file

@ -141,6 +141,19 @@ LDP Configuration
If GTSM is enabled, multi-hop neighbors should have either GTSM disabled
individually or configured with an appropriate ttl-security hops distance.
.. clicmd:: disable-establish-hello
Located under the MPLS address-family interface node. By default,
the ldpd service sends additional LDP multicast hello messages on TCP
session establishment. This should speed up the connection time, so
the "passive" service would receive the "hello" earlier and would "accept"
TCP without waiting for the UDP message on interval. This behaviour can
produce massive traffic with multicast packets if there are a lot of ldpd
services in one local network, essentially each "addition hello" may trigger
attempt for connection and sending "additional hello" from other ldpd
services. This option allows to disable that behaviour. LDP hello multicast
messages would be sent only by interval.
.. clicmd:: neighbor A.B.C.D password PASSWORD
The following command located under MPLS router node configures the router

View file

@ -33,6 +33,7 @@ RUN apt update && apt upgrade -y && \
screen \
texinfo \
tmux \
iptables \
&& \
# Protobuf build requirements
apt-get install -y \

View file

@ -63,11 +63,13 @@ if_new(const char *name)
iface->ipv4.af = AF_INET;
iface->ipv4.iface = iface;
iface->ipv4.enabled = 0;
iface->ipv4.disable_establish_hello = 0;
/* ipv6 */
iface->ipv6.af = AF_INET6;
iface->ipv6.iface = iface;
iface->ipv6.enabled = 0;
iface->ipv6.disable_establish_hello = 0;
return (iface);
}

View file

@ -24,6 +24,7 @@ int ldp_vty_allow_broken_lsp(struct vty *, const char *);
int ldp_vty_address_family (struct vty *, const char *, const char *);
int ldp_vty_disc_holdtime(struct vty *, const char *, enum hello_type, long);
int ldp_vty_disc_interval(struct vty *, const char *, enum hello_type, long);
int ldp_vty_disable_establish_hello(struct vty *, const char *);
int ldp_vty_targeted_hello_accept(struct vty *, const char *, const char *);
int ldp_vty_nbr_session_holdtime(struct vty *, const char *, struct in_addr, long);
int ldp_vty_af_session_holdtime(struct vty *, const char *, long);

View file

@ -122,6 +122,15 @@ DEFPY (ldp_discovery_link_interval,
return (ldp_vty_disc_interval(vty, no, HELLO_LINK, interval));
}
DEFPY (ldp_disable_establish_hello,
ldp_disable_establish_hello_cmd,
"[no] disable-establish-hello",
NO_STR
"Disable sending additional LDP hello message on establishing LDP tcp connection\n")
{
return ldp_vty_disable_establish_hello(vty, no);
}
DEFPY (ldp_discovery_targeted_interval,
ldp_discovery_targeted_interval_cmd,
"[no] discovery targeted-hello interval (1-65535)$interval",
@ -866,9 +875,11 @@ ldp_vty_init (void)
install_element(LDP_IPV4_IFACE_NODE, &ldp_discovery_link_holdtime_cmd);
install_element(LDP_IPV4_IFACE_NODE, &ldp_discovery_link_interval_cmd);
install_element(LDP_IPV4_IFACE_NODE, &ldp_disable_establish_hello_cmd);
install_element(LDP_IPV6_IFACE_NODE, &ldp_discovery_link_holdtime_cmd);
install_element(LDP_IPV6_IFACE_NODE, &ldp_discovery_link_interval_cmd);
install_element(LDP_IPV6_IFACE_NODE, &ldp_disable_establish_hello_cmd);
install_element(LDP_L2VPN_NODE, &ldp_bridge_cmd);
install_element(LDP_L2VPN_NODE, &ldp_mtu_cmd);

View file

@ -119,6 +119,8 @@ ldp_af_iface_config_write(struct vty *vty, int af)
ia->hello_interval != 0)
vty_out (vty, " discovery hello interval %u\n",
ia->hello_interval);
if (ia->disable_establish_hello)
vty_out (vty, " disable-establish-hello\n");
vty_out (vty, " exit\n");
}
@ -632,6 +634,36 @@ ldp_vty_disc_interval(struct vty *vty, const char *negate,
return (CMD_SUCCESS);
}
int
ldp_vty_disable_establish_hello(struct vty *vty,
const char *negate)
{
struct iface *iface;
struct iface_af *ia;
int af;
switch (vty->node) {
case LDP_IPV4_IFACE_NODE:
case LDP_IPV6_IFACE_NODE:
af = ldp_vty_get_af(vty);
iface = VTY_GET_CONTEXT(iface);
VTY_CHECK_CONTEXT(iface);
ia = iface_af_get(iface, af);
if (negate)
ia->disable_establish_hello = 0;
else
ia->disable_establish_hello = 1;
ldp_config_apply(vty, vty_conf);
break;
default:
fatalx("ldp_vty_disable_establish_hello: unexpected node");
}
return (CMD_SUCCESS);
}
int
ldp_vty_targeted_hello_accept(struct vty *vty, const char *negate,
const char *acl_from_str)

View file

@ -1603,6 +1603,7 @@ merge_iface_af(struct iface_af *ia, struct iface_af *xi)
}
ia->hello_holdtime = xi->hello_holdtime;
ia->hello_interval = xi->hello_interval;
ia->disable_establish_hello = xi->disable_establish_hello;
}
static void

View file

@ -332,6 +332,7 @@ struct iface_af {
struct event *hello_timer;
uint16_t hello_holdtime;
uint16_t hello_interval;
int disable_establish_hello;
};
struct iface_ldp_sync {

View file

@ -630,8 +630,9 @@ nbr_establish_connection(struct nbr *nbr)
* an adjacency as well.
*/
RB_FOREACH(adj, nbr_adj_head, &nbr->adj_tree)
send_hello(adj->source.type, adj->source.link.ia,
adj->source.target);
if (!(adj->source.type == HELLO_LINK && adj->source.link.ia->disable_establish_hello))
send_hello(adj->source.type, adj->source.link.ia,
adj->source.target);
if (connect(nbr->fd, &remote_su.sa, sockaddr_len(&remote_su.sa)) == -1) {
if (errno == EINPROGRESS) {

View file

@ -0,0 +1,21 @@
hostname r1
log file ldpd.log
!
! debug mpls ldp zebra
! debug mpls ldp event
! debug mpls ldp errors
! debug mpls ldp messages recv
! debug mpls ldp messages sent
! debug mpls ldp discovery hello recv
! debug mpls ldp discovery hello sent
!
mpls ldp
router-id 1.1.1.1
!
address-family ipv4
discovery transport-address 1.1.1.1
!
!
!
line vty
!

View file

@ -0,0 +1,17 @@
log file zebra.log
!
hostname r1
!
interface lo
ip address 1.1.1.1/32
!
interface r1-eth0
description to sw0
ip address 10.0.1.1/24
no link-detect
!
ip forwarding
!
!
line vty
!

View file

@ -0,0 +1,21 @@
hostname r2
log file ldpd.log
!
! debug mpls ldp zebra
! debug mpls ldp event
! debug mpls ldp errors
! debug mpls ldp messages recv
! debug mpls ldp messages sent
! debug mpls ldp discovery hello recv
! debug mpls ldp discovery hello sent
!
mpls ldp
router-id 2.2.2.2
!
address-family ipv4
discovery transport-address 2.2.2.2
!
!
!
line vty
!

View file

@ -0,0 +1,17 @@
log file zebra.log
!
hostname r2
!
interface lo
ip address 2.2.2.2/32
!
interface r2-eth0
description to sw0
ip address 10.0.1.2/24
no link-detect
!
ip forwarding
!
!
line vty
!

View file

@ -0,0 +1,21 @@
hostname r3
log file ldpd.log
!
! debug mpls ldp zebra
! debug mpls ldp event
! debug mpls ldp errors
! debug mpls ldp messages recv
! debug mpls ldp messages sent
! debug mpls ldp discovery hello recv
! debug mpls ldp discovery hello sent
!
mpls ldp
router-id 3.3.3.3
!
address-family ipv4
discovery transport-address 3.3.3.3
!
!
!
line vty
!

View file

@ -0,0 +1,17 @@
log file zebra.log
!
hostname r3
!
interface lo
ip address 3.3.3.3/32
!
interface r3-eth0
description to sw0
ip address 10.0.1.3/24
no link-detect
!
ip forwarding
!
!
line vty
!

View file

@ -0,0 +1,51 @@
## 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 - LDP-ESTABLISH-HELLO 1";
# Routers
r1 [
shape=doubleoctagon,
label="1.1.1.1",
fillcolor="#f08080",
style=filled,
];
r2 [
shape=doubleoctagon
label="2.2.2.2",
fillcolor="#f08080",
style=filled,
];
r3 [
shape=doubleoctagon
label="3.3.3.3",
fillcolor="#f08080",
style=filled,
];
# Switches
sw0 [
shape=oval,
label="10.0.1.0/24",
fillcolor="#d0e0d0",
style=filled,
];
# Connections
r1 -- sw0 [label="r1-eth0"];
r2 -- sw0 [label="r2-eth0"];
r3 -- sw0 [label="r3-eth0"];
}

View file

@ -0,0 +1,192 @@
#!/usr/bin/env python
# SPDX-License-Identifier: ISC
#
# test_establish_hello_topo1.py
#
# Copyright (c) 2025 by VyOS Networks
# Andrii Melnychenko (a.melnychenko@vyos.io)
#
r"""
test_establish_hello_topo1.py: Simple FRR LDP Test
+-------------+
| r1 |
| 1.1.1.1 |
+-------------+
|
| .1 r1-eth0
|
+---------+ ~~~~~~~~~~~~~
| r2 | .2 r2-eth0 ~~ sw0 ~~
| 2.2.2.2 | ------------- ~~ 10.0.1.0/24 ~~
+---------+ ~~~~~~~~~~~~~
|
| .3 r3-eth0
|
+-------------+
| r3 |
| 3.3.3.3 |
+-------------+
"""
import os
import re
import sys
import pytest
from time import sleep
from lib.topogen import Topogen, get_topogen
fatal_error = ""
pytestmark = [pytest.mark.ldpd]
def build_topo(tgen):
# Setup Routers
for router in ["r1", "r2", "r3"]:
tgen.add_router(router)
# Switch
switch = tgen.add_switch("sw0")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r3"])
def setup_module(module):
thisDir = os.path.dirname(os.path.realpath(__file__))
tgen = Topogen(build_topo, module.__name__)
tgen.start_topology()
net = tgen.net
# Starting Routers
for router in ["r1", "r2", "r3"]:
net[router].loadConf("zebra", "%s/%s/zebra.conf" % (thisDir, router))
net[router].loadConf("ldpd", "%s/%s/ldpd.conf" % (thisDir, router))
tgen.gears[router].start()
# For debugging after starting FRR daemons, uncomment the next line
# tgen.mininet_cli()
def teardown_module(module):
tgen = get_topogen()
tgen.stop_topology()
def test_default_behaviour():
global fatal_error
# Skip if previous fatal error condition is raised
if fatal_error != "":
pytest.skip(fatal_error)
tgen = get_topogen()
# Setup counters
tgen.gears["r3"].run("""
iptables -t filter -A INPUT -s 10.0.1.1 -p udp --dport 646 -j ACCEPT
iptables -t filter -A INPUT -s 10.0.1.2 -p udp --dport 646 -j ACCEPT
iptables -t filter -A OUTPUT -s 10.0.1.3 -p udp --dport 646 -j ACCEPT
""")
# Setup the LDP service
for router in ["r3", "r2", "r1"]:
tgen.gears[router].vtysh_multicmd([
"configure terminal",
"mpls ldp",
"address-family ipv4",
f"interface {router}-eth0",
"end"])
sleep(7)
# Get values from counters
output = tgen.gears["r3"].run("iptables -t filter -L -v -n")
# Disable the LDP service
for router in ["r3", "r2", "r1"]:
tgen.gears[router].vtysh_multicmd([
"configure terminal",
"mpls ldp",
"address-family ipv4",
f"no interface {router}-eth0",
"end"])
# Remove counter
tgen.gears["r3"].run("iptables -t filter -F")
pattern = r"\n\s+(\d+)"
matches = re.findall(pattern, output)
# Each router should send at least 2 packets of LDP hello,
# one at the start and one after the "interval"(default 5 sec)
# So, router 10.0.1.1(1.1.1.1) should send only 2 packets
# Router 10.0.1.2(2.2.2.2) sent 2 packets plus 2 packets for each attempt to connect to the 1.1.1.1 - in total 4
# Router 10.0.1.3(3.3.3.3) sent 2 packets plus 2 packets to the 1.1.1.1 and 4 packets to the 2.2.2.2 - in total 8
assert matches == ['2', '4', '8'], "Wrong count of the LDP hello messages"
def test_disable_establish_hello():
global fatal_error
# Skip if previous fatal error condition is raised
if fatal_error != "":
pytest.skip(fatal_error)
tgen = get_topogen()
# Setup counters
tgen.gears["r3"].run("""
iptables -t filter -A INPUT -s 10.0.1.1 -p udp --dport 646 -j ACCEPT
iptables -t filter -A INPUT -s 10.0.1.2 -p udp --dport 646 -j ACCEPT
iptables -t filter -A OUTPUT -s 10.0.1.3 -p udp --dport 646 -j ACCEPT
""")
# Setup the LDP service with disable-establish-hello option
for router in ["r3", "r2", "r1"]:
tgen.gears[router].vtysh_multicmd([
"configure terminal",
"mpls ldp",
"address-family ipv4",
f"interface {router}-eth0",
"disable-establish-hello",
"end"])
sleep(7)
# Get values from counters
output = tgen.gears["r3"].run("iptables -t filter -L -v -n")
# Disable the LDP service
for router in ["r3", "r2", "r1"]:
tgen.gears[router].vtysh_multicmd([
"configure terminal",
"mpls ldp",
"address-family ipv4",
f"no interface {router}-eth0",
"end"])
# Remove counter
tgen.gears["r3"].run("iptables -t filter -F")
pattern = r"\n\s+(\d+)"
matches = re.findall(pattern, output)
# With disabled sending LDP hello message on attempt to establish TCP connection
# Each router should only send 2 packets, at start and after 5 seconds(default interval)
assert matches == ['2', '2', '2'], "Wrong count of the LDP hello messages"
if __name__ == "__main__":
# To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
# retval = pytest.main(["-s", "--tb=no"])
retval = pytest.main(["-s"])
sys.exit(retval)