Skip to content

Commit 52962f8

Browse files
authored
cherry-pick [bgpcfgd] ECMP overlay VxLan with BGP support to 202012 (#11079)
Why I did it This is a cherry-pick PR from master to 202012 branch below is the original PR which merged to master. #10716 How I did it How to verify it
1 parent adfe20b commit 52962f8

File tree

5 files changed

+263
-34
lines changed

5 files changed

+263
-34
lines changed

src/sonic-bgpcfgd/bgpcfgd/main.py

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from .managers_intf import InterfaceMgr
1818
from .managers_setsrc import ZebraSetSrc
1919
from .managers_static_rt import StaticRouteMgr
20+
from .managers_rm import RouteMapMgr
2021
from .runner import Runner, signal_handler
2122
from .template import TemplateFabric
2223
from .utils import read_constants
@@ -60,6 +61,7 @@ def do_work():
6061
StaticRouteMgr(common_objs, "CONFIG_DB", "STATIC_ROUTE"),
6162
# Route Advertisement Managers
6263
AdvertiseRouteMgr(common_objs, "STATE_DB", swsscommon.STATE_ADVERTISE_NETWORK_TABLE_NAME),
64+
RouteMapMgr(common_objs, "APPL_DB", swsscommon.APP_BGP_PROFILE_TABLE_NAME),
6365
]
6466
runner = Runner(common_objs['cfg_mgr'])
6567
for mgr in managers:
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
from .manager import Manager
22
from .template import TemplateFabric
33
from swsscommon import swsscommon
4+
from .managers_rm import ROUTE_MAPS
5+
import ipaddress
6+
from .log import log_info, log_err, log_debug
47

58

69
class AdvertiseRouteMgr(Manager):
710
""" This class Advertises routes when ADVERTISE_NETWORK_TABLE in STATE_DB is updated """
11+
812
def __init__(self, common_objs, db, table):
913
"""
1014
Initialize the object
@@ -18,82 +22,105 @@ def __init__(self, common_objs, db, table):
1822
db,
1923
table,
2024
)
21-
25+
2226
self.directory.subscribe([("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, "localhost/bgp_asn"),], self.on_bgp_asn_change)
2327
self.advertised_routes = dict()
2428

2529

26-
OP_DELETE = 'DELETE'
27-
OP_ADD = 'ADD'
28-
30+
OP_DELETE = "DELETE"
31+
OP_ADD = "ADD"
2932

3033
def set_handler(self, key, data):
34+
log_debug("AdvertiseRouteMgr:: set handler")
35+
if not self.__set_handler_validate(key, data):
36+
return True
3137
vrf, ip_prefix = self.split_key(key)
32-
self.add_route_advertisement(vrf, ip_prefix)
38+
self.add_route_advertisement(vrf, ip_prefix, data)
3339

3440
return True
3541

36-
3742
def del_handler(self, key):
43+
log_debug("AdvertiseRouteMgr:: del handler")
3844
vrf, ip_prefix = self.split_key(key)
3945
self.remove_route_advertisement(vrf, ip_prefix)
4046

41-
42-
def add_route_advertisement(self, vrf, ip_prefix):
47+
def __set_handler_validate(self, key, data):
48+
if data:
49+
if ("profile" in data and data["profile"] in ROUTE_MAPS) or data == {"":""}:
50+
"""
51+
APP which config the data should be responsible to pass a valid IP prefix
52+
"""
53+
return True
54+
55+
log_err("BGPAdvertiseRouteMgr:: Invalid data %s for advertised route %s" % (data, key))
56+
return False
57+
58+
def add_route_advertisement(self, vrf, ip_prefix, data):
4359
if self.directory.path_exist("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, "localhost/bgp_asn"):
44-
if not self.advertised_routes.get(vrf, set()):
60+
if not self.advertised_routes.get(vrf, dict()):
4561
self.bgp_network_import_check_commands(vrf, self.OP_ADD)
46-
self.advertise_route_commands(ip_prefix, vrf, self.OP_ADD)
47-
48-
self.advertised_routes.setdefault(vrf, set()).add(ip_prefix)
62+
self.advertise_route_commands(ip_prefix, vrf, self.OP_ADD, data)
4963

64+
self.advertised_routes.setdefault(vrf, dict()).update({ip_prefix: data})
5065

5166
def remove_route_advertisement(self, vrf, ip_prefix):
52-
self.advertised_routes.setdefault(vrf, set()).discard(ip_prefix)
53-
if not self.advertised_routes.get(vrf, set()):
67+
if ip_prefix not in self.advertised_routes.get(vrf, dict()):
68+
log_info("BGPAdvertiseRouteMgr:: %s|%s does not exist" % (vrf, ip_prefix))
69+
return
70+
self.advertised_routes.get(vrf, dict()).pop(ip_prefix)
71+
if not self.advertised_routes.get(vrf, dict()):
5472
self.advertised_routes.pop(vrf, None)
5573

5674
if self.directory.path_exist("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, "localhost/bgp_asn"):
57-
if not self.advertised_routes.get(vrf, set()):
75+
if not self.advertised_routes.get(vrf, dict()):
5876
self.bgp_network_import_check_commands(vrf, self.OP_DELETE)
5977
self.advertise_route_commands(ip_prefix, vrf, self.OP_DELETE)
6078

61-
62-
def advertise_route_commands(self, ip_prefix, vrf, op):
79+
def advertise_route_commands(self, ip_prefix, vrf, op, data=None):
6380
is_ipv6 = TemplateFabric.is_ipv6(ip_prefix)
6481
bgp_asn = self.directory.get_slot("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME)["localhost"]["bgp_asn"]
6582

6683
cmd_list = []
67-
if vrf == 'default':
84+
if vrf == "default":
6885
cmd_list.append("router bgp %s" % bgp_asn)
6986
else:
7087
cmd_list.append("router bgp %s vrf %s" % (bgp_asn, vrf))
7188

7289
cmd_list.append(" address-family %s unicast" % ("ipv6" if is_ipv6 else "ipv4"))
73-
cmd_list.append(" %snetwork %s" % ('no ' if op == self.OP_DELETE else '', ip_prefix))
7490

75-
self.cfg_mgr.push_list(cmd_list)
91+
if data and "profile" in data:
92+
cmd_list.append(" network %s route-map %s" % (ip_prefix, "%s_RM" % data["profile"]))
93+
log_debug(
94+
"BGPAdvertiseRouteMgr:: Update bgp %s network %s with route-map %s"
95+
% (bgp_asn, vrf + "|" + ip_prefix, "%s_RM" % data["profile"])
96+
)
97+
else:
98+
cmd_list.append(" %snetwork %s" % ("no " if op == self.OP_DELETE else "", ip_prefix))
99+
log_debug(
100+
"BGPAdvertiseRouteMgr:: %sbgp %s network %s"
101+
% ("Remove " if op == self.OP_DELETE else "Update ", bgp_asn, vrf + "|" + ip_prefix)
102+
)
76103

104+
self.cfg_mgr.push_list(cmd_list)
105+
log_debug("BGPAdvertiseRouteMgr::Done")
77106

78107
def bgp_network_import_check_commands(self, vrf, op):
79108
bgp_asn = self.directory.get_slot("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME)["localhost"]["bgp_asn"]
80109
cmd_list = []
81-
if vrf == 'default':
110+
if vrf == "default":
82111
cmd_list.append("router bgp %s" % bgp_asn)
83112
else:
84113
cmd_list.append("router bgp %s vrf %s" % (bgp_asn, vrf))
85-
cmd_list.append(" %sbgp network import-check" % ('' if op == self.OP_DELETE else 'no '))
114+
cmd_list.append(" %sbgp network import-check" % ("" if op == self.OP_DELETE else "no "))
86115

87116
self.cfg_mgr.push_list(cmd_list)
88117

89-
90118
def on_bgp_asn_change(self):
91119
if self.directory.path_exist("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, "localhost/bgp_asn"):
92120
for vrf, ip_prefixes in self.advertised_routes.items():
93121
self.bgp_network_import_check_commands(vrf, self.OP_ADD)
94122
for ip_prefix in ip_prefixes:
95-
self.add_route_advertisement(vrf, ip_prefix)
96-
123+
self.add_route_advertisement(vrf, ip_prefix, ip_prefixes[ip_prefix])
97124

98125
@staticmethod
99126
def split_key(key):
@@ -102,7 +129,7 @@ def split_key(key):
102129
:param key: key to split
103130
:return: vrf name extracted from the key, ip prefix extracted from the key
104131
"""
105-
if '|' not in key:
106-
return 'default', key
132+
if "|" not in key:
133+
return "default", key
107134
else:
108-
return tuple(key.split('|', 1))
135+
return tuple(key.split("|", 1))
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from .manager import Manager
2+
from .log import log_err, log_debug
3+
4+
ROUTE_MAPS = ["FROM_SDN_SLB_ROUTES"]
5+
6+
7+
class RouteMapMgr(Manager):
8+
"""This class add route-map when BGP_PROFILE_TABLE in APPL_DB is updated"""
9+
10+
def __init__(self, common_objs, db, table):
11+
"""
12+
Initialize the object
13+
:param common_objs: common object dictionary
14+
:param db: name of the db
15+
:param table: name of the table in the db
16+
"""
17+
super(RouteMapMgr, self).__init__(
18+
common_objs,
19+
[],
20+
db,
21+
table,
22+
)
23+
24+
def set_handler(self, key, data):
25+
log_debug("BGPRouteMapMgr:: set handler")
26+
"""Only need a name as the key, and community id as the data"""
27+
if not self.__set_handler_validate(key, data):
28+
return True
29+
30+
self.__update_rm(key, data)
31+
return True
32+
33+
def del_handler(self, key):
34+
log_debug("BGPRouteMapMgr:: del handler")
35+
if not self.__del_handler_validate(key):
36+
return
37+
self.__remove_rm(key)
38+
39+
def __remove_rm(self, rm):
40+
cmds = ["no route-map %s permit 100" % ("%s_RM" % rm)]
41+
log_debug("BGPRouteMapMgr:: remove route-map %s" % ("%s_RM" % rm))
42+
self.cfg_mgr.push_list(cmds)
43+
log_debug("BGPRouteMapMgr::Done")
44+
45+
def __set_handler_validate(self, key, data):
46+
if key not in ROUTE_MAPS:
47+
log_err("BGPRouteMapMgr:: Invalid key for route-map %s" % key)
48+
return False
49+
50+
if not data:
51+
log_err("BGPRouteMapMgr:: data is None")
52+
return False
53+
community_ids = data["community_id"].split(":")
54+
try:
55+
if (
56+
len(community_ids) != 2
57+
or int(community_ids[0]) not in range(0, 65536)
58+
or int(community_ids[1]) not in range(0, 65536)
59+
):
60+
log_err("BGPRouteMapMgr:: data %s doesn't include valid community id %s" % (data, community_ids))
61+
return False
62+
except ValueError:
63+
log_err("BGPRouteMapMgr:: data %s includes illegal input" % (data))
64+
return False
65+
66+
return True
67+
68+
def __del_handler_validate(self, key):
69+
if key not in ROUTE_MAPS:
70+
log_err("BGPRouteMapMgr:: Invalid key for route-map %s" % key)
71+
return False
72+
return True
73+
74+
def __update_rm(self, rm, data):
75+
cmds = ["route-map %s permit 100" % ("%s_RM" % rm), " set community %s" % data["community_id"]]
76+
log_debug("BGPRouteMapMgr:: update route-map %s community %s" % ("%s_RM" % rm, data["community_id"]))
77+
self.cfg_mgr.push_list(cmds)
78+
log_debug("BGPRouteMapMgr::Done")

src/sonic-bgpcfgd/tests/test_advertise_rt.py

+66-6
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def test_set_del():
4848
set_del_test(
4949
mgr,
5050
"SET",
51-
("10.1.0.0/24", {}),
51+
("10.1.0.0/24", {"":""}),
5252
True,
5353
[
5454
["router bgp 65100",
@@ -62,7 +62,7 @@ def test_set_del():
6262
set_del_test(
6363
mgr,
6464
"SET",
65-
("fc00:10::/64", {}),
65+
("fc00:10::/64", {"":""}),
6666
True,
6767
[
6868
["router bgp 65100",
@@ -103,7 +103,7 @@ def test_set_del_vrf():
103103
set_del_test(
104104
mgr,
105105
"SET",
106-
("vrfRED|10.2.0.0/24", {}),
106+
("vrfRED|10.2.0.0/24", {"":""}),
107107
True,
108108
[
109109
["router bgp 65100 vrf vrfRED",
@@ -117,7 +117,7 @@ def test_set_del_vrf():
117117
set_del_test(
118118
mgr,
119119
"SET",
120-
("vrfRED|fc00:20::/64", {}),
120+
("vrfRED|fc00:20::/64", {"":""}),
121121
True,
122122
[
123123
["router bgp 65100 vrf vrfRED",
@@ -158,7 +158,9 @@ def test_set_del_bgp_asn_change():
158158
set_del_test(
159159
mgr,
160160
"SET",
161-
("vrfRED|10.3.0.0/24", {}),
161+
("vrfRED|10.3.0.0/24", {
162+
"profile": "FROM_SDN_SLB_ROUTES"
163+
}),
162164
True,
163165
[]
164166
)
@@ -170,7 +172,7 @@ def test_set_del_bgp_asn_change():
170172
" no bgp network import-check"],
171173
["router bgp 65100 vrf vrfRED",
172174
" address-family ipv4 unicast",
173-
" network 10.3.0.0/24"]
175+
" network 10.3.0.0/24 route-map FROM_SDN_SLB_ROUTES_RM"]
174176
]
175177
def push_list(cmds):
176178
test_set_del_bgp_asn_change.push_list_called = True
@@ -183,3 +185,61 @@ def push_list(cmds):
183185
mgr.directory.put("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, "localhost", {"bgp_asn": "65100"})
184186

185187
assert test_set_del_bgp_asn_change.push_list_called
188+
189+
def test_set_del_with_community():
190+
mgr = constructor()
191+
set_del_test(
192+
mgr,
193+
"SET",
194+
("10.1.0.0/24", {
195+
"profile": "FROM_SDN_SLB_ROUTES"
196+
}),
197+
True,
198+
[
199+
["router bgp 65100",
200+
" no bgp network import-check"],
201+
["router bgp 65100",
202+
" address-family ipv4 unicast",
203+
" network 10.1.0.0/24 route-map FROM_SDN_SLB_ROUTES_RM"]
204+
]
205+
)
206+
207+
set_del_test(
208+
mgr,
209+
"SET",
210+
("fc00:10::/64", {
211+
"profile": "FROM_SDN_SLB_ROUTES"
212+
}),
213+
True,
214+
[
215+
["router bgp 65100",
216+
" address-family ipv6 unicast",
217+
" network fc00:10::/64 route-map FROM_SDN_SLB_ROUTES_RM"]
218+
]
219+
)
220+
221+
set_del_test(
222+
mgr,
223+
"DEL",
224+
("10.1.0.0/24",),
225+
True,
226+
[
227+
["router bgp 65100",
228+
" address-family ipv4 unicast",
229+
" no network 10.1.0.0/24"]
230+
]
231+
)
232+
233+
set_del_test(
234+
mgr,
235+
"DEL",
236+
("fc00:10::/64",),
237+
True,
238+
[
239+
["router bgp 65100",
240+
" bgp network import-check"],
241+
["router bgp 65100",
242+
" address-family ipv6 unicast",
243+
" no network fc00:10::/64"]
244+
]
245+
)

0 commit comments

Comments
 (0)