summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/northbound_cli.c14
-rw-r--r--tests/topotests/bgp-basic-functionality-topo1/bgp_basic_functionality.json159
-rwxr-xr-xtests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py554
-rw-r--r--tests/topotests/lib/bgp.py24
-rw-r--r--tests/topotests/lib/common_config.py287
-rw-r--r--tests/topotests/lib/topotest.py27
-rw-r--r--zebra/kernel_netlink.c14
-rw-r--r--zebra/zebra_evpn_mh.c13
8 files changed, 951 insertions, 141 deletions
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 2f6aef5398..ee080bca3f 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -63,7 +63,15 @@ static int nb_cli_classic_commit(struct vty *vty)
context.user = vty;
ret = nb_candidate_commit(&context, vty->candidate_config, true, NULL,
NULL, errmsg, sizeof(errmsg));
- if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) {
+ switch (ret) {
+ case NB_OK:
+ /* Successful commit. Print warnings (if any). */
+ if (strlen(errmsg) > 0)
+ vty_out(vty, "%s\n", errmsg);
+ break;
+ case NB_ERR_NO_CHANGES:
+ break;
+ default:
vty_out(vty, "%% Configuration failed.\n\n");
vty_show_nb_errors(vty, ret, errmsg);
if (vty->t_pending_commit)
@@ -74,9 +82,7 @@ static int nb_cli_classic_commit(struct vty *vty)
/* Regenerate candidate for consistency. */
nb_config_replace(vty->candidate_config, running_config, true);
return CMD_WARNING_CONFIG_FAILED;
- } else if (strlen(errmsg) > 0)
- /* Successful commit. Print warnings (if any). */
- vty_out(vty, "%s\n", errmsg);
+ }
return CMD_SUCCESS;
}
diff --git a/tests/topotests/bgp-basic-functionality-topo1/bgp_basic_functionality.json b/tests/topotests/bgp-basic-functionality-topo1/bgp_basic_functionality.json
index c778ae4bed..ee1f1b74c0 100644
--- a/tests/topotests/bgp-basic-functionality-topo1/bgp_basic_functionality.json
+++ b/tests/topotests/bgp-basic-functionality-topo1/bgp_basic_functionality.json
@@ -1,36 +1,17 @@
{
+ "address_types": ["ipv4", "ipv6"],
"ipv4base": "10.0.0.0",
"ipv4mask": 30,
"ipv6base": "fd00::",
"ipv6mask": 64,
- "link_ip_start": {
- "ipv4": "10.0.0.0",
- "v4mask": 30,
- "ipv6": "fd00::",
- "v6mask": 64
- },
- "lo_prefix": {
- "ipv4": "1.0.",
- "v4mask": 32,
- "ipv6": "2001:DB8:F::",
- "v6mask": 128
- },
+ "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
"routers": {
"r1": {
"links": {
- "lo": {
- "ipv4": "auto",
- "ipv6": "auto",
- "type": "loopback"
- },
- "r2": {
- "ipv4": "auto",
- "ipv6": "auto"
- },
- "r3": {
- "ipv4": "auto",
- "ipv6": "auto"
- }
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "100",
@@ -38,16 +19,16 @@
"ipv4": {
"unicast": {
"neighbor": {
- "r2": {
- "dest_link": {
- "r1": {}
- }
- },
- "r3": {
- "dest_link": {
- "r1": {}
- }
- }
+ "r2": {"dest_link": {"r1": {}}},
+ "r3": {"dest_link": {"r1": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {}}},
+ "r3": {"dest_link": {"r1": {}}}
}
}
}
@@ -56,19 +37,9 @@
},
"r2": {
"links": {
- "lo": {
- "ipv4": "auto",
- "ipv6": "auto",
- "type": "loopback"
- },
- "r1": {
- "ipv4": "auto",
- "ipv6": "auto"
- },
- "r3": {
- "ipv4": "auto",
- "ipv6": "auto"
- }
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4": "auto", "ipv6": "auto"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "100",
@@ -76,16 +47,16 @@
"ipv4": {
"unicast": {
"neighbor": {
- "r1": {
- "dest_link": {
- "r2": {}
- }
- },
- "r3": {
- "dest_link": {
- "r2": {}
- }
- }
+ "r1": {"dest_link": {"r2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
}
}
}
@@ -94,23 +65,10 @@
},
"r3": {
"links": {
- "lo": {
- "ipv4": "auto",
- "ipv6": "auto",
- "type": "loopback"
- },
- "r1": {
- "ipv4": "auto",
- "ipv6": "auto"
- },
- "r2": {
- "ipv4": "auto",
- "ipv6": "auto"
- },
- "r4": {
- "ipv4": "auto",
- "ipv6": "auto"
- }
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"},
+ "r4": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "100",
@@ -118,21 +76,18 @@
"ipv4": {
"unicast": {
"neighbor": {
- "r1": {
- "dest_link": {
- "r3": {}
- }
- },
- "r2": {
- "dest_link": {
- "r3": {}
- }
- },
- "r4": {
- "dest_link": {
- "r3": {}
- }
- }
+ "r1": {"dest_link": {"r3": {}}},
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r3": {}}},
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
}
}
}
@@ -141,29 +96,17 @@
},
"r4": {
"links": {
- "lo": {
- "ipv4": "auto",
- "ipv6": "auto",
- "type": "loopback"
- },
- "r3": {
- "ipv4": "auto",
- "ipv6": "auto"
- }
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "200",
"address_family": {
"ipv4": {
- "unicast": {
- "neighbor": {
- "r3": {
- "dest_link": {
- "r4": {}
- }
- }
- }
- }
+ "unicast": {"neighbor": {"r3": {"dest_link": {"r4": {}}}}}
+ },
+ "ipv6": {
+ "unicast": {"neighbor": {"r3": {"dest_link": {"r4": {}}}}}
}
}
}
diff --git a/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py b/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py
index 3441d68731..69e050caed 100755
--- a/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py
+++ b/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py
@@ -37,6 +37,8 @@ Test steps
- Verify clear bgp
- Test bgp convergence with loopback interface
- Test advertise network using network command
+- Verify routes not installed in zebra when /32 routes received
+ with loopback BGP session subnet
"""
import os
@@ -59,6 +61,7 @@ from lib.topogen import Topogen, get_topogen
from mininet.topo import Topo
from lib.common_config import (
+ step,
start_topology,
write_test_header,
write_test_footer,
@@ -66,6 +69,13 @@ from lib.common_config import (
create_static_routes,
verify_rib,
verify_admin_distance_for_static_routes,
+ check_address_types,
+ apply_raw_config,
+ addKernelRoute,
+ verify_fib_routes,
+ create_prefix_lists,
+ create_route_maps,
+ verify_bgp_community,
)
from lib.topolog import logger
from lib.bgp import (
@@ -76,6 +86,7 @@ from lib.bgp import (
verify_as_numbers,
clear_bgp_and_verify,
verify_bgp_timers_and_functionality,
+ verify_bgp_rib,
)
from lib.topojson import build_topo_from_json, build_config_from_json
@@ -90,6 +101,18 @@ except IOError:
# Global Variable
KEEPALIVETIMER = 2
HOLDDOWNTIMER = 6
+r1_ipv4_loopback = "1.0.1.0/24"
+r2_ipv4_loopback = "1.0.2.0/24"
+r3_ipv4_loopback = "1.0.3.0/24"
+r4_ipv4_loopback = "1.0.4.0/24"
+r1_ipv6_loopback = "2001:db8:f::1:0/120"
+r2_ipv6_loopback = "2001:db8:f::2:0/120"
+r3_ipv6_loopback = "2001:db8:f::3:0/120"
+r4_ipv6_loopback = "2001:db8:f::4:0/120"
+NETWORK = {
+ "ipv4": ["100.1.1.1/32", "100.1.1.2/32"],
+ "ipv6": ["100::1/128", "100::2/128"],
+}
class CreateTopo(Topo):
@@ -131,7 +154,9 @@ def setup_module(mod):
# Creating configuration from JSON
build_config_from_json(tgen, topo)
+ global ADDR_TYPES
global BGP_CONVERGENCE
+ ADDR_TYPES = check_address_types()
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
BGP_CONVERGENCE
@@ -522,6 +547,243 @@ def test_clear_bgp_and_verify(request):
write_test_footer(tc_name)
+def test_BGP_attributes_with_vrf_default_keyword_p0(request):
+ """
+ TC_9:
+ Verify BGP functionality for default vrf with
+ "vrf default" keyword.
+ """
+
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ #reset_config_on_routers(tgen)
+
+ step("Configure static routes and redistribute in BGP on R3")
+ for addr_type in ADDR_TYPES:
+ input_dict = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type][0],
+ "no_of_ip": 4,
+ "next_hop": "Null0",
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_2 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Create a route-map to match a specific prefix and modify"
+ "BGP attributes for matched prefix"
+ )
+ input_dict_2 = {
+ "r3": {
+ "prefix_lists": {
+ "ipv4": {
+ "ABC": [
+ {
+ "seqid": 10,
+ "action": "permit",
+ "network": NETWORK["ipv4"][0],
+ }
+ ]
+ },
+ "ipv6": {
+ "XYZ": [
+ {
+ "seqid": 100,
+ "action": "permit",
+ "network": NETWORK["ipv6"][0],
+ }
+ ]
+ },
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ if addr_type == "ipv4":
+ pf_list = "ABC"
+ else:
+ pf_list = "XYZ"
+
+ input_dict_6 = {
+ "r3": {
+ "route_maps": {
+ "BGP_ATTR_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "seq_id": 10,
+ "match": {addr_type: {"prefix_lists": pf_list}},
+ "set": {
+ "aspath": {"as_num": 500, "as_action": "prepend"},
+ "localpref": 500,
+ "origin": "egp",
+ "community": {"num": "500:500", "action": "additive"},
+ "large_community": {
+ "num": "500:500:500",
+ "action": "additive",
+ },
+ },
+ },
+ {"action": "permit", "seq_id": 20},
+ ]
+ },
+ "BGP_ATTR_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "seq_id": 100,
+ "match": {addr_type: {"prefix_lists": pf_list}},
+ "set": {
+ "aspath": {"as_num": 500, "as_action": "prepend"},
+ "localpref": 500,
+ "origin": "egp",
+ "community": {"num": "500:500", "action": "additive"},
+ "large_community": {
+ "num": "500:500:500",
+ "action": "additive",
+ },
+ },
+ },
+ {"action": "permit", "seq_id": 200},
+ ],
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Apply the route-map on R3 in outbound direction for peer R4")
+
+ input_dict_7 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {
+ "name": "BGP_ATTR_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {
+ "name": "BGP_ATTR_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "verify modified attributes for specific prefix with 'vrf default'"
+ "keyword on R4"
+ )
+ for addr_type in ADDR_TYPES:
+ dut = "r4"
+ input_dict = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type][0],
+ "vrf": "default",
+ "largeCommunity": "500:500:500",
+ }
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+ result = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r4"
+ input_dict = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type][0],
+ "vrf": "default",
+ "community": "500:500",
+ }
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+ result = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict_4 = {"largeCommunity": "500:500:500", "community": "500:500"}
+
+ result = verify_bgp_community(
+ tgen, addr_type, dut, [NETWORK[addr_type][0]], input_dict_4
+ )
+ assert result is True, "Test case {} : Should fail \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
def test_bgp_with_loopback_interface(request):
"""
Test BGP with loopback interface
@@ -588,6 +850,298 @@ def test_bgp_with_loopback_interface(request):
write_test_footer(tc_name)
+def test_bgp_with_loopback_with_same_subnet_p1(request):
+ """
+ Verify routes not installed in zebra when /32 routes received
+ with loopback BGP session subnet
+ """
+
+ tgen = get_topogen()
+ if BGP_CONVERGENCE is not True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+ step("Delete BGP seesion created initially")
+ input_dict_r1 = {
+ "r1": {"bgp": {"delete": True}},
+ "r2": {"bgp": {"delete": True}},
+ "r3": {"bgp": {"delete": True}},
+ "r4": {"bgp": {"delete": True}},
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Create BGP session over loop address")
+ topo_modify = deepcopy(topo)
+
+ for routerN in sorted(topo["routers"].keys()):
+ for addr_type in ADDR_TYPES:
+ for bgp_neighbor in topo_modify["routers"][routerN]["bgp"][
+ "address_family"
+ ][addr_type]["unicast"]["neighbor"].keys():
+
+ # Adding ['source_link'] = 'lo' key:value pair
+ topo_modify["routers"][routerN]["bgp"]["address_family"][addr_type][
+ "unicast"
+ ]["neighbor"][bgp_neighbor]["dest_link"] = {
+ "lo": {"source_link": "lo", "ebgp_multihop": 2}
+ }
+
+ result = create_router_bgp(tgen, topo_modify["routers"])
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Disable IPv6 BGP nbr from ipv4 address family")
+ raw_config = {
+ "r1": {
+ "raw_config": [
+ "router bgp {}".format(topo["routers"]["r1"]["bgp"]["local_as"]),
+ "address-family ipv4 unicast",
+ "no neighbor {} activate".format(
+ topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
+ ),
+ "no neighbor {} activate".format(
+ topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0]
+ ),
+ ]
+ },
+ "r2": {
+ "raw_config": [
+ "router bgp {}".format(topo["routers"]["r2"]["bgp"]["local_as"]),
+ "address-family ipv4 unicast",
+ "no neighbor {} activate".format(
+ topo["routers"]["r1"]["links"]["lo"]["ipv6"].split("/")[0]
+ ),
+ "no neighbor {} activate".format(
+ topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0]
+ ),
+ ]
+ },
+ "r3": {
+ "raw_config": [
+ "router bgp {}".format(topo["routers"]["r3"]["bgp"]["local_as"]),
+ "address-family ipv4 unicast",
+ "no neighbor {} activate".format(
+ topo["routers"]["r1"]["links"]["lo"]["ipv6"].split("/")[0]
+ ),
+ "no neighbor {} activate".format(
+ topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
+ ),
+ "no neighbor {} activate".format(
+ topo["routers"]["r4"]["links"]["lo"]["ipv6"].split("/")[0]
+ ),
+ ]
+ },
+ "r4": {
+ "raw_config": [
+ "router bgp {}".format(topo["routers"]["r4"]["bgp"]["local_as"]),
+ "address-family ipv4 unicast",
+ "no neighbor {} activate".format(
+ topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0]
+ ),
+ ]
+ },
+ }
+
+ step("Configure kernel routes")
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ r1_ipv4_lo = topo["routers"]["r1"]["links"]["lo"]["ipv4"]
+ r1_ipv6_lo = topo["routers"]["r1"]["links"]["lo"]["ipv6"]
+ r2_ipv4_lo = topo["routers"]["r2"]["links"]["lo"]["ipv4"]
+ r2_ipv6_lo = topo["routers"]["r2"]["links"]["lo"]["ipv6"]
+ r3_ipv4_lo = topo["routers"]["r3"]["links"]["lo"]["ipv4"]
+ r3_ipv6_lo = topo["routers"]["r3"]["links"]["lo"]["ipv6"]
+ r4_ipv4_lo = topo["routers"]["r4"]["links"]["lo"]["ipv4"]
+ r4_ipv6_lo = topo["routers"]["r4"]["links"]["lo"]["ipv6"]
+
+ r1_r2 = topo["routers"]["r1"]["links"]["r2"]["ipv6"].split("/")[0]
+ r2_r1 = topo["routers"]["r2"]["links"]["r1"]["ipv6"].split("/")[0]
+ r1_r3 = topo["routers"]["r1"]["links"]["r3"]["ipv6"].split("/")[0]
+ r3_r1 = topo["routers"]["r3"]["links"]["r1"]["ipv6"].split("/")[0]
+ r2_r3 = topo["routers"]["r2"]["links"]["r3"]["ipv6"].split("/")[0]
+ r3_r2 = topo["routers"]["r3"]["links"]["r2"]["ipv6"].split("/")[0]
+ r3_r4 = topo["routers"]["r3"]["links"]["r4"]["ipv6"].split("/")[0]
+ r4_r3 = topo["routers"]["r4"]["links"]["r3"]["ipv6"].split("/")[0]
+
+ r1_r2_ipv4 = topo["routers"]["r1"]["links"]["r2"]["ipv4"].split("/")[0]
+ r2_r1_ipv4 = topo["routers"]["r2"]["links"]["r1"]["ipv4"].split("/")[0]
+ r1_r3_ipv4 = topo["routers"]["r1"]["links"]["r3"]["ipv4"].split("/")[0]
+ r3_r1_ipv4 = topo["routers"]["r3"]["links"]["r1"]["ipv4"].split("/")[0]
+ r2_r3_ipv4 = topo["routers"]["r2"]["links"]["r3"]["ipv4"].split("/")[0]
+ r3_r2_ipv4 = topo["routers"]["r3"]["links"]["r2"]["ipv4"].split("/")[0]
+ r3_r4_ipv4 = topo["routers"]["r3"]["links"]["r4"]["ipv4"].split("/")[0]
+ r4_r3_ipv4 = topo["routers"]["r4"]["links"]["r3"]["ipv4"].split("/")[0]
+
+ r1_r2_intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
+ r2_r1_intf = topo["routers"]["r2"]["links"]["r1"]["interface"]
+ r1_r3_intf = topo["routers"]["r1"]["links"]["r3"]["interface"]
+ r3_r1_intf = topo["routers"]["r3"]["links"]["r1"]["interface"]
+ r2_r3_intf = topo["routers"]["r2"]["links"]["r3"]["interface"]
+ r3_r2_intf = topo["routers"]["r3"]["links"]["r2"]["interface"]
+ r3_r4_intf = topo["routers"]["r3"]["links"]["r4"]["interface"]
+ r4_r3_intf = topo["routers"]["r4"]["links"]["r3"]["interface"]
+
+ ipv4_list = [
+ ("r1", r1_r2_intf, r2_ipv4_loopback),
+ ("r1", r1_r3_intf, r3_ipv4_loopback),
+ ("r2", r2_r1_intf, r1_ipv4_loopback),
+ ("r2", r2_r3_intf, r3_ipv4_loopback),
+ ("r3", r3_r1_intf, r1_ipv4_loopback),
+ ("r3", r3_r2_intf, r2_ipv4_loopback),
+ ("r3", r3_r4_intf, r4_ipv4_loopback),
+ ("r4", r4_r3_intf, r3_ipv4_loopback),
+ ]
+
+ ipv6_list = [
+ ("r1", r1_r2_intf, r2_ipv6_loopback, r2_r1),
+ ("r1", r1_r3_intf, r3_ipv6_loopback, r3_r1),
+ ("r2", r2_r1_intf, r1_ipv6_loopback, r1_r2),
+ ("r2", r2_r3_intf, r3_ipv6_loopback, r3_r2),
+ ("r3", r3_r1_intf, r1_ipv6_loopback, r1_r3),
+ ("r3", r3_r2_intf, r2_ipv6_loopback, r2_r3),
+ ("r3", r3_r4_intf, r4_ipv6_loopback, r4_r3),
+ ("r4", r4_r3_intf, r3_ipv6_loopback, r3_r4),
+ ]
+
+ for dut, intf, loop_addr in ipv4_list:
+ result = addKernelRoute(tgen, dut, intf, loop_addr)
+ assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result)
+
+ for dut, intf, loop_addr, next_hop in ipv6_list:
+ result = addKernelRoute(tgen, dut, intf, loop_addr, next_hop)
+ assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure static routes")
+
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {"network": r2_ipv4_loopback, "next_hop": r2_r1_ipv4},
+ {"network": r3_ipv4_loopback, "next_hop": r3_r1_ipv4},
+ {"network": r2_ipv6_loopback, "next_hop": r2_r1},
+ {"network": r3_ipv6_loopback, "next_hop": r3_r1},
+ ]
+ },
+ "r2": {
+ "static_routes": [
+ {"network": r1_ipv4_loopback, "next_hop": r1_r2_ipv4},
+ {"network": r3_ipv4_loopback, "next_hop": r3_r2_ipv4},
+ {"network": r1_ipv6_loopback, "next_hop": r1_r2},
+ {"network": r3_ipv6_loopback, "next_hop": r3_r2},
+ ]
+ },
+ "r3": {
+ "static_routes": [
+ {"network": r1_ipv4_loopback, "next_hop": r1_r3_ipv4},
+ {"network": r2_ipv4_loopback, "next_hop": r2_r3_ipv4},
+ {"network": r4_ipv4_loopback, "next_hop": r4_r3_ipv4},
+ {"network": r1_ipv6_loopback, "next_hop": r1_r3},
+ {"network": r2_ipv6_loopback, "next_hop": r2_r3},
+ {"network": r4_ipv6_loopback, "next_hop": r4_r3},
+ ]
+ },
+ "r4": {
+ "static_routes": [
+ {"network": r3_ipv4_loopback, "next_hop": r3_r4_ipv4},
+ {"network": r3_ipv6_loopback, "next_hop": r3_r4},
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify BGP session convergence")
+
+ result = verify_bgp_convergence(tgen, topo_modify)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure redistribute connected on R2 and R4")
+ input_dict_1 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ }
+ }
+ },
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ }
+ }
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify Ipv4 and Ipv6 network installed in R1 RIB but not in FIB")
+ input_dict_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": "1.0.2.17/32"},
+ {"network": "2001:db8:f::2:17/128"},
+ ]
+ }
+ }
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict_r1, protocol=protocol)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_routes(tgen, addr_type, dut, input_dict_r1, expected=False)
+ assert result is not True, "Testcase {} : Failed \n"
+ "Expected behavior: routes should not present in fib \n"
+ "Error: {}".format(tc_name, result)
+
+ step("Verify Ipv4 and Ipv6 network installed in r3 RIB but not in FIB")
+ input_dict_r3 = {
+ "r3": {
+ "static_routes": [
+ {"network": "1.0.4.17/32"},
+ {"network": "2001:db8:f::4:17/128"},
+ ]
+ }
+ }
+ dut = "r3"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_r3, protocol=protocol, fib=None
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_routes(tgen, addr_type, dut, input_dict_r1, expected=False)
+ assert result is not True, "Testcase {} : Failed \n"
+ "Expected behavior: routes should not present in fib \n"
+ "Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 7b1eead944..316d4cf414 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -46,6 +46,7 @@ from lib.common_config import (
LOGDIR = "/tmp/topotests/"
TMPDIR = None
+
def create_router_bgp(tgen, topo, input_dict=None, build=False, load_config=True):
"""
API to configure bgp on router
@@ -1219,11 +1220,17 @@ def verify_bgp_convergence(tgen, topo, dut=None):
no_of_peer += 1
if no_of_peer == total_peer:
- logger.info("[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
- router, vrf, addr_type)
+ logger.info(
+ "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
+ router,
+ vrf,
+ addr_type,
+ )
else:
- errormsg = ("[DUT: %s] VRF: %s, BGP is not converged for %s address-family" %
- (router, vrf, addr_type))
+ errormsg = (
+ "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
+ % (router, vrf, addr_type)
+ )
return errormsg
logger.debug("Exiting API: verify_bgp_convergence()")
@@ -2553,10 +2560,19 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
missing_routes = []
st_found = False
nh_found = False
+
vrf = static_route.setdefault("vrf", None)
+ community = static_route.setdefault("community", None)
+ largeCommunity = static_route.setdefault("largeCommunity", None)
+
if vrf:
cmd = "{} vrf {} {}".format(command, vrf, addr_type)
+ if community:
+ cmd = "{} community {}".format(cmd, community)
+
+ if largeCommunity:
+ cmd = "{} large-community {}".format(cmd, largeCommunity)
else:
cmd = "{} {}".format(command, addr_type)
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index e4d72ea2d7..d77946b1ed 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -30,14 +30,19 @@ from functools import wraps
from re import search as re_search
from tempfile import mkdtemp
-import StringIO
import os
import sys
-import ConfigParser
import traceback
import socket
import ipaddress
+if sys.version_info[0] > 2:
+ import io
+ import configparser
+else:
+ import StringIO
+ import ConfigParser as configparser
+
from lib.topolog import logger, logger_config
from lib.topogen import TopoRouter, get_topogen
from lib.topotest import interface_set_status
@@ -61,7 +66,7 @@ TMPDIR = None
# NOTE: to save execution logs to log file frrtest_log_dir must be configured
# in `pytest.ini`.
-config = ConfigParser.ConfigParser()
+config = configparser.ConfigParser()
config.read(PYTESTINI_PATH)
config_section = "topogen"
@@ -393,6 +398,14 @@ def check_router_status(tgen):
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
+def getStrIO():
+ """
+ Return a StringIO object appropriate for the current python version.
+ """
+ if sys.version_info[0] > 2:
+ return io.StringIO()
+ else:
+ return StringIO.StringIO()
def reset_config_on_routers(tgen, routerName=None):
"""
@@ -465,7 +478,7 @@ def reset_config_on_routers(tgen, routerName=None):
raise InvalidCLIError("Unknown error in %s", output)
f = open(dname, "r")
- delta = StringIO.StringIO()
+ delta = getStrIO()
delta.write("configure terminal\n")
t_delta = f.read()
@@ -499,7 +512,7 @@ def reset_config_on_routers(tgen, routerName=None):
output = router.vtysh_multicmd(delta.getvalue(), pretty_output=False)
delta.close()
- delta = StringIO.StringIO()
+ delta = getStrIO()
cfg = router.run("vtysh -c 'show running'")
for line in cfg.split("\n"):
line = line.strip()
@@ -713,8 +726,8 @@ def start_topology(tgen):
os.chdir("{}/{}".format(TMPDIR, rname))
os.system("touch zebra.conf bgpd.conf")
- except IOError as (errno, strerror):
- logger.error("I/O error({0}): {1}".format(errno, strerror))
+ except IOError as err:
+ logger.error("I/O error({0}): {1}".format(err.errno, err.strerror))
# Loading empty zebra.conf file to router, to start the zebra deamon
router.load_config(
@@ -2191,7 +2204,7 @@ def addKernelRoute(
if mask == "32" or mask == "128":
grp_addr = ip
- if not re_search(r"{}".format(grp_addr), result) and mask is not "0":
+ if not re_search(r"{}".format(grp_addr), result) and mask != "0":
errormsg = (
"[DUT: {}]: Kernal route is not added for group"
" address {} Config output: {}".format(router, grp_addr, output)
@@ -2352,7 +2365,9 @@ def configure_brctl(tgen, topo, input_dict):
):
ip_cmd_list = []
- cmd = "ip link add name {} type bridge stp_state {}".format(brctl_name, stp)
+ cmd = "ip link add name {} type bridge stp_state {}".format(
+ brctl_name, stp
+ )
logger.info("[DUT: %s]: Running command: %s", dut, cmd)
rnode.run(cmd)
@@ -2821,6 +2836,260 @@ def verify_rib(
return True
+@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
+ """
+ Data will be read from input_dict or input JSON file, API will generate
+ same prefixes, which were redistributed by either create_static_routes() or
+ advertise_networks_using_network_command() and will verify next_hop and
+ each prefix/routes is present in "show ip/ipv6 fib json"
+ command o/p.
+
+ Parameters
+ ----------
+ * `tgen` : topogen object
+ * `addr_type` : ip type, ipv4/ipv6
+ * `dut`: Device Under Test, for which user wants to test the data
+ * `input_dict` : input dict, has details of static routes
+ * `next_hop`[optional]: next_hop which needs to be verified,
+ default: static
+
+ Usage
+ -----
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": ["1.1.1.1/32],
+ "next_hop": "Null0",
+ "vrf": "RED"
+ }]
+ }
+ }
+ result = result = verify_fib_routes(tgen, "ipv4, "r1", input_routes_r1)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ router_list = tgen.routers()
+ for routerInput in input_dict.keys():
+ for router, rnode in router_list.iteritems():
+ if router != dut:
+ continue
+
+ logger.info("Checking router %s FIB routes:", router)
+
+ # Verifying RIB routes
+ if addr_type == "ipv4":
+ command = "show ip fib"
+ else:
+ command = "show ipv6 fib"
+
+ found_routes = []
+ missing_routes = []
+
+ if "static_routes" in input_dict[routerInput]:
+ static_routes = input_dict[routerInput]["static_routes"]
+
+ for static_route in static_routes:
+ if "vrf" in static_route and static_route["vrf"] is not None:
+
+ logger.info(
+ "[DUT: {}]: Verifying routes for VRF:"
+ " {}".format(router, static_route["vrf"])
+ )
+
+ cmd = "{} vrf {}".format(command, static_route["vrf"])
+
+ else:
+ cmd = "{}".format(command)
+
+ cmd = "{} json".format(cmd)
+
+ rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ # Verifying output dictionary rib_routes_json is not empty
+ if bool(rib_routes_json) is False:
+ errormsg = "[DUT: {}]: No route found in fib".format(router)
+ return errormsg
+
+ network = static_route["network"]
+ if "no_of_ip" in static_route:
+ no_of_ip = static_route["no_of_ip"]
+ else:
+ no_of_ip = 1
+
+ # Generating IPs for verification
+ ip_list = generate_ips(network, no_of_ip)
+ st_found = False
+ nh_found = False
+
+ for st_rt in ip_list:
+ st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+
+ _addr_type = validate_ip_address(st_rt)
+ if _addr_type != addr_type:
+ continue
+
+ if st_rt in rib_routes_json:
+ st_found = True
+ found_routes.append(st_rt)
+
+ if next_hop:
+ if type(next_hop) is not list:
+ next_hop = [next_hop]
+
+ count = 0
+ for nh in next_hop:
+ for nh_dict in rib_routes_json[st_rt][0][
+ "nexthops"
+ ]:
+ if nh_dict["ip"] != nh:
+ continue
+ else:
+ count += 1
+
+ if count == len(next_hop):
+ nh_found = True
+ else:
+ missing_routes.append(st_rt)
+ errormsg = (
+ "Nexthop {} is Missing"
+ " for route {} in "
+ "RIB of router {}\n".format(
+ next_hop, st_rt, dut
+ )
+ )
+ return errormsg
+
+ else:
+ missing_routes.append(st_rt)
+
+ if len(missing_routes) > 0:
+ errormsg = "[DUT: {}]: Missing route in FIB:" " {}".format(
+ dut, missing_routes
+ )
+ return errormsg
+
+ if nh_found:
+ logger.info(
+ "Found next_hop {} for all routes in RIB"
+ " of router {}\n".format(next_hop, dut)
+ )
+
+ if found_routes:
+ logger.info(
+ "[DUT: %s]: Verified routes in FIB, found" " routes are: %s\n",
+ dut,
+ found_routes,
+ )
+
+ continue
+
+ if "bgp" in input_dict[routerInput]:
+ if (
+ "advertise_networks"
+ not in input_dict[routerInput]["bgp"]["address_family"][addr_type][
+ "unicast"
+ ]
+ ):
+ continue
+
+ found_routes = []
+ missing_routes = []
+ advertise_network = input_dict[routerInput]["bgp"]["address_family"][
+ addr_type
+ ]["unicast"]["advertise_networks"]
+
+ # Continue if there are no network advertise
+ if len(advertise_network) == 0:
+ continue
+
+ for advertise_network_dict in advertise_network:
+ if "vrf" in advertise_network_dict:
+ cmd = "{} vrf {} json".format(command, static_route["vrf"])
+ else:
+ cmd = "{} json".format(command)
+
+ rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ # Verifying output dictionary rib_routes_json is not empty
+ if bool(rib_routes_json) is False:
+ errormsg = "No route found in rib of router {}..".format(router)
+ return errormsg
+
+ start_ip = advertise_network_dict["network"]
+ if "no_of_network" in advertise_network_dict:
+ no_of_network = advertise_network_dict["no_of_network"]
+ else:
+ no_of_network = 1
+
+ # Generating IPs for verification
+ ip_list = generate_ips(start_ip, no_of_network)
+ st_found = False
+ nh_found = False
+
+ for st_rt in ip_list:
+ st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+
+ _addr_type = validate_ip_address(st_rt)
+ if _addr_type != addr_type:
+ continue
+
+ if st_rt in rib_routes_json:
+ st_found = True
+ found_routes.append(st_rt)
+
+ if next_hop:
+ if type(next_hop) is not list:
+ next_hop = [next_hop]
+
+ count = 0
+ for nh in next_hop:
+ for nh_dict in rib_routes_json[st_rt][0]["nexthops"]:
+ if nh_dict["ip"] != nh:
+ continue
+ else:
+ count += 1
+
+ if count == len(next_hop):
+ nh_found = True
+ else:
+ missing_routes.append(st_rt)
+ errormsg = (
+ "Nexthop {} is Missing"
+ " for route {} in "
+ "RIB of router {}\n".format(next_hop, st_rt, dut)
+ )
+ return errormsg
+ else:
+ missing_routes.append(st_rt)
+
+ if len(missing_routes) > 0:
+ errormsg = "[DUT: {}]: Missing route in FIB: " "{} \n".format(
+ dut, missing_routes
+ )
+ return errormsg
+
+ if nh_found:
+ logger.info(
+ "Found next_hop {} for all routes in RIB"
+ " of router {}\n".format(next_hop, dut)
+ )
+
+ if found_routes:
+ logger.info(
+ "[DUT: {}]: Verified routes FIB"
+ ", found routes are: {}\n".format(dut, found_routes)
+ )
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
def verify_admin_distance_for_static_routes(tgen, input_dict):
"""
API to verify admin distance for static routes as defined in input_dict/
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 766ab71ed1..8a40490be3 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -29,7 +29,6 @@ import re
import sys
import functools
import glob
-import StringIO
import subprocess
import tempfile
import platform
@@ -1013,12 +1012,9 @@ class Router(Node):
self.cmd("chown {0}:{0}vty /etc/{0}".format(self.routertype))
def terminate(self):
- # Delete Running Quagga or FRR Daemons
+ # Stop running FRR daemons
self.stopRouter()
- # rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype)
- # for d in StringIO.StringIO(rundaemons):
- # self.cmd('kill -7 `cat %s`' % d.rstrip())
- # self.waitOutput()
+
# Disable forwarding
set_sysctl(self, "net.ipv4.ip_forward", 0)
set_sysctl(self, "net.ipv6.conf.all.forwarding", 0)
@@ -1033,10 +1029,12 @@ class Router(Node):
if re.search(r"No such file or directory", rundaemons):
return 0
if rundaemons is not None:
- for d in StringIO.StringIO(rundaemons):
+ bet = rundaemons.split('\n')
+ for d in bet[:-1]:
daemonpid = self.cmd("cat %s" % d.rstrip()).rstrip()
if daemonpid.isdigit() and pid_exists(int(daemonpid)):
ret.append(os.path.basename(d.rstrip().rsplit(".", 1)[0]))
+
return ret
def stopRouter(self, wait=True, assertOnError=True, minErrorVersion="5.1"):
@@ -1046,7 +1044,9 @@ class Router(Node):
if re.search(r"No such file or directory", rundaemons):
return errors
if rundaemons is not None:
- for d in StringIO.StringIO(rundaemons):
+ dmns = rundaemons.split('\n')
+ # Exclude empty string at end of list
+ for d in dmns[:-1]:
daemonpid = self.cmd("cat %s" % d.rstrip()).rstrip()
if daemonpid.isdigit() and pid_exists(int(daemonpid)):
daemonname = os.path.basename(d.rstrip().rsplit(".", 1)[0])
@@ -1080,7 +1080,9 @@ class Router(Node):
if running:
# 2nd round of kill if daemons didn't exit
- for d in StringIO.StringIO(rundaemons):
+ dmns = rundaemons.split('\n')
+ # Exclude empty string at end of list
+ for d in dmns[:-1]:
daemonpid = self.cmd("cat %s" % d.rstrip()).rstrip()
if daemonpid.isdigit() and pid_exists(int(daemonpid)):
logger.info(
@@ -1330,7 +1332,9 @@ class Router(Node):
for daemon in daemons:
if rundaemons is not None and daemon in rundaemons:
numRunning = 0
- for d in StringIO.StringIO(rundaemons):
+ dmns = rundaemons.split('\n')
+ # Exclude empty string at end of list
+ for d in dmns[:-1]:
if re.search(r"%s" % daemon, d):
daemonpid = self.cmd("cat %s" % d.rstrip()).rstrip()
if daemonpid.isdigit() and pid_exists(int(daemonpid)):
@@ -1351,8 +1355,9 @@ class Router(Node):
self.name, daemon
),
)
+
# 2nd round of kill if daemons didn't exit
- for d in StringIO.StringIO(rundaemons):
+ for d in dmns[:-1]:
if re.search(r"%s" % daemon, d):
daemonpid = self.cmd("cat %s" % d.rstrip()).rstrip()
if daemonpid.isdigit() and pid_exists(
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 16c94b7482..ad0d4bf56b 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -1453,6 +1453,15 @@ void kernel_init(struct zebra_ns *zns)
if (ret < 0)
zlog_notice("Registration for extended dp ACK failed : %d %s",
errno, safe_strerror(errno));
+
+ /*
+ * Trim off the payload of the original netlink message in the
+ * acknowledgment. This option is available since Linux 4.2, so if
+ * setsockopt fails, ignore the error.
+ */
+ one = 1;
+ ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_CAP_ACK,
+ &one, sizeof(one));
#endif
/* Register kernel socket. */
@@ -1469,8 +1478,11 @@ void kernel_init(struct zebra_ns *zns)
zns->netlink_dplane.name, safe_strerror(errno), errno);
/* Set receive buffer size if it's set from command line */
- if (nl_rcvbufsize)
+ if (nl_rcvbufsize) {
netlink_recvbuf(&zns->netlink, nl_rcvbufsize);
+ netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize);
+ netlink_recvbuf(&zns->netlink_dplane, nl_rcvbufsize);
+ }
netlink_install_filter(zns->netlink.sock,
zns->netlink_cmd.snl.nl_pid,
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 029480eb4a..3c99ce29c3 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -1356,7 +1356,8 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es *es)
if (!(es->flags & ZEBRA_EVPNES_LOCAL))
return;
- es->flags &= ~ZEBRA_EVPNES_LOCAL;
+ es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP);
+
/* if there any local macs referring to the ES as dest we
* need to clear the static reference on them
*/
@@ -1613,9 +1614,13 @@ bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi)
es = zebra_evpn_es_find(esi);
if (!es) {
- es = zebra_evpn_es_new(esi);
- if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("auto es %s add on mac ref", es->esi_str);
+ /* If non-zero esi implicitly create a new ES */
+ if (memcmp(esi, zero_esi, sizeof(esi_t))) {
+ es = zebra_evpn_es_new(esi);
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("auto es %s add on mac ref",
+ es->esi_str);
+ }
}
return zebra_evpn_es_mac_ref_entry(mac, es);