diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/dynamic/delete.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/dynamic/delete.conf.j2 new file mode 100644 index 00000000000..36205a629d1 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/dynamic/delete.conf.j2 @@ -0,0 +1,7 @@ +! +! template: bgpd/templates/dynamic/delete.conf.j2 +! +no neighbor {{ neighbor_addr }} +! +! end of template: bgpd/templates/dynamic/delete.conf.j2 +! \ No newline at end of file diff --git a/src/sonic-bgpcfgd/bgpcfgd/managers_bgp.py b/src/sonic-bgpcfgd/bgpcfgd/managers_bgp.py index 4d7ee75204c..b9d3f514a85 100644 --- a/src/sonic-bgpcfgd/bgpcfgd/managers_bgp.py +++ b/src/sonic-bgpcfgd/bgpcfgd/managers_bgp.py @@ -109,6 +109,9 @@ def __init__(self, common_objs, db_name, table_name, peer_type, check_neig_meta) if (os.path.exists(self.fabric.env.loader.searchpath[0] + "/" + base_template + "update.conf.j2")): self.templates["update"] = self.fabric.from_file(base_template + "update.conf.j2") + if os.path.exists(self.fabric.env.loader.searchpath[0] + "/" + base_template + "delete.conf.j2"): + self.templates["delete"] = self.fabric.from_file(base_template + "delete.conf.j2") + log_info("Using delete template found at %s" % (base_template + "delete.conf.j2")) deps = [ ("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, "localhost/bgp_asn"), @@ -440,7 +443,18 @@ def del_handler(self, key): log_info("Listen range '%s' for peer '(%s|%s)' has been disabled" % (ip_range, vrf, nbr)) else: log_err("Listen range '%s' for peer '(%s|%s)' hasn't been disabled" % (ip_range, vrf, nbr)) - cmd = self.templates["delete"].render(neighbor_addr=nbr) + + kwargs = { + 'CONFIG_DB__DEVICE_METADATA': self.directory.get_slot("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME), + 'neighbor_addr': nbr, + 'vrf': vrf + } + + try: + cmd = self.templates["delete"].render(**kwargs) + except jinja2.TemplateError as e: + log_err("Peer '(%s|%s)'. Error in rendering the template for 'DEL' command '%s'" % (vrf, nbr, str(e))) + ret_code = self.apply_op(cmd, vrf) if ret_code: self.update_state_db(vrf, nbr, {}, "DEL") diff --git a/src/sonic-bgpcfgd/tests/test_bgp.py b/src/sonic-bgpcfgd/tests/test_bgp.py index ee7f0f28442..e66c5621c4b 100644 --- a/src/sonic-bgpcfgd/tests/test_bgp.py +++ b/src/sonic-bgpcfgd/tests/test_bgp.py @@ -56,6 +56,7 @@ def constructor(constants_path, bgp_router_id="", peer_type="general", with_lo0_ m.directory.put("LOCAL", "local_addresses", "fc00:20::20", {"interface": "Ethernet8|fc00:20::20/96"}) m.directory.put("LOCAL", "interfaces", "Ethernet4|30.30.30.30/24", {"anything": "anything"}) m.directory.put("LOCAL", "interfaces", "Ethernet8|fc00:20::20/96", {"anything": "anything"}) + m.directory.put("CONFIG_DB", swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME, "default|10.10.10.1", {"ip_range": None}) if m.check_neig_meta: m.directory.put("CONFIG_DB", swsscommon.CFG_DEVICE_NEIGHBOR_METADATA_TABLE_NAME, "TOR", {}) @@ -244,6 +245,16 @@ def test_del_handler(mocked_log_info): m = constructor(constant) m.del_handler("10.10.10.1") mocked_log_info.assert_called_with("Peer '(default|10.10.10.1)' has been removed") + +@patch('bgpcfgd.managers_bgp.log_info') +def test_del_handler_dynamic_template_exists(mocked_log_info): + for constant in load_constant_files(): + m = constructor(constant, peer_type="dynamic") + base_template = "bgpd/templates/" + m.constants["bgp"]["peers"]["dynamic"]["template_dir"] + "/delete.conf.j2" + if os.path.exists(TEMPLATE_PATH + "/" + base_template): + mocked_log_info.assert_called_with("Using delete template found at %s" % base_template) + m.del_handler("10.10.10.1") + mocked_log_info.assert_called_with("Peer '(default|10.10.10.1)' has been removed") @patch('bgpcfgd.managers_bgp.log_warn') def test_del_handler_nonexist_peer(mocked_log_warn): @@ -251,3 +262,14 @@ def test_del_handler_nonexist_peer(mocked_log_warn): m = constructor(constant) m.del_handler("40.40.40.1") mocked_log_warn.assert_called_with("Peer '(default|40.40.40.1)' has not been found") + +@patch('bgpcfgd.managers_bgp.log_info') +@patch('bgpcfgd.managers_bgp.log_warn') +def test_del_handler_dynamic_nonexist_peer_template_exists(mocked_log_warn, mocked_log_info): + for constant in load_constant_files(): + m = constructor(constant, peer_type="dynamic") + base_template = "bgpd/templates/" + m.constants["bgp"]["peers"]["dynamic"]["template_dir"] + "/delete.conf.j2" + if os.path.exists(TEMPLATE_PATH + "/" + base_template): + mocked_log_info.assert_called_with("Using delete template found at %s" % base_template) + m.del_handler("40.40.40.1") + mocked_log_warn.assert_called_with("Peer '(default|40.40.40.1)' has not been found")