Skip to content

Commit 8601709

Browse files
authored
[bgpcfgd] to support removal part of configuration of bgp allowed prefix list (#10165)
* fix allow list issue Signed-off-by: stormliang <[email protected]> * add the ipaddress in the install list * add unit test Co-authored-by: Ubuntu <azureuser@SONIC-SH-STORM-02.5pu3m0fajw1edcfltykk1gauxa.gx.internal.cloudapp.net> Why I did it Failed to remove part of configuration of bgp allowed prefix list. The details in #10141 How I did it There are two issues: In FRR, ipv6 default route is ::/0, but in the configuration, it is 0::/0, string comparison would be false, but why ipv4 failed to remove the allowed prefix list, ipv6 works? Looks into next one for the answer. The current managers_allow_list doesn’t support removal part of the prefix list. But why IPv6 works in 1? It is because the bug for the IPv6 default route comparison, it would do the update no matter what is the operation (the code will compare the prefix list in the FRR and configuration db, if all configurations in db are presented in FRR, it do nothing, otherwise it will update the prefix list based on the configuration from db). How to verify it Follow the step in #10141
1 parent 0179844 commit 8601709

File tree

3 files changed

+153
-52
lines changed

3 files changed

+153
-52
lines changed

src/sonic-bgpcfgd/bgpcfgd/managers_allow_list.py

+37-12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Implementation of "allow-list" feature
33
"""
44
import re
5+
import ipaddress
56

67
from .log import log_debug, log_info, log_err, log_warn
78
from .template import TemplateFabric
@@ -19,6 +20,7 @@ class BGPAllowListMgr(Manager):
1920
ROUTE_MAP_ENTRY_WITH_COMMUNITY_END = 29990
2021
ROUTE_MAP_ENTRY_WITHOUT_COMMUNITY_START = 30000
2122
ROUTE_MAP_ENTRY_WITHOUT_COMMUNITY_END = 65530
23+
PREFIX_LIST_POS = 1 # the position of the ip prefix in the permit string.
2224

2325
V4 = "v4" # constant for af enum: V4
2426
V6 = "v6" # constant for af enum: V6
@@ -228,6 +230,12 @@ def __update_prefix_list(self, af, pl_name, allow_list):
228230
constant_list = self.__get_constant_list(af)
229231
allow_list = self.__to_prefix_list(af, allow_list)
230232
log_debug("BGPAllowListMgr::__update_prefix_list. af='%s' prefix-list name=%s" % (af, pl_name))
233+
'''
234+
Need to check exist and equality of the allowed prefix list.
235+
A. If exist and equal, no operation needed.
236+
B. If exist but not equal, first delete then add prefix based on the data from condig db and constants.
237+
C. If non-exist, directly add prefix based on the data from condig db and constants.
238+
'''
231239
exist, correct = self.__is_prefix_list_valid(af, pl_name, allow_list, constant_list)
232240
if correct:
233241
log_debug("BGPAllowListMgr::__update_prefix_list. the prefix-list '%s' exists and correct" % pl_name)
@@ -237,7 +245,7 @@ def __update_prefix_list(self, af, pl_name, allow_list):
237245
seq_no = 10
238246
if exist:
239247
cmds.append('no %s prefix-list %s' % (family, pl_name))
240-
for entry in constant_list + allow_list:
248+
for entry in self.__normalize_ipnetwork(af, constant_list + allow_list):
241249
cmds.append('%s prefix-list %s seq %d %s' % (family, pl_name, seq_no, entry))
242250
seq_no += 10
243251
return cmds
@@ -258,6 +266,24 @@ def __remove_prefix_list(self, af, pl_name):
258266
family = self.__af_to_family(af)
259267
return ["no %s prefix-list %s" % (family, pl_name)]
260268

269+
def __normalize_ipnetwork(self, af, allow_prefix_list):
270+
'''
271+
Normalize IPv6 addresses
272+
for example:
273+
2001:cdba:0000:0000:0000:0000:3257:9652
274+
2001:cdba:0:0:0:0:3257:9652
275+
2001:cdba::3257:9652
276+
after normalize, all would be normalized to
277+
2001:cdba::3257:9652
278+
'''
279+
normalize_list = []
280+
for allow_item in allow_prefix_list:
281+
tmp_list = allow_item.split(' ')
282+
if af == self.V6:
283+
tmp_list[self.PREFIX_LIST_POS] = str(ipaddress.IPv6Network(tmp_list[self.PREFIX_LIST_POS]))
284+
normalize_list.append(' '.join(tmp_list))
285+
return normalize_list
286+
261287
def __is_prefix_list_valid(self, af, pl_name, allow_list, constant_list):
262288
"""
263289
Check that a prefix list exists and it has valid entries
@@ -266,28 +292,27 @@ def __is_prefix_list_valid(self, af, pl_name, allow_list, constant_list):
266292
:param allow_list: a prefix-list which must be a part of the valid prefix list
267293
:param constant_list: a constant list which must be on top of each "allow" prefix list on the device
268294
:return: a tuple. The first element of the tuple has True if the prefix-list exists, False otherwise,
269-
The second element of the tuple has True if the prefix-list contains correct entries, False if not
295+
The second element of the tuple has True if allow prefix list in running configuraiton is
296+
equal with ones in config db + constants, False if not
270297
"""
271298
assert af == self.V4 or af == self.V6
272299
family = self.__af_to_family(af)
273300
match_string = '%s prefix-list %s seq ' % (family, pl_name)
274301
conf = self.cfg_mgr.get_text()
275302
if not any(line.strip().startswith(match_string) for line in conf):
276303
return False, False # if the prefix list is not exists, it is not correct
277-
constant_set = set(constant_list)
278-
allow_set = set(allow_list)
304+
expect_set = set(self.__normalize_ipnetwork(af, constant_list))
305+
expect_set.update(set(self.__normalize_ipnetwork(af, allow_list)))
306+
307+
config_list = []
279308
for line in conf:
280309
if line.startswith(match_string):
281310
found = line[len(match_string):].strip().split(' ')
282311
rule = " ".join(found[1:])
283-
if rule in constant_set:
284-
constant_set.discard(rule)
285-
elif rule in allow_set:
286-
if constant_set:
287-
return True, False # Not everything from constant set is presented
288-
else:
289-
allow_set.discard(rule)
290-
return True, len(allow_set) == 0 # allow_set should be presented all
312+
config_list.append(rule)
313+
314+
# Return double Ture, when running configuraiton is identical with config db + constants.
315+
return True, expect_set == set(self.__normalize_ipnetwork(af, config_list))
291316

292317
def __update_community(self, community_name, community_value):
293318
"""

src/sonic-bgpcfgd/setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
'jinja2>=2.10',
1919
'netaddr==0.8.0',
2020
'pyyaml==5.4.1',
21+
'ipaddress==1.0.23'
2122
],
2223
setup_requires = [
2324
'pytest-runner',

0 commit comments

Comments
 (0)