Skip to content

Commit 920abdc

Browse files
- Extended sonic-bmp.yang YANG model to include BMP collector (potentially multiple collectors) configuration parameters: IP, port, stats interval, retry intervals, monitor policies.
- Updated unified/separated mode templates (bgpd.conf.db.j2 and bgpd.main.conf.j2) to use BMP configuration from CONFIG_DB with fallback to default values - Added BMP handler in frrcfgd.py to dynamically convert CONFIG_DB BMP changes to vtysh commands for runtime configuration updates - Supports multiple configurable monitor policies per target: pre-policy, post-policy, loc-rib - Default collector IP is 127.0.0.1 when not specified to maintain backward compatibility Signed-off-by: Kalash Nainwal <kalash@nexthop.ai>
1 parent 7e41e35 commit 920abdc

File tree

9 files changed

+1645
-5
lines changed

9 files changed

+1645
-5
lines changed

dockers/docker-fpm-frr/frr/bgpd/bgpd.main.conf.j2

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,111 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }}
9696
{% if (FEATURE is defined) and
9797
(('frr_bmp' in FEATURE and 'state' in FEATURE['frr_bmp'] and FEATURE['frr_bmp']['state'] == 'enabled') or
9898
('bmp' in FEATURE and 'state' in FEATURE['bmp'] and FEATURE['bmp']['state'] == 'enabled')) %}
99+
{# Global mirror buffer limit #}
99100
!
101+
{% if BMP is defined and 'global' in BMP and 'mirror-buffer-limit' in BMP['global'] %}
102+
bmp mirror buffer-limit {{ BMP['global']['mirror-buffer-limit'] }}
103+
{% else %}
100104
bmp mirror buffer-limit 4294967214
105+
{% endif %}
101106
!
107+
{# Iterate over all BMP targets from BMP_TARGET table #}
108+
{# First, check if any targets are configured #}
109+
{% set has_targets = namespace(value=false) %}
110+
{% if BMP_TARGET is defined and BMP_TARGET|length > 0 %}
111+
{% set has_targets.value = true %}
112+
{% endif %}
113+
{# Backward compatibility: If no targets configured, create default sonic-bmp target #}
114+
{% if not has_targets.value %}
102115
bmp targets sonic-bmp
103116
bmp stats interval 1000
104117
bmp monitor ipv4 unicast pre-policy
105118
bmp monitor ipv6 unicast pre-policy
106119
bmp connect 127.0.0.1 port 5000 min-retry 10000 max-retry 15000
120+
exit
107121
!
108-
!
109-
{% endif %}
122+
{% else %}
123+
{# Process configured targets from BMP_TARGET table #}
124+
{% set afi_safi_map = {
125+
'ipv4_unicast': ('ipv4', 'unicast'),
126+
'ipv6_unicast': ('ipv6', 'unicast'),
127+
'ipv4_multicast': ('ipv4', 'multicast'),
128+
'ipv6_multicast': ('ipv6', 'multicast'),
129+
'l2vpn_evpn': ('l2vpn', 'evpn'),
130+
'ipv4_vpn': ('ipv4', 'vpn'),
131+
'ipv6_vpn': ('ipv6', 'vpn')
132+
} %}
133+
{% for target_key, target_value in BMP_TARGET.items() %}
134+
{% set target_name = target_key if target_key is string else target_key[0] %}
135+
bmp targets {{ target_name }}
136+
{# Check if stats-interval is configured for this target #}
137+
{% if target_value is mapping and 'stats-interval' in target_value %}
138+
bmp stats interval {{ target_value['stats-interval'] }}
139+
{% endif %}
140+
{# Check if mirror is enabled for this target #}
141+
{% if target_value is mapping and 'mirror' in target_value and target_value['mirror'] == 'true' %}
142+
bmp mirror
143+
{% endif %}
144+
{# Collect all AFI/SAFI configs for this target from BMP_TARGET_AFI_SAFI table #}
145+
{% if BMP_TARGET_AFI_SAFI is defined %}
146+
{% for afi_safi_key, afi_safi_value in BMP_TARGET_AFI_SAFI.items() %}
147+
{% set afi_safi_target = none %}
148+
{% set afi_safi_name = none %}
149+
{% if afi_safi_key is string %}
150+
{% set parts = afi_safi_key.split('|') %}
151+
{% if parts|length >= 2 %}
152+
{% set afi_safi_target = parts[0] %}
153+
{% set afi_safi_name = parts[1] %}
154+
{% endif %}
155+
{% elif afi_safi_key is iterable and afi_safi_key|length >= 2 %}
156+
{% set afi_safi_target = afi_safi_key[0] %}
157+
{% set afi_safi_name = afi_safi_key[1] %}
158+
{% endif %}
159+
{% if afi_safi_target == target_name and afi_safi_name is not none and afi_safi_name in afi_safi_map %}
160+
{% set afi, safi = afi_safi_map[afi_safi_name] %}
161+
{% if afi_safi_value.get('adj-rib-in-pre') == 'true' %}
162+
bmp monitor {{ afi }} {{ safi }} pre-policy
163+
{% endif %}
164+
{% if afi_safi_value.get('adj-rib-in-post') == 'true' %}
165+
bmp monitor {{ afi }} {{ safi }} post-policy
166+
{% endif %}
167+
{% if afi_safi_value.get('loc-rib') == 'true' %}
168+
bmp monitor {{ afi }} {{ safi }} loc-rib
169+
{% endif %}
170+
{% endif %}
171+
{% endfor %}
172+
{% endif %}
173+
{# Collect all collectors for this target from BMP_TARGET_COLLECTOR table #}
174+
{% if BMP_TARGET_COLLECTOR is defined %}
175+
{% for collector_key, collector_value in BMP_TARGET_COLLECTOR.items() %}
176+
{% set collector_target = none %}
177+
{% set collector_ip = none %}
178+
{% set collector_port = none %}
179+
{% if collector_key is string %}
180+
{% set parts = collector_key.split('|') %}
181+
{% if parts|length >= 3 %}
182+
{% set collector_target = parts[0] %}
183+
{% set collector_ip = parts[1] %}
184+
{% set collector_port = parts[2] %}
185+
{% endif %}
186+
{% elif collector_key is iterable and collector_key|length >= 3 %}
187+
{% set collector_target = collector_key[0] %}
188+
{% set collector_ip = collector_key[1] %}
189+
{% set collector_port = collector_key[2] %}
190+
{% endif %}
191+
{% if collector_target == target_name and collector_ip is not none and collector_port is not none %}
192+
{% set min_retry = collector_value.get('min-retry', '30000') %}
193+
{% set max_retry = collector_value.get('max-retry', '720000') %}
194+
bmp connect {{ collector_ip }} port {{ collector_port }} min-retry {{ min_retry }} max-retry {{ max_retry }}
195+
{% endif %}
196+
{% endfor %}
197+
{% endif %}
198+
exit
199+
!
200+
{% endfor %}
201+
{% endif %}{# end else (has_targets) #}
202+
!
203+
{% endif %}{# end if FEATURE bmp enabled #}
110204
{# set router-id #}
111205
{% if DEVICE_METADATA['localhost']['sub_role'] == 'BackEnd' or voq_chassis is defined or DEVICE_METADATA['localhost']['switch_type'] == 'chassis-packet' %}
112206
{% if 'bgp_router_id' in DEVICE_METADATA['localhost'] %}

src/sonic-config-engine/tests/sample_output/py3/bgpd_frr_bmp.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ router bgp 65100
6161
bmp monitor ipv4 unicast pre-policy
6262
bmp monitor ipv6 unicast pre-policy
6363
bmp connect 127.0.0.1 port 5000 min-retry 10000 max-retry 15000
64+
exit
6465
!
6566
!
6667
bgp router-id 10.1.0.32
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
!
2+
! template: bgpd/bgpd.conf.j2
3+
!
4+
!
5+
! =========== Managed by sonic-cfggen DO NOT edit manually! ====================
6+
! generated by templates/quagga/bgpd.conf.j2 with config DB data
7+
! file: bgpd.conf
8+
!
9+
!
10+
! template: common/daemons.common.conf.j2
11+
!
12+
hostname switch-t0
13+
password zebra
14+
enable password zebra
15+
!
16+
log syslog informational
17+
log facility local4
18+
!
19+
! end of template: common/daemons.common.conf.j2!
20+
agentx
21+
!
22+
!
23+
!
24+
! template: bgpd/bgpd.main.conf.j2
25+
!
26+
! bgp multiple-instance
27+
!
28+
! BGP configuration
29+
!
30+
! TSA configuration
31+
!
32+
ip prefix-list PL_LoopbackV4 permit 10.1.0.32/32
33+
!
34+
ipv6 prefix-list PL_LoopbackV6 permit fc00:1::/64
35+
!
36+
ip prefix-list LOCAL_VLAN_IPV4_PREFIX seq 5 permit 192.168.0.0/27
37+
!
38+
ip prefix-list LOCAL_VLAN_IPV4_PREFIX seq 10 permit 192.168.200.0/27
39+
!
40+
!
41+
!
42+
router bgp 65100
43+
!
44+
bgp log-neighbor-changes
45+
bgp suppress-fib-pending
46+
no bgp default ipv4-unicast
47+
no bgp ebgp-requires-policy
48+
!
49+
bgp bestpath as-path multipath-relax
50+
!
51+
bgp graceful-restart restart-time 240
52+
bgp graceful-restart
53+
bgp graceful-restart preserve-fw-state
54+
bgp graceful-restart select-defer-time 45
55+
!
56+
!
57+
bmp mirror buffer-limit 1000000000
58+
!
59+
bmp targets production
60+
bmp stats interval 2000
61+
bmp monitor ipv4 unicast pre-policy
62+
bmp connect 192.168.1.100 port 5000 min-retry 30000 max-retry 720000
63+
exit
64+
!
65+
bmp targets troubleshooting
66+
bmp stats interval 500
67+
bmp mirror
68+
bmp monitor ipv4 unicast pre-policy
69+
bmp monitor ipv4 unicast post-policy
70+
bmp monitor l2vpn evpn loc-rib
71+
bmp connect 10.0.0.1 port 6000 min-retry 20000 max-retry 600000
72+
exit
73+
!
74+
!
75+
bgp router-id 10.1.0.32
76+
!
77+
network 10.1.0.32/32
78+
!
79+
address-family ipv6
80+
network fc00:1::32/64
81+
exit-address-family
82+
!
83+
network 192.168.0.1/27
84+
network 192.168.200.1/27
85+
!
86+
!
87+
!
88+
address-family ipv4
89+
maximum-paths 514
90+
exit-address-family
91+
address-family ipv6
92+
maximum-paths 514
93+
exit-address-family
94+
!
95+
! end of template: bgpd/bgpd.main.conf.j2
96+
!!
97+
! end of template: bgpd/bgpd.conf.j2
98+
!
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
!
2+
! template: bgpd/bgpd.conf.j2
3+
!
4+
!
5+
! =========== Managed by sonic-cfggen DO NOT edit manually! ====================
6+
! generated by templates/quagga/bgpd.conf.j2 with config DB data
7+
! file: bgpd.conf
8+
!
9+
!
10+
! template: common/daemons.common.conf.j2
11+
!
12+
hostname switch-t0
13+
password zebra
14+
enable password zebra
15+
!
16+
log syslog informational
17+
log facility local4
18+
!
19+
! end of template: common/daemons.common.conf.j2!
20+
agentx
21+
!
22+
!
23+
!
24+
! template: bgpd/bgpd.main.conf.j2
25+
!
26+
! bgp multiple-instance
27+
!
28+
! BGP configuration
29+
!
30+
! TSA configuration
31+
!
32+
ip prefix-list PL_LoopbackV4 permit 10.1.0.32/32
33+
!
34+
ipv6 prefix-list PL_LoopbackV6 permit fc00:1::/64
35+
!
36+
ip prefix-list LOCAL_VLAN_IPV4_PREFIX seq 5 permit 192.168.0.0/27
37+
!
38+
ip prefix-list LOCAL_VLAN_IPV4_PREFIX seq 10 permit 192.168.200.0/27
39+
!
40+
!
41+
!
42+
router bgp 65100
43+
!
44+
bgp log-neighbor-changes
45+
bgp suppress-fib-pending
46+
no bgp default ipv4-unicast
47+
no bgp ebgp-requires-policy
48+
!
49+
bgp bestpath as-path multipath-relax
50+
!
51+
bgp graceful-restart restart-time 240
52+
bgp graceful-restart
53+
bgp graceful-restart preserve-fw-state
54+
bgp graceful-restart select-defer-time 45
55+
!
56+
!
57+
bmp mirror buffer-limit 4294967214
58+
!
59+
bmp targets production
60+
bmp stats interval 5000
61+
bmp mirror
62+
bmp monitor ipv4 unicast pre-policy
63+
bmp monitor ipv6 unicast post-policy
64+
bmp connect 192.168.1.100 port 5000 min-retry 30000 max-retry 720000
65+
exit
66+
!
67+
!
68+
bgp router-id 10.1.0.32
69+
!
70+
network 10.1.0.32/32
71+
!
72+
address-family ipv6
73+
network fc00:1::32/64
74+
exit-address-family
75+
!
76+
network 192.168.0.1/27
77+
network 192.168.200.1/27
78+
!
79+
!
80+
!
81+
address-family ipv4
82+
maximum-paths 514
83+
exit-address-family
84+
address-family ipv6
85+
maximum-paths 514
86+
exit-address-family
87+
!
88+
! end of template: bgpd/bgpd.main.conf.j2
89+
!!
90+
! end of template: bgpd/bgpd.conf.j2
91+
!

src/sonic-config-engine/tests/test_frr.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,42 @@ def test_zebra_frr_dualtor(self):
8181

8282
def test_bgpd_frr_bmp(self):
8383
extra_data = {"FEATURE": {"frr_bmp": {"state": "enabled"}}}
84-
self.assertTrue(*self.run_case('bgpd/bgpd.conf.j2', 'bgpd_frr_bmp.conf', extra_data=extra_data))
84+
self.assertTrue(*self.run_case('bgpd/bgpd.conf.j2', 'bgpd_frr_bmp.conf', extra_data=extra_data))
85+
86+
def test_bgpd_frr_bmp_single_target(self):
87+
extra_data = {
88+
"FEATURE": {"frr_bmp": {"state": "enabled"}},
89+
"BMP_TARGET": {
90+
"production": {"mirror": "true", "stats-interval": "5000"}
91+
},
92+
"BMP_TARGET_COLLECTOR": {
93+
"production|192.168.1.100|5000": {"min-retry": "30000", "max-retry": "720000"}
94+
},
95+
"BMP_TARGET_AFI_SAFI": {
96+
"production|ipv4_unicast": {"adj-rib-in-pre": "true", "adj-rib-in-post": "false", "loc-rib": "false"},
97+
"production|ipv6_unicast": {"adj-rib-in-pre": "false", "adj-rib-in-post": "true", "loc-rib": "false"}
98+
}
99+
}
100+
self.assertTrue(*self.run_case('bgpd/bgpd.conf.j2', 'bgpd_frr_bmp_single_target.conf', extra_data=extra_data))
101+
102+
def test_bgpd_frr_bmp_multiple_targets(self):
103+
extra_data = {
104+
"FEATURE": {"frr_bmp": {"state": "enabled"}},
105+
"BMP": {
106+
"global": {"mirror-buffer-limit": "1000000000"}
107+
},
108+
"BMP_TARGET": {
109+
"production": {"mirror": "false", "stats-interval": "2000"},
110+
"troubleshooting": {"mirror": "true", "stats-interval": "500"}
111+
},
112+
"BMP_TARGET_COLLECTOR": {
113+
"production|192.168.1.100|5000": {"min-retry": "30000", "max-retry": "720000"},
114+
"troubleshooting|10.0.0.1|6000": {"min-retry": "20000", "max-retry": "600000"}
115+
},
116+
"BMP_TARGET_AFI_SAFI": {
117+
"production|ipv4_unicast": {"adj-rib-in-pre": "true", "adj-rib-in-post": "false", "loc-rib": "false"},
118+
"troubleshooting|ipv4_unicast": {"adj-rib-in-pre": "true", "adj-rib-in-post": "true", "loc-rib": "false"},
119+
"troubleshooting|l2vpn_evpn": {"adj-rib-in-pre": "false", "adj-rib-in-post": "false", "loc-rib": "true"}
120+
}
121+
}
122+
self.assertTrue(*self.run_case('bgpd/bgpd.conf.j2', 'bgpd_frr_bmp_multiple_targets.conf', extra_data=extra_data))

0 commit comments

Comments
 (0)