From 06b1bc921ec95ede295383746ea10cc67086308a Mon Sep 17 00:00:00 2001 From: shahzad Iqbal Date: Tue, 29 Oct 2024 19:24:42 +0000 Subject: [PATCH 01/18] added changes to give vnet route precedence over BGP learnt route. --- orchagent/routeorch.cpp | 18 + orchagent/routeorch.h | 1 + orchagent/vnetorch.cpp | 42 +- tests/test_vnet.py | 1229 +-------------------------------------- tests/test_vnet2.py | 320 ++++++++++ tests/vnet_lib.py | 1226 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 1607 insertions(+), 1229 deletions(-) create mode 100644 tests/test_vnet2.py create mode 100644 tests/vnet_lib.py diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index b1508656b3..2195725a22 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -2607,6 +2607,24 @@ bool RouteOrch::removeRoutePost(const RouteBulkContext& ctx) return true; } +bool RouteOrch::removeRouteIfExists(const IpPrefix& prefix) +{ + // This function removes the route if it exists. + + string key = "ROUTE_TABLE:" + prefix.to_string(); + RouteBulkContext context(key, false); + context.ip_prefix = prefix; + context.vrf_id = gVirtualRouterId; + if (removeRoute(context)) + { + SWSS_LOG_INFO("Could not find the route with prefix %s", prefix.to_string().c_str()); + return true; + } + gRouteBulker.flush(); + return removeRoutePost(context); + +} + bool RouteOrch::createRemoteVtep(sai_object_id_t vrf_id, const NextHopKey &nextHop) { SWSS_LOG_ENTER(); diff --git a/orchagent/routeorch.h b/orchagent/routeorch.h index 577d966a26..d047c85e21 100644 --- a/orchagent/routeorch.h +++ b/orchagent/routeorch.h @@ -215,6 +215,7 @@ class RouteOrch : public Orch, public Subject const NextHopGroupKey getSyncdRouteNhgKey(sai_object_id_t vrf_id, const IpPrefix& ipPrefix); bool createFineGrainedNextHopGroup(sai_object_id_t &next_hop_group_id, vector &nhg_attrs); bool removeFineGrainedNextHopGroup(sai_object_id_t &next_hop_group_id); + bool removeRouteIfExists(const IpPrefix& prefix); void addLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix); void delLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix); diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index 5c482d726d..d56c44ab14 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -1147,6 +1147,7 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP } else { + gRouteOrch->removeRouteIfExists(ipPrefix); if (it_route == syncd_tunnel_routes_[vnet].end()) { route_status = add_route(vr_id, pfx, nh_id); @@ -2270,7 +2271,11 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) { continue; } - + // when we add the first nexthop to the route, we dont create a nexthop group, we call the updateTunnelRoute with NHG with one member. + // when adding the 2nd, 3rd ... members we create each NH using this create_next_hop_group_member call but give it the reference of next_hop_group_id. + // this way we dont have to update the route, the syncd does it by itself. we only call the updateTunnelRoute to add/remove when adding the route and + // removing it fully. + bool failed = false; if (state == SAI_BFD_SESSION_STATE_UP) { sai_object_id_t next_hop_group_member_id = SAI_NULL_OBJECT_ID; @@ -2322,10 +2327,30 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) { for (auto ip_pfx : syncd_nexthop_groups_[vnet][nexthops].tunnel_routes) { + // remove the bgp learnt routr first if any and then add the tunnel route. + if (!gRouteOrch->removeRouteIfExists(ip_pfx)) + { + SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", ip_pfx.to_string().c_str()); + failed = true; + break; + } string op = SET_COMMAND; - updateTunnelRoute(vnet, ip_pfx, nexthops, op); + SWSS_LOG_NOTICE("Adding Vnet route for prefix : %s with nexthops %s\n", + ip_pfx.to_string().c_str(), + nexthops.to_string().c_str()); + + if (!updateTunnelRoute(vnet, ip_pfx, nexthops, op)) + { + SWSS_LOG_NOTICE("Failed to create tunnel route in hardware for prefix : %s\n", ip_pfx.to_string().c_str()); + failed = true; + } } } + if (failed) + { + // This is an unrecoverable error, Throw a LOG_ERROR and return + SWSS_LOG_ERROR("Inconsistant Hardware State. Failed to create tunnel routes\n"); + } } else { @@ -2366,6 +2391,7 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) { for (auto ip_pfx : syncd_nexthop_groups_[vnet][nexthops].tunnel_routes) { + SWSS_LOG_NOTICE("Removing Vnet route for prefix : %s due to no nexthops.\n",ip_pfx.to_string().c_str()); string op = DEL_COMMAND; updateTunnelRoute(vnet, ip_pfx, nexthops, op); } @@ -2373,12 +2399,14 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) } } } - - // Post configured in State DB - for (auto ip_pfx : syncd_nexthop_groups_[vnet][nexthops].tunnel_routes) + if (!failed) { - string profile = vrf_obj->getProfile(ip_pfx); - postRouteState(vnet, ip_pfx, nexthops, profile); + // Post configured in State DB + for (auto ip_pfx : syncd_nexthop_groups_[vnet][nexthops].tunnel_routes) + { + string profile = vrf_obj->getProfile(ip_pfx); + postRouteState(vnet, ip_pfx, nexthops, profile); + } } } } diff --git a/tests/test_vnet.py b/tests/test_vnet.py index be08a52c69..75e9aeeabe 100644 --- a/tests/test_vnet.py +++ b/tests/test_vnet.py @@ -8,1222 +8,7 @@ from swsscommon import swsscommon from pprint import pprint from dvslib.dvs_common import wait_for_result - - -def create_entry(tbl, key, pairs): - fvs = swsscommon.FieldValuePairs(pairs) - tbl.set(key, fvs) - time.sleep(1) - - -def create_entry_tbl(db, table, separator, key, pairs): - tbl = swsscommon.Table(db, table) - create_entry(tbl, key, pairs) - - -def create_entry_pst(db, table, separator, key, pairs): - tbl = swsscommon.ProducerStateTable(db, table) - create_entry(tbl, key, pairs) - - -def delete_entry_tbl(db, table, key): - tbl = swsscommon.Table(db, table) - tbl._del(key) - time.sleep(1) - - -def delete_entry_pst(db, table, key): - tbl = swsscommon.ProducerStateTable(db, table) - tbl._del(key) - time.sleep(1) - - -def how_many_entries_exist(db, table): - tbl = swsscommon.Table(db, table) - return len(tbl.getKeys()) - - -def entries(db, table): - tbl = swsscommon.Table(db, table) - return set(tbl.getKeys()) - - -def get_exist_entries(dvs, table): - db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(db, table) - return set(tbl.getKeys()) - - -def get_created_entry(db, table, existed_entries): - tbl = swsscommon.Table(db, table) - entries = set(tbl.getKeys()) - new_entries = list(entries - existed_entries) - assert len(new_entries) == 1, "Wrong number of created entries." - return new_entries[0] - - -def get_all_created_entries(db, table, existed_entries): - tbl = swsscommon.Table(db, table) - entries = set(tbl.getKeys()) - new_entries = list(entries - set(existed_entries)) - assert len(new_entries) >= 0, "Get all could be no new created entries." - new_entries.sort() - return new_entries - - -def get_created_entries(db, table, existed_entries, count): - new_entries = get_all_created_entries(db, table, existed_entries) - assert len(new_entries) == count, "Wrong number of created entries." - return new_entries - - -def get_deleted_entries(db, table, existed_entries, count): - tbl = swsscommon.Table(db, table) - entries = set(tbl.getKeys()) - old_entries = list(existed_entries - entries) - assert len(old_entries) == count, "Wrong number of deleted entries." - old_entries.sort() - return old_entries - - -def get_default_vr_id(dvs): - db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - table = 'ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER' - tbl = swsscommon.Table(db, table) - keys = tbl.getKeys() - assert len(keys) == 1, "Wrong number of virtual routers found" - - return keys[0] - - -def check_object(db, table, key, expected_attributes): - tbl = swsscommon.Table(db, table) - keys = tbl.getKeys() - assert key in keys, "The desired key is not presented" - - status, fvs = tbl.get(key) - assert status, "Got an error when get a key" - - assert len(fvs) >= len(expected_attributes), "Incorrect attributes" - - attr_keys = {entry[0] for entry in fvs} - - for name, value in fvs: - if name in expected_attributes: - assert expected_attributes[name] == value, "Wrong value %s for the attribute %s = %s" % \ - (value, name, expected_attributes[name]) - -def check_deleted_object(db, table, key): - tbl = swsscommon.Table(db, table) - keys = tbl.getKeys() - assert key not in keys, "The desired key is not removed" - - -def create_vnet_local_routes(dvs, prefix, vnet_name, ifname): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - create_entry_tbl( - conf_db, - "VNET_ROUTE", '|', "%s|%s" % (vnet_name, prefix), - [ - ("ifname", ifname), - ] - ) - - time.sleep(2) - - -def delete_vnet_local_routes(dvs, prefix, vnet_name): - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - - delete_entry_pst(app_db, "VNET_ROUTE_TABLE", "%s:%s" % (vnet_name, prefix)) - - time.sleep(2) - - -def create_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor="", profile="", primary="", monitoring="", adv_prefix=""): - set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac=mac, vni=vni, ep_monitor=ep_monitor, profile=profile, primary=primary, monitoring=monitoring, adv_prefix=adv_prefix) - - -def set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor="", profile="", primary="", monitoring="", adv_prefix=""): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("endpoint", endpoint), - ] - - if vni: - attrs.append(('vni', vni)) - - if mac: - attrs.append(('mac_address', mac)) - - if ep_monitor: - attrs.append(('endpoint_monitor', ep_monitor)) - - if profile: - attrs.append(('profile', profile)) - - if primary: - attrs.append(('primary', primary)) - - if monitoring: - attrs.append(('monitoring', monitoring)) - - if adv_prefix: - attrs.append(('adv_prefix', adv_prefix)) - - tbl = swsscommon.Table(conf_db, "VNET_ROUTE_TUNNEL") - fvs = swsscommon.FieldValuePairs(attrs) - tbl.set("%s|%s" % (vnet_name, prefix), fvs) - - time.sleep(2) - - -def delete_vnet_routes(dvs, prefix, vnet_name): - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - - delete_entry_pst(app_db, "VNET_ROUTE_TUNNEL_TABLE", "%s:%s" % (vnet_name, prefix)) - - time.sleep(2) - - -def create_vlan(dvs, vlan_name, vlan_ids): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - vlan_id = vlan_name[4:] - - # create vlan - create_entry_tbl( - conf_db, - "VLAN", '|', vlan_name, - [ - ("vlanid", vlan_id), - ], - ) - - time.sleep(1) - - vlan_oid = get_created_entry(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN", vlan_ids) - - check_object(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN", vlan_oid, - { - "SAI_VLAN_ATTR_VLAN_ID": vlan_id, - } - ) - - return vlan_oid - - -def create_vlan_interface(dvs, vlan_name, ifname, vnet_name, ipaddr): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - vlan_ids = get_exist_entries(dvs, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") - - vlan_oid = create_vlan (dvs, vlan_name, vlan_ids) - - # create a vlan member in config db - create_entry_tbl( - conf_db, - "VLAN_MEMBER", '|', "%s|%s" % (vlan_name, ifname), - [ - ("tagging_mode", "untagged"), - ], - ) - - time.sleep(1) - - # create vlan interface in config db - create_entry_tbl( - conf_db, - "VLAN_INTERFACE", '|', vlan_name, - [ - ("vnet_name", vnet_name), - ("proxy_arp", "enabled"), - ], - ) - - #FIXME - This is created by IntfMgr - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - create_entry_pst( - app_db, - "INTF_TABLE", ':', vlan_name, - [ - ("vnet_name", vnet_name), - ("proxy_arp", "enabled"), - ], - ) - time.sleep(2) - - create_entry_tbl( - conf_db, - "VLAN_INTERFACE", '|', "%s|%s" % (vlan_name, ipaddr), - [ - ("family", "IPv4"), - ], - ) - - time.sleep(2) - - return vlan_oid - - -def delete_vlan_interface(dvs, ifname, ipaddr): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - delete_entry_tbl(conf_db, "VLAN_INTERFACE", "%s|%s" % (ifname, ipaddr)) - - time.sleep(2) - - delete_entry_tbl(conf_db, "VLAN_INTERFACE", ifname) - - time.sleep(2) - - -def create_phy_interface(dvs, ifname, vnet_name, ipaddr): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - exist_rifs = get_exist_entries(dvs, "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE") - - # create vlan interface in config db - create_entry_tbl( - conf_db, - "INTERFACE", '|', ifname, - [ - ("vnet_name", vnet_name), - ], - ) - - #FIXME - This is created by IntfMgr - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - create_entry_pst( - app_db, - "INTF_TABLE", ':', ifname, - [ - ("vnet_name", vnet_name), - ], - ) - time.sleep(2) - - create_entry_tbl( - conf_db, - "INTERFACE", '|', "%s|%s" % (ifname, ipaddr), - [ - ("family", "IPv4"), - ], - ) - - -def delete_phy_interface(dvs, ifname, ipaddr): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - delete_entry_tbl(conf_db, "INTERFACE", "%s|%s" % (ifname, ipaddr)) - - time.sleep(2) - - delete_entry_tbl(conf_db, "INTERFACE", ifname) - - time.sleep(2) - - -def create_vnet_entry(dvs, name, tunnel, vni, peer_list, scope="", advertise_prefix=False, overlay_dmac=""): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - attrs = [ - ("vxlan_tunnel", tunnel), - ("vni", vni), - ("peer_list", peer_list), - ] - - if scope: - attrs.append(('scope', scope)) - - if advertise_prefix: - attrs.append(('advertise_prefix', 'true')) - - if overlay_dmac: - attrs.append(('overlay_dmac', overlay_dmac)) - - # create the VXLAN tunnel Term entry in Config DB - create_entry_tbl( - conf_db, - "VNET", '|', name, - attrs, - ) - - time.sleep(2) - - -def delete_vnet_entry(dvs, name): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - delete_entry_tbl(conf_db, "VNET", "%s" % (name)) - - time.sleep(2) - - -def create_vxlan_tunnel(dvs, name, src_ip): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("src_ip", src_ip), - ] - - # create the VXLAN tunnel Term entry in Config DB - create_entry_tbl( - conf_db, - "VXLAN_TUNNEL", '|', name, - attrs, - ) - -def delete_vxlan_tunnel(dvs, name): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - delete_entry_tbl(conf_db, "VXLAN_TUNNEL", name) - -def create_vxlan_tunnel_map(dvs, tunnel_name, tunnel_map_entry_name, vlan, vni_id): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - # create the VXLAN tunnel map entry in Config DB - create_entry_tbl( - conf_db, - "VXLAN_TUNNEL_MAP", '|', "%s|%s" % (tunnel_name, tunnel_map_entry_name), - [ - ("vni", vni_id), - ("vlan", vlan), - ], - ) - - -def get_lo(dvs): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - vr_id = get_default_vr_id(dvs) - - tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE') - - entries = tbl.getKeys() - lo_id = None - for entry in entries: - status, fvs = tbl.get(entry) - assert status, "Got an error when get a key" - for key, value in fvs: - if key == 'SAI_ROUTER_INTERFACE_ATTR_TYPE' and value == 'SAI_ROUTER_INTERFACE_TYPE_LOOPBACK': - lo_id = entry - break - else: - assert False, 'Don\'t found loopback id' - - return lo_id - - -def get_switch_mac(dvs): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_SWITCH') - - entries = tbl.getKeys() - mac = None - for entry in entries: - status, fvs = tbl.get(entry) - assert status, "Got an error when get a key" - for key, value in fvs: - if key == 'SAI_SWITCH_ATTR_SRC_MAC_ADDRESS': - mac = value - break - else: - assert False, 'Don\'t found switch mac' - - return mac - - -def check_linux_intf_arp_proxy(dvs, ifname): - (exitcode, out) = dvs.runcmd("cat /proc/sys/net/ipv4/conf/{0}/proxy_arp_pvlan".format(ifname)) - assert out != "1", "ARP proxy is not enabled for VNET interface in Linux kernel" - - -def update_bfd_session_state(dvs, addr, state): - bfd_id = get_bfd_session_id(dvs, addr) - assert bfd_id is not None - - bfd_sai_state = {"Admin_Down": "SAI_BFD_SESSION_STATE_ADMIN_DOWN", - "Down": "SAI_BFD_SESSION_STATE_DOWN", - "Init": "SAI_BFD_SESSION_STATE_INIT", - "Up": "SAI_BFD_SESSION_STATE_UP"} - - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - ntf = swsscommon.NotificationProducer(asic_db, "NOTIFICATIONS") - fvp = swsscommon.FieldValuePairs() - ntf_data = "[{\"bfd_session_id\":\""+bfd_id+"\",\"session_state\":\""+bfd_sai_state[state]+"\"}]" - ntf.send("bfd_session_state_change", ntf_data, fvp) - -def update_monitor_session_state(dvs, addr, monitor, state): - state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) - create_entry_tbl( - state_db, - "VNET_MONITOR_TABLE", '|', "%s|%s" % (monitor,addr), - [ - ("state", state), - ] - ) - -def get_bfd_session_id(dvs, addr): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_BFD_SESSION") - entries = set(tbl.getKeys()) - for entry in entries: - status, fvs = tbl.get(entry) - fvs = dict(fvs) - assert status, "Got an error when get a key" - if fvs["SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS"] == addr and fvs["SAI_BFD_SESSION_ATTR_MULTIHOP"] == "true": - return entry - - return None - - -def check_del_bfd_session(dvs, addrs): - for addr in addrs: - assert get_bfd_session_id(dvs, addr) is None - - -def check_bfd_session(dvs, addrs): - for addr in addrs: - assert get_bfd_session_id(dvs, addr) is not None - - -def check_state_db_routes(dvs, vnet, prefix, endpoints): - state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(state_db, "VNET_ROUTE_TUNNEL_TABLE") - - status, fvs = tbl.get(vnet + '|' + prefix) - assert status, "Got an error when get a key" - - fvs = dict(fvs) - assert fvs['active_endpoints'] == ','.join(endpoints) - - if endpoints: - assert fvs['state'] == 'active' - else: - assert fvs['state'] == 'inactive' - - -def check_remove_state_db_routes(dvs, vnet, prefix): - state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(state_db, "VNET_ROUTE_TUNNEL_TABLE") - keys = tbl.getKeys() - - assert vnet + '|' + prefix not in keys - - -def check_routes_advertisement(dvs, prefix, profile=""): - state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(state_db, "ADVERTISE_NETWORK_TABLE") - keys = tbl.getKeys() - - assert prefix in keys - - if profile: - status, fvs = tbl.get(prefix) - assert status, "Got an error when get a key" - fvs = dict(fvs) - assert fvs['profile'] == profile - - -def check_remove_routes_advertisement(dvs, prefix): - state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(state_db, "ADVERTISE_NETWORK_TABLE") - keys = tbl.getKeys() - - assert prefix not in keys - - -def check_syslog(dvs, marker, err_log): - (exitcode, num) = dvs.runcmd(['sh', '-c', "awk \'/%s/,ENDFILE {print;}\' /var/log/syslog | grep \"%s\" | wc -l" % (marker, err_log)]) - assert num.strip() == "0" - - -def create_fvs(**kwargs): - return swsscommon.FieldValuePairs(list(kwargs.items())) - - -def create_subnet_decap_tunnel(dvs, tunnel_name, **kwargs): - """Create tunnel and verify all needed entries in state DB exists.""" - appdb = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - statedb = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) - fvs = create_fvs(**kwargs) - # create tunnel entry in DB - ps = swsscommon.ProducerStateTable(appdb, "TUNNEL_DECAP_TABLE") - ps.set(tunnel_name, fvs) - - # wait till config will be applied - time.sleep(1) - - # validate the tunnel entry in state db - tunnel_state_table = swsscommon.Table(statedb, "TUNNEL_DECAP_TABLE") - - tunnels = tunnel_state_table.getKeys() - for tunnel in tunnels: - status, fvs = tunnel_state_table.get(tunnel) - assert status == True - - for field, value in fvs: - if field == "tunnel_type": - assert value == "IPINIP" - elif field == "dscp_mode": - assert value == kwargs["dscp_mode"] - elif field == "ecn_mode": - assert value == kwargs["ecn_mode"] - elif field == "ttl_mode": - assert value == kwargs["ttl_mode"] - elif field == "encap_ecn_mode": - assert value == kwargs["encap_ecn_mode"] - else: - assert False, "Field %s is not tested" % field - - -def delete_subnet_decap_tunnel(dvs, tunnel_name): - """Delete tunnel and checks that state DB is cleared.""" - appdb = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - statedb = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) - tunnel_app_table = swsscommon.Table(appdb, "TUNNEL_DECAP_TABLE") - tunnel_state_table = swsscommon.Table(statedb, "TUNNEL_DECAP_TABLE") - - ps = swsscommon.ProducerStateTable(appdb, "TUNNEL_DECAP_TABLE") - ps._del(tunnel_name) - - # wait till config will be applied - time.sleep(1) - - assert len(tunnel_app_table.getKeys()) == 0 - assert len(tunnel_state_table.getKeys()) == 0 - - -loopback_id = 0 -def_vr_id = 0 -switch_mac = None - -def update_bgp_global_dev_state(dvs, state): - config_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - create_entry_tbl( - config_db, - "BGP_DEVICE_GLOBAL",'|',"STATE", - [ - ("tsa_enabled", state), - ] - ) - -def set_tsa(dvs): - update_bgp_global_dev_state(dvs, "true") - -def clear_tsa(dvs): - update_bgp_global_dev_state(dvs, "false") - -class VnetVxlanVrfTunnel(object): - - ASIC_TUNNEL_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL" - ASIC_TUNNEL_MAP = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP" - ASIC_TUNNEL_MAP_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY" - ASIC_TUNNEL_TERM_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY" - ASIC_RIF_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE" - ASIC_VRF_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER" - ASIC_ROUTE_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY" - ASIC_NEXT_HOP = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP" - ASIC_VLAN_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_VLAN" - ASIC_NEXT_HOP_GROUP = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP" - ASIC_NEXT_HOP_GROUP_MEMBER = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER" - ASIC_BFD_SESSION = "ASIC_STATE:SAI_OBJECT_TYPE_BFD_SESSION" - APP_VNET_MONITOR = "VNET_MONITOR_TABLE" - - ecn_modes_map = { - "standard" : "SAI_TUNNEL_DECAP_ECN_MODE_STANDARD", - "copy_from_outer": "SAI_TUNNEL_DECAP_ECN_MODE_COPY_FROM_OUTER" - } - - dscp_modes_map = { - "pipe" : "SAI_TUNNEL_DSCP_MODE_PIPE_MODEL", - "uniform" : "SAI_TUNNEL_DSCP_MODE_UNIFORM_MODEL" - } - - ttl_modes_map = { - "pipe" : "SAI_TUNNEL_TTL_MODE_PIPE_MODEL", - "uniform" : "SAI_TUNNEL_TTL_MODE_UNIFORM_MODEL" - } - - def __init__(self): - self.tunnel_map_ids = set() - self.tunnel_map_entry_ids = set() - self.tunnel_ids = set() - self.tunnel_term_ids = set() - self.ipinip_tunnel_term_ids = {} - self.tunnel_map_map = {} - self.tunnel = {} - self.vnet_vr_ids = set() - self.vr_map = {} - self.nh_ids = {} - self.nhg_ids = {} - - def fetch_exist_entries(self, dvs): - self.vnet_vr_ids = get_exist_entries(dvs, self.ASIC_VRF_TABLE) - self.tunnel_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_TABLE) - self.tunnel_map_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_MAP) - self.tunnel_map_entry_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_MAP_ENTRY) - self.tunnel_term_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_TERM_ENTRY) - self.rifs = get_exist_entries(dvs, self.ASIC_RIF_TABLE) - self.routes = get_exist_entries(dvs, self.ASIC_ROUTE_ENTRY) - self.nhops = get_exist_entries(dvs, self.ASIC_NEXT_HOP) - self.nhgs = get_exist_entries(dvs, self.ASIC_NEXT_HOP_GROUP) - self.bfd_sessions = get_exist_entries(dvs, self.ASIC_BFD_SESSION) - - global loopback_id, def_vr_id, switch_mac - if not loopback_id: - loopback_id = get_lo(dvs) - - if not def_vr_id: - def_vr_id = get_default_vr_id(dvs) - - if switch_mac is None: - switch_mac = get_switch_mac(dvs) - - def check_ipinip_tunnel(self, dvs, tunnel_name, dscp_mode, ecn_mode, ttl_mode): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tunnel_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TABLE, self.tunnel_ids) - tunnel_attrs = { - 'SAI_TUNNEL_ATTR_TYPE': 'SAI_TUNNEL_TYPE_IPINIP', - 'SAI_TUNNEL_ATTR_ENCAP_DSCP_MODE': self.dscp_modes_map[dscp_mode], - 'SAI_TUNNEL_ATTR_ENCAP_ECN_MODE': self.ecn_modes_map[ecn_mode], - 'SAI_TUNNEL_ATTR_ENCAP_TTL_MODE': self.ttl_modes_map[ttl_mode] - } - check_object(asic_db, self.ASIC_TUNNEL_TABLE, tunnel_id, tunnel_attrs) - - self.tunnel_ids.add(tunnel_id) - self.tunnel[tunnel_name] = tunnel_id - - def check_del_ipinip_tunnel(self, dvs, tunnel_name): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tunnel_id = get_deleted_entries(asic_db, self.ASIC_TUNNEL_TABLE, self.tunnel_ids, 1)[0] - check_deleted_object(asic_db, self.ASIC_TUNNEL_TABLE, tunnel_id) - self.tunnel_ids.remove(tunnel_id) - assert tunnel_id == self.tunnel[tunnel_name] - self.tunnel.pop(tunnel_name) - - def check_ipinip_tunnel_decap_term(self, dvs, tunnel_name, dst_ip, src_ip): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - dst_ip = ipaddress.ip_network(dst_ip) - src_ip = ipaddress.ip_network(src_ip) - tunnel_term_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, self.tunnel_term_ids) - tunnel_term_attrs = { - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE': 'SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_MP2MP', - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE': 'SAI_TUNNEL_TYPE_IPINIP', - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP': str(dst_ip.network_address), - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP_MASK': str(dst_ip.netmask), - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_SRC_IP': str(src_ip.network_address), - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_SRC_IP_MASK': str(src_ip.netmask), - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID': self.tunnel[tunnel_name] - } - check_object(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, tunnel_term_id, tunnel_term_attrs) - - self.tunnel_term_ids.add(tunnel_term_id) - self.ipinip_tunnel_term_ids[(tunnel_name, src_ip, dst_ip)] = tunnel_term_id - - def check_del_ipinip_tunnel_decap_term(self, dvs, tunnel_name, dst_ip, src_ip): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - dst_ip = ipaddress.ip_network(dst_ip) - src_ip = ipaddress.ip_network(src_ip) - tunnel_term_id = get_deleted_entries(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, self.tunnel_term_ids, 1)[0] - check_deleted_object(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, tunnel_term_id) - self.tunnel_term_ids.remove(tunnel_term_id) - assert self.ipinip_tunnel_term_ids[(tunnel_name, src_ip, dst_ip)] == tunnel_term_id - self.ipinip_tunnel_term_ids.pop((tunnel_name, src_ip, dst_ip)) - - def check_vxlan_tunnel(self, dvs, tunnel_name, src_ip): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - global loopback_id, def_vr_id - - tunnel_map_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 4) - tunnel_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TABLE, self.tunnel_ids) - tunnel_term_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, self.tunnel_term_ids) - - # check that the vxlan tunnel termination are there - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP) == (len(self.tunnel_map_ids) + 4), "The TUNNEL_MAP wasn't created" - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) == len(self.tunnel_map_entry_ids), "The TUNNEL_MAP_ENTRY is created" - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_TABLE) == (len(self.tunnel_ids) + 1), "The TUNNEL wasn't created" - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_TERM_ENTRY) == (len(self.tunnel_term_ids) + 1), "The TUNNEL_TERM_TABLE_ENTRY wasm't created" - - check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[2], - { - 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID', - } - ) - - check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[3], - { - 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI', - } - ) - - check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[0], - { - 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VLAN_ID', - } - ) - - check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[1], - { - 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VLAN_ID_TO_VNI', - } - ) - - check_object(asic_db, self.ASIC_TUNNEL_TABLE, tunnel_id, - { - 'SAI_TUNNEL_ATTR_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', - 'SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE': loopback_id, - 'SAI_TUNNEL_ATTR_DECAP_MAPPERS': '2:%s,%s' % (tunnel_map_id[0], tunnel_map_id[2]), - 'SAI_TUNNEL_ATTR_ENCAP_MAPPERS': '2:%s,%s' % (tunnel_map_id[1], tunnel_map_id[3]), - 'SAI_TUNNEL_ATTR_ENCAP_SRC_IP': src_ip, - } - ) - - expected_attributes = { - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE': 'SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2MP', - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_VR_ID': def_vr_id, - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP': src_ip, - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID': tunnel_id, - } - - check_object(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, tunnel_term_id, expected_attributes) - - self.tunnel_map_ids.update(tunnel_map_id) - self.tunnel_ids.add(tunnel_id) - self.tunnel_term_ids.add(tunnel_term_id) - self.tunnel_map_map[tunnel_name] = tunnel_map_id - self.tunnel[tunnel_name] = tunnel_id - - def check_del_vxlan_tunnel(self, dvs): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - old_tunnel = get_deleted_entries(asic_db, self.ASIC_TUNNEL_TABLE, self.tunnel_ids, 1) - check_deleted_object(asic_db, self.ASIC_TUNNEL_TABLE, old_tunnel[0]) - self.tunnel_ids.remove(old_tunnel[0]) - - old_tunnel_maps = get_deleted_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 4) - for old_tunnel_map in old_tunnel_maps: - check_deleted_object(asic_db, self.ASIC_TUNNEL_MAP, old_tunnel_map) - self.tunnel_map_ids.remove(old_tunnel_map) - - def check_vxlan_tunnel_entry(self, dvs, tunnel_name, vnet_name, vni_id): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - - time.sleep(2) - - if (self.tunnel_map_map.get(tunnel_name) is None): - tunnel_map_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 4) - else: - tunnel_map_id = self.tunnel_map_map[tunnel_name] - - tunnel_map_entry_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, self.tunnel_map_entry_ids, 2) - - # check that the vxlan tunnel termination are there - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) == (len(self.tunnel_map_entry_ids) + 2), "The TUNNEL_MAP_ENTRY is created too early" - - check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[0], - { - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI', - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[3], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_KEY': self.vr_map[vnet_name].get('ing'), - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_VALUE': vni_id, - } - ) - - check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[1], - { - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID', - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[2], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vni_id, - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_VALUE': self.vr_map[vnet_name].get('egr'), - } - ) - - self.tunnel_map_entry_ids.update(tunnel_map_entry_id) - - def check_vnet_entry(self, dvs, name, peer_list=[]): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - - #Assert if there are linklocal entries - tbl = swsscommon.Table(app_db, "VNET_ROUTE_TUNNEL_TABLE") - route_entries = tbl.getKeys() - assert "ff00::/8" not in route_entries - assert "fe80::/64" not in route_entries - - #Check virtual router objects - assert how_many_entries_exist(asic_db, self.ASIC_VRF_TABLE) == (len(self.vnet_vr_ids) + 1),\ - "The VR objects are not created" - - new_vr_ids = get_created_entries(asic_db, self.ASIC_VRF_TABLE, self.vnet_vr_ids, 1) - - self.vnet_vr_ids.update(new_vr_ids) - self.vr_map[name] = { 'ing':new_vr_ids[0], 'egr':new_vr_ids[0], 'peer':peer_list } - - def check_default_vnet_entry(self, dvs, name): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - #Check virtual router objects - assert how_many_entries_exist(asic_db, self.ASIC_VRF_TABLE) == (len(self.vnet_vr_ids)),\ - "Some VR objects are created" - #Mappers for default VNET is created with default VR objects. - self.vr_map[name] = { 'ing':list(self.vnet_vr_ids)[0], 'egr':list(self.vnet_vr_ids)[0], 'peer':[] } - - def check_del_vnet_entry(self, dvs, name): - # TODO: Implement for VRF VNET - return True - - def vnet_route_ids(self, dvs, name, local=False): - vr_set = set() - - vr_set.add(self.vr_map[name].get('ing')) - - try: - for peer in self.vr_map[name].get('peer'): - vr_set.add(self.vr_map[peer].get('ing')) - except IndexError: - pass - - return vr_set - - def check_router_interface(self, dvs, intf_name, name, vlan_oid=0): - # Check RIF in ingress VRF - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - global switch_mac - - expected_attr = { - "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": self.vr_map[name].get('ing'), - "SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS": switch_mac, - "SAI_ROUTER_INTERFACE_ATTR_MTU": "9100", - } - - if vlan_oid: - expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_TYPE': 'SAI_ROUTER_INTERFACE_TYPE_VLAN'}) - expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_VLAN_ID': vlan_oid}) - else: - expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_TYPE': 'SAI_ROUTER_INTERFACE_TYPE_PORT'}) - - new_rif = get_created_entry(asic_db, self.ASIC_RIF_TABLE, self.rifs) - check_object(asic_db, self.ASIC_RIF_TABLE, new_rif, expected_attr) - - #IP2ME route will be created with every router interface - new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, 1) - - if vlan_oid: - expected_attr = { 'SAI_VLAN_ATTR_BROADCAST_FLOOD_CONTROL_TYPE': 'SAI_VLAN_FLOOD_CONTROL_TYPE_NONE' } - check_object(asic_db, self.ASIC_VLAN_TABLE, vlan_oid, expected_attr) - - expected_attr = { 'SAI_VLAN_ATTR_UNKNOWN_MULTICAST_FLOOD_CONTROL_TYPE': 'SAI_VLAN_FLOOD_CONTROL_TYPE_NONE' } - check_object(asic_db, self.ASIC_VLAN_TABLE, vlan_oid, expected_attr) - - check_linux_intf_arp_proxy(dvs, intf_name) - - self.rifs.add(new_rif) - self.routes.update(new_route) - - def check_del_router_interface(self, dvs, name): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - old_rif = get_deleted_entries(asic_db, self.ASIC_RIF_TABLE, self.rifs, 1) - check_deleted_object(asic_db, self.ASIC_RIF_TABLE, old_rif[0]) - - self.rifs.remove(old_rif[0]) - - def check_vnet_local_routes(self, dvs, name): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - vr_ids = self.vnet_route_ids(dvs, name, True) - count = len(vr_ids) - - new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) - - #Routes are not replicated to egress VRF, return if count is 0, else check peering - if not count: - return - - asic_vrs = set() - for idx in range(count): - rt_key = json.loads(new_route[idx]) - asic_vrs.add(rt_key['vr']) - - assert asic_vrs == vr_ids - - self.routes.update(new_route) - - def check_del_vnet_local_routes(self, dvs, name): - # TODO: Implement for VRF VNET - return True - - def check_vnet_routes(self, dvs, name, endpoint, tunnel, mac="", vni=0, route_ids=""): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - vr_ids = self.vnet_route_ids(dvs, name) - count = len(vr_ids) - - # Check routes in ingress VRF - expected_attr = { - "SAI_NEXT_HOP_ATTR_TYPE": "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP", - "SAI_NEXT_HOP_ATTR_IP": endpoint, - "SAI_NEXT_HOP_ATTR_TUNNEL_ID": self.tunnel[tunnel], - } - - if vni: - expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_VNI': vni}) - - if mac: - expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_MAC': mac}) - - if endpoint in self.nh_ids: - new_nh = self.nh_ids[endpoint] - else: - new_nh = get_created_entry(asic_db, self.ASIC_NEXT_HOP, self.nhops) - self.nh_ids[endpoint] = new_nh - self.nhops.add(new_nh) - - check_object(asic_db, self.ASIC_NEXT_HOP, new_nh, expected_attr) - if not route_ids: - new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) - else: - new_route = route_ids - - #Check if the route is in expected VRF - asic_vrs = set() - for idx in range(count): - check_object(asic_db, self.ASIC_ROUTE_ENTRY, new_route[idx], - { - "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": new_nh, - } - ) - rt_key = json.loads(new_route[idx]) - asic_vrs.add(rt_key['vr']) - - assert asic_vrs == vr_ids - - self.routes.update(new_route) - - return new_route - - def serialize_endpoint_group(self, endpoints): - endpoints.sort() - return ",".join(endpoints) - - def check_next_hop_group_member(self, dvs, nhg, ordered_ecmp, expected_endpoint, expected_attrs): - expected_endpoint_str = self.serialize_endpoint_group(expected_endpoint) - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - tbl_nhgm = swsscommon.Table(asic_db, self.ASIC_NEXT_HOP_GROUP_MEMBER) - tbl_nh = swsscommon.Table(asic_db, self.ASIC_NEXT_HOP) - entries = set(tbl_nhgm.getKeys()) - endpoints = [] - for entry in entries: - status, fvs = tbl_nhgm.get(entry) - fvs = dict(fvs) - assert status, "Got an error when get a key" - if fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID"] == nhg: - nh_key = fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID"] - status, nh_fvs = tbl_nh.get(nh_key) - nh_fvs = dict(nh_fvs) - assert status, "Got an error when get a key" - endpoint = nh_fvs["SAI_NEXT_HOP_ATTR_IP"] - endpoints.append(endpoint) - assert endpoint in expected_attrs - if ordered_ecmp == "true": - assert fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_SEQUENCE_ID"] == expected_attrs[endpoint]['SAI_NEXT_HOP_GROUP_MEMBER_ATTR_SEQUENCE_ID'] - del expected_attrs[endpoint]['SAI_NEXT_HOP_GROUP_MEMBER_ATTR_SEQUENCE_ID'] - else: - assert fvs.get("SAI_NEXT_HOP_GROUP_MEMBER_ATTR_SEQUENCE_ID") is None - - check_object(asic_db, self.ASIC_NEXT_HOP, nh_key, expected_attrs[endpoint]) - - assert self.serialize_endpoint_group(endpoints) == expected_endpoint_str - - def get_nexthop_groups(self, dvs, nhg): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - tbl_nhgm = swsscommon.Table(asic_db, self.ASIC_NEXT_HOP_GROUP_MEMBER) - tbl_nh = swsscommon.Table(asic_db, self.ASIC_NEXT_HOP) - nhg_data = {} - nhg_data['id'] = nhg - entries = set(tbl_nhgm.getKeys()) - nhg_data['endpoints'] = [] - for entry in entries: - status, fvs = tbl_nhgm.get(entry) - fvs = dict(fvs) - assert status, "Got an error when get a key" - if fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID"] == nhg: - nh_key = fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID"] - status, nh_fvs = tbl_nh.get(nh_key) - nh_fvs = dict(nh_fvs) - assert status, "Got an error when get a key" - endpoint = nh_fvs["SAI_NEXT_HOP_ATTR_IP"] - nhg_data['endpoints'].append(endpoint) - return nhg_data - def check_vnet_ecmp_routes(self, dvs, name, endpoints, tunnel, mac=[], vni=[], route_ids=[], nhg="", ordered_ecmp="false", nh_seq_id=None): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - endpoint_str = name + "|" + self.serialize_endpoint_group(endpoints) - - vr_ids = self.vnet_route_ids(dvs, name) - count = len(vr_ids) - - expected_attrs = {} - for idx, endpoint in enumerate(endpoints): - expected_attr = { - "SAI_NEXT_HOP_ATTR_TYPE": "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP", - "SAI_NEXT_HOP_ATTR_IP": endpoint, - "SAI_NEXT_HOP_ATTR_TUNNEL_ID": self.tunnel[tunnel], - } - if vni and vni[idx]: - expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_VNI': vni[idx]}) - if mac and mac[idx]: - expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_MAC': mac[idx]}) - if ordered_ecmp == "true" and nh_seq_id: - expected_attr.update({'SAI_NEXT_HOP_GROUP_MEMBER_ATTR_SEQUENCE_ID': nh_seq_id[idx]}) - expected_attrs[endpoint] = expected_attr - - if nhg: - new_nhg = nhg - elif endpoint_str in self.nhg_ids: - new_nhg = self.nhg_ids[endpoint_str] - else: - new_nhg = get_created_entry(asic_db, self.ASIC_NEXT_HOP_GROUP, self.nhgs) - self.nhg_ids[endpoint_str] = new_nhg - self.nhgs.add(new_nhg) - - - # Check routes in ingress VRF - expected_nhg_attr = { - "SAI_NEXT_HOP_GROUP_ATTR_TYPE": "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP" if ordered_ecmp == "false" else "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_ORDERED_ECMP", - } - check_object(asic_db, self.ASIC_NEXT_HOP_GROUP, new_nhg, expected_nhg_attr) - - # Check nexthop group member - self.check_next_hop_group_member(dvs, new_nhg, ordered_ecmp, endpoints, expected_attrs) - - if route_ids: - new_route = route_ids - else: - new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) - - #Check if the route is in expected VRF - asic_vrs = set() - for idx in range(count): - check_object(asic_db, self.ASIC_ROUTE_ENTRY, new_route[idx], - { - "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": new_nhg, - } - ) - rt_key = json.loads(new_route[idx]) - asic_vrs.add(rt_key['vr']) - - assert asic_vrs == vr_ids - - self.routes.update(new_route) - - return new_route, new_nhg - - def check_priority_vnet_ecmp_routes(self, dvs, name, endpoints_primary, tunnel, mac=[], vni=[], route_ids=[], count =1, prefix =""): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - endpoint_str_primary = name + "|" + self.serialize_endpoint_group(endpoints_primary) - new_nhgs = [] - expected_attrs_primary = {} - for idx, endpoint in enumerate(endpoints_primary): - expected_attr = { - "SAI_NEXT_HOP_ATTR_TYPE": "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP", - "SAI_NEXT_HOP_ATTR_IP": endpoint, - "SAI_NEXT_HOP_ATTR_TUNNEL_ID": self.tunnel[tunnel], - } - if vni and vni[idx]: - expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_VNI': vni[idx]}) - if mac and mac[idx]: - expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_MAC': mac[idx]}) - expected_attrs_primary[endpoint] = expected_attr - - if len(endpoints_primary) == 1: - if route_ids: - new_route = route_ids - else: - new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) - return new_route - else : - new_nhgs = get_all_created_entries(asic_db, self.ASIC_NEXT_HOP_GROUP, self.nhgs) - found_match = False - - for nhg in new_nhgs: - nhg_data = self.get_nexthop_groups(dvs, nhg) - eplist = self.serialize_endpoint_group(nhg_data['endpoints']) - if eplist == self.serialize_endpoint_group(endpoints_primary): - self.nhg_ids[endpoint_str_primary] = nhg - found_match = True - - assert found_match, "the expected Nexthop group was not found." - - # Check routes in ingress VRF - expected_nhg_attr = { - "SAI_NEXT_HOP_GROUP_ATTR_TYPE": "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP", - } - for nhg in new_nhgs: - check_object(asic_db, self.ASIC_NEXT_HOP_GROUP, nhg, expected_nhg_attr) - - # Check nexthop group member - self.check_next_hop_group_member(dvs, self.nhg_ids[endpoint_str_primary], "false", endpoints_primary, expected_attrs_primary) - - if route_ids: - new_route = route_ids - else: - new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) - - #Check if the route is in expected VRF - active_nhg = self.nhg_ids[endpoint_str_primary] - for idx in range(count): - if prefix != "" and prefix not in new_route[idx] : - continue - check_object(asic_db, self.ASIC_ROUTE_ENTRY, new_route[idx], - { - "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": active_nhg, - } - ) - rt_key = json.loads(new_route[idx]) - - - self.routes.update(new_route) - del self.nhg_ids[endpoint_str_primary] - return new_route - - def check_del_vnet_routes(self, dvs, name, prefixes=[]): - # TODO: Implement for VRF VNET - - def _access_function(): - route_entries = get_exist_entries(dvs, self.ASIC_ROUTE_ENTRY) - route_prefixes = [json.loads(route_entry)["dest"] for route_entry in route_entries] - return (all(prefix not in route_prefixes for prefix in prefixes), None) - - if prefixes: - wait_for_result(_access_function) - - return True - - def check_custom_monitor_app_db(self, dvs, prefix, endpoint, packet_type, overlay_dmac): - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - key = endpoint + ':' + prefix - check_object(app_db, self.APP_VNET_MONITOR, key, - { - "packet_type": packet_type, - "overlay_dmac" : overlay_dmac - } - ) - return True - - def check_custom_monitor_deleted(self, dvs, prefix, endpoint): - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - key = endpoint + ':' + prefix - check_deleted_object(app_db, self.APP_VNET_MONITOR, key) +from vnet_lib import * class TestVnetOrch(object): @@ -3549,9 +2334,9 @@ def test_vnet_orch_24(self, dvs, testlog): vnet_obj.fetch_exist_entries(dvs) # create vnet route - create_vnet_routes(dvs, "100.100.1.0/24", 'Vnet_2000', '10.10.10.3') - vnet_obj.check_vnet_routes(dvs, 'Vnet_2000', '10.10.10.3', tunnel_name) - check_state_db_routes(dvs, 'Vnet_2000', "100.100.1.0/24", ['10.10.10.3']) + create_vnet_routes(dvs, "100.100.1.0/24", 'Vnet_2000', '10.10.10.6') + vnet_obj.check_vnet_routes(dvs, 'Vnet_2000', '10.10.10.6', tunnel_name) + check_state_db_routes(dvs, 'Vnet_2000', "100.100.1.0/24", ['10.10.10.6']) time.sleep(2) # create l3 interface @@ -3564,14 +2349,14 @@ def test_vnet_orch_24(self, dvs, testlog): self.set_admin_status("Ethernet0", "up") # set ip address and default route - dvs.servers[0].runcmd("ip address add 10.10.10.3/24 dev eth0") + dvs.servers[0].runcmd("ip address add 10.10.10.6/24 dev eth0") dvs.servers[0].runcmd("ip route add default via 10.10.10.1") marker = dvs.add_log_marker("/var/log/syslog") time.sleep(2) # add another route for same prefix as vnet route - dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 100.100.1.0/24 10.10.10.3\"") + dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 100.100.1.0/24 10.10.10.6\"") # check application database self.pdb.wait_for_entry("ROUTE_TABLE", "100.100.1.0/24") @@ -3584,7 +2369,7 @@ def test_vnet_orch_24(self, dvs, testlog): check_syslog(dvs, marker, log_string) # remove route entry - dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 100.100.1.0/24 10.10.10.3\"") + dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 100.100.1.0/24 10.10.10.6\"") # delete vnet route delete_vnet_routes(dvs, "100.100.1.0/24", 'Vnet_2000') diff --git a/tests/test_vnet2.py b/tests/test_vnet2.py new file mode 100644 index 0000000000..329b8f1999 --- /dev/null +++ b/tests/test_vnet2.py @@ -0,0 +1,320 @@ +import time +import ipaddress +import json +import random +import time +import pytest + +from swsscommon import swsscommon +from pprint import pprint +from dvslib.dvs_common import wait_for_result +from vnet_lib import * + + +class TestVnet2Orch(object): + CFG_SUBNET_DECAP_TABLE_NAME = "SUBNET_DECAP" + + @pytest.fixture + def setup_subnet_decap(self, dvs): + + def _apply_subnet_decap_config(subnet_decap_config): + """Apply subnet decap config to CONFIG_DB.""" + subnet_decap_tbl = swsscommon.Table(configdb, self.CFG_SUBNET_DECAP_TABLE_NAME) + fvs = create_fvs(**subnet_decap_config) + subnet_decap_tbl.set("AZURE", fvs) + + def _cleanup_subnet_decap_config(): + """Cleanup subnet decap config in CONFIG_DB.""" + subnet_decap_tbl = swsscommon.Table(configdb, self.CFG_SUBNET_DECAP_TABLE_NAME) + for key in subnet_decap_tbl.getKeys(): + subnet_decap_tbl._del(key) + + configdb = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + _cleanup_subnet_decap_config() + + yield _apply_subnet_decap_config + + _cleanup_subnet_decap_config() + + def get_vnet_obj(self): + return VnetVxlanVrfTunnel() + + def setup_db(self, dvs): + self.pdb = dvs.get_app_db() + self.adb = dvs.get_asic_db() + self.cdb = dvs.get_config_db() + self.sdb = dvs.get_state_db() + + def clear_srv_config(self, dvs): + dvs.servers[0].runcmd("ip address flush dev eth0") + dvs.servers[1].runcmd("ip address flush dev eth0") + dvs.servers[2].runcmd("ip address flush dev eth0") + dvs.servers[3].runcmd("ip address flush dev eth0") + + def set_admin_status(self, interface, status): + self.cdb.update_entry("PORT", interface, {"admin_status": status}) + + def create_l3_intf(self, interface, vrf_name): + if len(vrf_name) == 0: + self.cdb.create_entry("INTERFACE", interface, {"NULL": "NULL"}) + else: + self.cdb.create_entry("INTERFACE", interface, {"vrf_name": vrf_name}) + + def add_ip_address(self, interface, ip): + self.cdb.create_entry("INTERFACE", interface + "|" + ip, {"NULL": "NULL"}) + + def remove_ip_address(self, interface, ip): + self.cdb.delete_entry("INTERFACE", interface + "|" + ip) + + def check_route_entries(self, destinations, absent=False): + def _access_function(): + route_entries = self.adb.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY") + route_destinations = [json.loads(route_entry)["dest"] + for route_entry in route_entries] + return (all(destination in route_destinations for destination in destinations), None) + if absent: + return True if _access_function() == None else False + + wait_for_result(_access_function) + return True + + + ''' + Test 1 - Test for vnet tunnel routes interaction with regular route. + Add the conflicting route and then add the vnet route with same nexthops. + Bring up the bfd sessions and check the vnet route is programmed in hardware. + Remove the vnet route and check the vnet route is removed. + Remove the conflicting route and check the conflicting route is removed. + ''' + def test_vnet_orch_1(self, dvs, testlog): + vnet_obj = self.get_vnet_obj() + + tunnel_name = 'tunnel_29' + vnet_name = 'Vnet29' + self.setup_db(dvs) + vnet_obj.fetch_exist_entries(dvs) + # create l3 interface and bring it up + self.create_l3_intf("Ethernet0", "") + self.add_ip_address("Ethernet0", "10.10.10.1/24") + self.set_admin_status("Ethernet0", "down") + time.sleep(1) + self.set_admin_status("Ethernet0", "up") + + # set ip address and default route + dvs.servers[0].runcmd("ip address add 10.10.10.5/24 dev eth0") + dvs.servers[0].runcmd("ip route add default via 10.10.10.1") + + # create vxlan tunnel and verfiy it + create_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') + create_vnet_entry(dvs, vnet_name, tunnel_name, '10029', "") + vnet_obj.check_vnet_entry(dvs, vnet_name) + vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '10029') + vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') + + vnet_obj.fetch_exist_entries(dvs) + + # add conflicting route + dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 103.100.1.1/32 10.10.10.5\"") + + # check ASIC route database + self.check_route_entries(["103.100.1.1/32"]) + + create_vnet_routes(dvs, "103.100.1.1/32", vnet_name, '9.0.0.1,9.0.0.2,9.0.0.3', ep_monitor='9.1.0.1,9.1.0.2,9.1.0.3') + + # default bfd status is down, route should not be programmed in this status + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["103.100.1.1/32"], absent=True) + check_state_db_routes(dvs, vnet_name, "103.100.1.1/32", []) + check_remove_routes_advertisement(dvs, "103.100.1.1/32") + + # Route should be properly configured when all bfd session states go up + update_bfd_session_state(dvs, '9.1.0.2', 'Up') + time.sleep(1) + route1, nhg1_1 = vnet_obj.check_vnet_ecmp_routes(dvs, vnet_name, ['9.0.0.2'], tunnel_name) + + update_bfd_session_state(dvs, '9.1.0.3', 'Up') + time.sleep(1) + route1, nhg1_1 = vnet_obj.check_vnet_ecmp_routes(dvs, vnet_name, ['9.0.0.2', '9.0.0.3'], tunnel_name, route_ids=route1, nhg=nhg1_1) + + update_bfd_session_state(dvs, '9.1.0.1', 'Up') + time.sleep(1) + route1, nhg1_1 = vnet_obj.check_vnet_ecmp_routes(dvs, vnet_name, ['9.0.0.1', '9.0.0.2', '9.0.0.3'], tunnel_name, route_ids=route1, nhg=nhg1_1) + check_state_db_routes(dvs, vnet_name, "103.100.1.1/32", ['9.0.0.1', '9.0.0.2', '9.0.0.3']) + + # Remove all endpoint from group route shouldnt come back up. + update_bfd_session_state(dvs, '9.1.0.2', 'Down') + update_bfd_session_state(dvs, '9.1.0.1', 'Down') + update_bfd_session_state(dvs, '9.1.0.3', 'Down') + + time.sleep(1) + # after removal of vnet route, conflicting route is not getting programmed as its not a bgp learnt route. + self.check_route_entries(["103.100.1.1/32"], absent=True) + # Remove tunnel route 1 + delete_vnet_routes(dvs, "103.100.1.1/32", vnet_name) + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["103.100.1.1/32"]) + check_remove_state_db_routes(dvs, vnet_name, "103.100.1.1/32") + check_remove_routes_advertisement(dvs, "103.100.1.1/32") + + # Check the previous nexthop group is removed + vnet_obj.fetch_exist_entries(dvs) + assert nhg1_1 not in vnet_obj.nhgs + + # Confirm the BFD sessions are removed + check_del_bfd_session(dvs, ['9.1.0.1', '9.1.0.2', '9.1.0.3']) + vnet_obj.nhg_ids = {} + vnet_obj.fetch_exist_entries(dvs) + # readd the same route. + create_vnet_routes(dvs, "103.100.1.1/32", vnet_name, '9.0.0.1,9.0.0.2,9.0.0.3', ep_monitor='9.1.0.1,9.1.0.2,9.1.0.3') + + # default bfd status is down, route should not be programmed in this status + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["103.100.1.1/32"], absent=True) + check_state_db_routes(dvs, vnet_name, "103.100.1.1/32", []) + check_remove_routes_advertisement(dvs, "103.100.1.1/32") + + # Route should be properly configured when all bfd session states go up + update_bfd_session_state(dvs, '9.1.0.2', 'Up') + time.sleep(1) + route1, nhg1_1 = vnet_obj.check_vnet_ecmp_routes(dvs, vnet_name, ['9.0.0.2'], tunnel_name) + + update_bfd_session_state(dvs, '9.1.0.3', 'Up') + time.sleep(1) + route1, nhg1_1 = vnet_obj.check_vnet_ecmp_routes(dvs, vnet_name, ['9.0.0.2', '9.0.0.3'], tunnel_name, route_ids=route1, nhg=nhg1_1) + + update_bfd_session_state(dvs, '9.1.0.1', 'Up') + time.sleep(1) + route1, nhg1_1 = vnet_obj.check_vnet_ecmp_routes(dvs, vnet_name, ['9.0.0.1', '9.0.0.2', '9.0.0.3'], tunnel_name, route_ids=route1, nhg=nhg1_1) + check_state_db_routes(dvs, vnet_name, "103.100.1.1/32", ['9.0.0.1', '9.0.0.2', '9.0.0.3']) + + # Remove all endpoint from group route shouldnt come back up. + update_bfd_session_state(dvs, '9.1.0.2', 'Down') + update_bfd_session_state(dvs, '9.1.0.1', 'Down') + update_bfd_session_state(dvs, '9.1.0.3', 'Down') + + time.sleep(1) + # after removal of vnet route, conflicting route is not getting programmed as its not a bgp learnt route. + self.check_route_entries(["103.100.1.1/32"], absent=True) + # Remove tunnel route 1 + delete_vnet_routes(dvs, "103.100.1.1/32", vnet_name) + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["103.100.1.1/32"]) + check_remove_state_db_routes(dvs, vnet_name, "103.100.1.1/32") + check_remove_routes_advertisement(dvs, "103.100.1.1/32") + + # Check the previous nexthop group is removed + vnet_obj.fetch_exist_entries(dvs) + assert nhg1_1 not in vnet_obj.nhgs + + # Confirm the BFD sessions are removed + check_del_bfd_session(dvs, ['9.1.0.1', '9.1.0.2', '9.1.0.3']) + dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 103.100.1.1/32\"") + delete_vnet_entry(dvs, vnet_name) + vnet_obj.check_del_vnet_entry(dvs, vnet_name) + delete_vxlan_tunnel(dvs, tunnel_name) + + ''' + Test 2 - Test for vnet tunnel routes interaction with regular route with endpoints bieng up. + Add the conflicting route and then add the vnet route with same nexthops. + Bring up the bfd sessions and check the vnet route is programmed in hardware. + Add the 2nd conflicting route and then add the 2nd vnet route with same nexthops. + This way we check if the preceding route works of mexthops are already UP. + Verify the vnet routes are programmed in hardware. + Remove all the vnet route and check the vnet route is removed. + Remove all the conflicting route and check the conflicting route is removed. + ''' + def test_vnet_orch_2(self, dvs, testlog): + vnet_obj = self.get_vnet_obj() + + tunnel_name = 'tunnel_30' + vnet_name = 'Vnet30' + self.setup_db(dvs) + vnet_obj.fetch_exist_entries(dvs) + + # create l3 interface and bring it up + self.create_l3_intf("Ethernet0", "") + self.add_ip_address("Ethernet0", "10.10.10.1/24") + self.set_admin_status("Ethernet0", "down") + time.sleep(1) + self.set_admin_status("Ethernet0", "up") + + # set ip address and default route + dvs.servers[0].runcmd("ip address add 10.10.10.6/24 dev eth0") + dvs.servers[0].runcmd("ip route add default via 10.10.10.1") + + # create vxlan tunnel and verfiy it + create_vxlan_tunnel(dvs, tunnel_name, '9.8.8.9') + create_vnet_entry(dvs, vnet_name, tunnel_name, '10030', "") + vnet_obj.check_vnet_entry(dvs, vnet_name) + vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '10030') + vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.8.8.9') + vnet_obj.fetch_exist_entries(dvs) + + # add conflicting route + dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 200.100.1.1/32 10.10.10.6\"") + + # check ASIC route database + self.check_route_entries(["200.100.1.1/32"]) + + create_vnet_routes(dvs, "200.100.1.1/32", vnet_name, '9.0.0.1,9.0.0.2,9.0.0.3', ep_monitor='9.1.0.1,9.1.0.2,9.1.0.3') + + # default bfd status is down, route should not be programmed in this status + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["200.100.1.1/32"], absent=True) + check_state_db_routes(dvs, vnet_name, "200.100.1.1/32", []) + check_remove_routes_advertisement(dvs, "200.100.1.1/32") + + # Route should be properly configured when all bfd session states go up + update_bfd_session_state(dvs, '9.1.0.2', 'Up') + time.sleep(1) + route1, nhg1_1 = vnet_obj.check_vnet_ecmp_routes(dvs, vnet_name, ['9.0.0.2'], tunnel_name) + + update_bfd_session_state(dvs, '9.1.0.3', 'Up') + time.sleep(1) + route1, nhg1_1 = vnet_obj.check_vnet_ecmp_routes(dvs, vnet_name, ['9.0.0.2', '9.0.0.3'], tunnel_name, route_ids=route1, nhg=nhg1_1) + + update_bfd_session_state(dvs, '9.1.0.1', 'Up') + time.sleep(1) + route1, nhg1_1 = vnet_obj.check_vnet_ecmp_routes(dvs, vnet_name, ['9.0.0.1', '9.0.0.2', '9.0.0.3'], tunnel_name, route_ids=route1, nhg=nhg1_1) + check_state_db_routes(dvs, vnet_name, "200.100.1.1/32", ['9.0.0.1', '9.0.0.2', '9.0.0.3']) + + # create a new regular and vnet route with same different prefix but same nexthops as before. + dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 200.200.1.1/32 10.10.10.6\"") + # check ASIC route database + self.check_route_entries(["200.200.1.1/32"]) + + create_vnet_routes(dvs, "200.200.1.1/32", vnet_name, '9.0.0.1,9.0.0.2,9.0.0.3', ep_monitor='9.1.0.1,9.1.0.2,9.1.0.3') + dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 200.100.1.1/32 10.10.10.6\"") + + # Remove all endpoint from group route shouldnt come back up. + update_bfd_session_state(dvs, '9.1.0.2', 'Down') + update_bfd_session_state(dvs, '9.1.0.1', 'Down') + update_bfd_session_state(dvs, '9.1.0.3', 'Down') + + time.sleep(1) + # after removal of vnet route, conflicting route is not getting programmed. + self.check_route_entries(["200.100.1.1/32"], absent=True) + self.check_route_entries(["200.200.1.1/32"], absent=True) + + # Remove tunnel route 1 + delete_vnet_routes(dvs, "200.100.1.1/32", vnet_name) + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["200.100.1.1/32"]) + check_remove_state_db_routes(dvs, vnet_name, "200.100.1.1/32") + check_remove_routes_advertisement(dvs, "200.100.1.1/32") + + # Remove tunnel route 2 + delete_vnet_routes(dvs, "200.200.1.1/32", vnet_name) + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["200.200.1.1/32"]) + check_remove_state_db_routes(dvs, vnet_name, "200.200.1.1/32") + check_remove_routes_advertisement(dvs, "200.200.1.1/32") + + # Check the previous nexthop group is removed + vnet_obj.fetch_exist_entries(dvs) + assert nhg1_1 not in vnet_obj.nhgs + + # Confirm the BFD sessions are removed + check_del_bfd_session(dvs, ['9.1.0.1', '9.1.0.2', '9.1.0.3']) + + delete_vnet_entry(dvs, vnet_name) + vnet_obj.check_del_vnet_entry(dvs, vnet_name) + delete_vxlan_tunnel(dvs, tunnel_name) + +# Add Dummy always-pass test at end as workaroud +# for issue when Flaky fail on final test it invokes module tear-down before retrying +def test_nonflaky_dummy(): + pass diff --git a/tests/vnet_lib.py b/tests/vnet_lib.py new file mode 100644 index 0000000000..6bdb2cda97 --- /dev/null +++ b/tests/vnet_lib.py @@ -0,0 +1,1226 @@ +import time +import ipaddress +import json +import time + +from swsscommon import swsscommon +from pprint import pprint +from dvslib.dvs_common import wait_for_result + + +def create_entry(tbl, key, pairs): + fvs = swsscommon.FieldValuePairs(pairs) + tbl.set(key, fvs) + time.sleep(1) + + +def create_entry_tbl(db, table, separator, key, pairs): + tbl = swsscommon.Table(db, table) + create_entry(tbl, key, pairs) + + +def create_entry_pst(db, table, separator, key, pairs): + tbl = swsscommon.ProducerStateTable(db, table) + create_entry(tbl, key, pairs) + + +def delete_entry_tbl(db, table, key): + tbl = swsscommon.Table(db, table) + tbl._del(key) + time.sleep(1) + + +def delete_entry_pst(db, table, key): + tbl = swsscommon.ProducerStateTable(db, table) + tbl._del(key) + time.sleep(1) + + +def how_many_entries_exist(db, table): + tbl = swsscommon.Table(db, table) + return len(tbl.getKeys()) + + +def entries(db, table): + tbl = swsscommon.Table(db, table) + return set(tbl.getKeys()) + + +def get_exist_entries(dvs, table): + db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(db, table) + return set(tbl.getKeys()) + + +def get_created_entry(db, table, existed_entries): + tbl = swsscommon.Table(db, table) + entries = set(tbl.getKeys()) + new_entries = list(entries - existed_entries) + assert len(new_entries) == 1, "Wrong number of created entries." + return new_entries[0] + + +def get_all_created_entries(db, table, existed_entries): + tbl = swsscommon.Table(db, table) + entries = set(tbl.getKeys()) + new_entries = list(entries - set(existed_entries)) + assert len(new_entries) >= 0, "Get all could be no new created entries." + new_entries.sort() + return new_entries + + +def get_created_entries(db, table, existed_entries, count): + new_entries = get_all_created_entries(db, table, existed_entries) + assert len(new_entries) == count, "Wrong number of created entries." + return new_entries + + +def get_deleted_entries(db, table, existed_entries, count): + tbl = swsscommon.Table(db, table) + entries = set(tbl.getKeys()) + old_entries = list(existed_entries - entries) + assert len(old_entries) == count, "Wrong number of deleted entries." + old_entries.sort() + return old_entries + + +def get_default_vr_id(dvs): + db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + table = 'ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER' + tbl = swsscommon.Table(db, table) + keys = tbl.getKeys() + assert len(keys) == 1, "Wrong number of virtual routers found" + + return keys[0] + + +def check_object(db, table, key, expected_attributes): + tbl = swsscommon.Table(db, table) + keys = tbl.getKeys() + assert key in keys, "The desired key is not presented" + + status, fvs = tbl.get(key) + assert status, "Got an error when get a key" + + assert len(fvs) >= len(expected_attributes), "Incorrect attributes" + + attr_keys = {entry[0] for entry in fvs} + + for name, value in fvs: + if name in expected_attributes: + assert expected_attributes[name] == value, "Wrong value %s for the attribute %s = %s" % \ + (value, name, expected_attributes[name]) + +def check_deleted_object(db, table, key): + tbl = swsscommon.Table(db, table) + keys = tbl.getKeys() + assert key not in keys, "The desired key is not removed" + + +def create_vnet_local_routes(dvs, prefix, vnet_name, ifname): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + create_entry_tbl( + conf_db, + "VNET_ROUTE", '|', "%s|%s" % (vnet_name, prefix), + [ + ("ifname", ifname), + ] + ) + + time.sleep(2) + + +def delete_vnet_local_routes(dvs, prefix, vnet_name): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + delete_entry_pst(app_db, "VNET_ROUTE_TABLE", "%s:%s" % (vnet_name, prefix)) + + time.sleep(2) + + +def create_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor="", profile="", primary="", monitoring="", adv_prefix=""): + set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac=mac, vni=vni, ep_monitor=ep_monitor, profile=profile, primary=primary, monitoring=monitoring, adv_prefix=adv_prefix) + + +def set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor="", profile="", primary="", monitoring="", adv_prefix=""): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + attrs = [ + ("endpoint", endpoint), + ] + + if vni: + attrs.append(('vni', vni)) + + if mac: + attrs.append(('mac_address', mac)) + + if ep_monitor: + attrs.append(('endpoint_monitor', ep_monitor)) + + if profile: + attrs.append(('profile', profile)) + + if primary: + attrs.append(('primary', primary)) + + if monitoring: + attrs.append(('monitoring', monitoring)) + + if adv_prefix: + attrs.append(('adv_prefix', adv_prefix)) + + tbl = swsscommon.Table(conf_db, "VNET_ROUTE_TUNNEL") + fvs = swsscommon.FieldValuePairs(attrs) + tbl.set("%s|%s" % (vnet_name, prefix), fvs) + + time.sleep(2) + + +def delete_vnet_routes(dvs, prefix, vnet_name): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + delete_entry_pst(app_db, "VNET_ROUTE_TUNNEL_TABLE", "%s:%s" % (vnet_name, prefix)) + + time.sleep(2) + + +def create_vlan(dvs, vlan_name, vlan_ids): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + vlan_id = vlan_name[4:] + + # create vlan + create_entry_tbl( + conf_db, + "VLAN", '|', vlan_name, + [ + ("vlanid", vlan_id), + ], + ) + + time.sleep(1) + + vlan_oid = get_created_entry(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN", vlan_ids) + + check_object(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN", vlan_oid, + { + "SAI_VLAN_ATTR_VLAN_ID": vlan_id, + } + ) + + return vlan_oid + + +def create_vlan_interface(dvs, vlan_name, ifname, vnet_name, ipaddr): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + vlan_ids = get_exist_entries(dvs, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + + vlan_oid = create_vlan (dvs, vlan_name, vlan_ids) + + # create a vlan member in config db + create_entry_tbl( + conf_db, + "VLAN_MEMBER", '|', "%s|%s" % (vlan_name, ifname), + [ + ("tagging_mode", "untagged"), + ], + ) + + time.sleep(1) + + # create vlan interface in config db + create_entry_tbl( + conf_db, + "VLAN_INTERFACE", '|', vlan_name, + [ + ("vnet_name", vnet_name), + ("proxy_arp", "enabled"), + ], + ) + + #FIXME - This is created by IntfMgr + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + create_entry_pst( + app_db, + "INTF_TABLE", ':', vlan_name, + [ + ("vnet_name", vnet_name), + ("proxy_arp", "enabled"), + ], + ) + time.sleep(2) + + create_entry_tbl( + conf_db, + "VLAN_INTERFACE", '|', "%s|%s" % (vlan_name, ipaddr), + [ + ("family", "IPv4"), + ], + ) + + time.sleep(2) + + return vlan_oid + + +def delete_vlan_interface(dvs, ifname, ipaddr): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + delete_entry_tbl(conf_db, "VLAN_INTERFACE", "%s|%s" % (ifname, ipaddr)) + + time.sleep(2) + + delete_entry_tbl(conf_db, "VLAN_INTERFACE", ifname) + + time.sleep(2) + + +def create_phy_interface(dvs, ifname, vnet_name, ipaddr): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + exist_rifs = get_exist_entries(dvs, "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE") + + # create vlan interface in config db + create_entry_tbl( + conf_db, + "INTERFACE", '|', ifname, + [ + ("vnet_name", vnet_name), + ], + ) + + #FIXME - This is created by IntfMgr + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + create_entry_pst( + app_db, + "INTF_TABLE", ':', ifname, + [ + ("vnet_name", vnet_name), + ], + ) + time.sleep(2) + + create_entry_tbl( + conf_db, + "INTERFACE", '|', "%s|%s" % (ifname, ipaddr), + [ + ("family", "IPv4"), + ], + ) + + +def delete_phy_interface(dvs, ifname, ipaddr): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + delete_entry_tbl(conf_db, "INTERFACE", "%s|%s" % (ifname, ipaddr)) + + time.sleep(2) + + delete_entry_tbl(conf_db, "INTERFACE", ifname) + + time.sleep(2) + + +def create_vnet_entry(dvs, name, tunnel, vni, peer_list, scope="", advertise_prefix=False, overlay_dmac=""): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + attrs = [ + ("vxlan_tunnel", tunnel), + ("vni", vni), + ("peer_list", peer_list), + ] + + if scope: + attrs.append(('scope', scope)) + + if advertise_prefix: + attrs.append(('advertise_prefix', 'true')) + + if overlay_dmac: + attrs.append(('overlay_dmac', overlay_dmac)) + + # create the VXLAN tunnel Term entry in Config DB + create_entry_tbl( + conf_db, + "VNET", '|', name, + attrs, + ) + + time.sleep(2) + + +def delete_vnet_entry(dvs, name): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + delete_entry_tbl(conf_db, "VNET", "%s" % (name)) + + time.sleep(2) + + +def create_vxlan_tunnel(dvs, name, src_ip): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + attrs = [ + ("src_ip", src_ip), + ] + + # create the VXLAN tunnel Term entry in Config DB + create_entry_tbl( + conf_db, + "VXLAN_TUNNEL", '|', name, + attrs, + ) + +def delete_vxlan_tunnel(dvs, name): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + delete_entry_tbl(conf_db, "VXLAN_TUNNEL", name) + +def create_vxlan_tunnel_map(dvs, tunnel_name, tunnel_map_entry_name, vlan, vni_id): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + # create the VXLAN tunnel map entry in Config DB + create_entry_tbl( + conf_db, + "VXLAN_TUNNEL_MAP", '|', "%s|%s" % (tunnel_name, tunnel_map_entry_name), + [ + ("vni", vni_id), + ("vlan", vlan), + ], + ) + + +def get_lo(dvs): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + vr_id = get_default_vr_id(dvs) + + tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE') + + entries = tbl.getKeys() + lo_id = None + for entry in entries: + status, fvs = tbl.get(entry) + assert status, "Got an error when get a key" + for key, value in fvs: + if key == 'SAI_ROUTER_INTERFACE_ATTR_TYPE' and value == 'SAI_ROUTER_INTERFACE_TYPE_LOOPBACK': + lo_id = entry + break + else: + assert False, 'Don\'t found loopback id' + + return lo_id + + +def get_switch_mac(dvs): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_SWITCH') + + entries = tbl.getKeys() + mac = None + for entry in entries: + status, fvs = tbl.get(entry) + assert status, "Got an error when get a key" + for key, value in fvs: + if key == 'SAI_SWITCH_ATTR_SRC_MAC_ADDRESS': + mac = value + break + else: + assert False, 'Don\'t found switch mac' + + return mac + + +def check_linux_intf_arp_proxy(dvs, ifname): + (exitcode, out) = dvs.runcmd("cat /proc/sys/net/ipv4/conf/{0}/proxy_arp_pvlan".format(ifname)) + assert out != "1", "ARP proxy is not enabled for VNET interface in Linux kernel" + + +def update_bfd_session_state(dvs, addr, state): + bfd_id = get_bfd_session_id(dvs, addr) + assert bfd_id is not None + + bfd_sai_state = {"Admin_Down": "SAI_BFD_SESSION_STATE_ADMIN_DOWN", + "Down": "SAI_BFD_SESSION_STATE_DOWN", + "Init": "SAI_BFD_SESSION_STATE_INIT", + "Up": "SAI_BFD_SESSION_STATE_UP"} + + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + ntf = swsscommon.NotificationProducer(asic_db, "NOTIFICATIONS") + fvp = swsscommon.FieldValuePairs() + ntf_data = "[{\"bfd_session_id\":\""+bfd_id+"\",\"session_state\":\""+bfd_sai_state[state]+"\"}]" + ntf.send("bfd_session_state_change", ntf_data, fvp) + +def update_monitor_session_state(dvs, addr, monitor, state): + state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) + create_entry_tbl( + state_db, + "VNET_MONITOR_TABLE", '|', "%s|%s" % (monitor,addr), + [ + ("state", state), + ] + ) + +def get_bfd_session_id(dvs, addr): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_BFD_SESSION") + entries = set(tbl.getKeys()) + for entry in entries: + status, fvs = tbl.get(entry) + fvs = dict(fvs) + assert status, "Got an error when get a key" + if fvs["SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS"] == addr and fvs["SAI_BFD_SESSION_ATTR_MULTIHOP"] == "true": + return entry + + return None + + +def check_del_bfd_session(dvs, addrs): + for addr in addrs: + assert get_bfd_session_id(dvs, addr) is None + + +def check_bfd_session(dvs, addrs): + for addr in addrs: + assert get_bfd_session_id(dvs, addr) is not None + + +def check_state_db_routes(dvs, vnet, prefix, endpoints): + state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(state_db, "VNET_ROUTE_TUNNEL_TABLE") + + status, fvs = tbl.get(vnet + '|' + prefix) + assert status, "Got an error when get a key" + + fvs = dict(fvs) + assert fvs['active_endpoints'] == ','.join(endpoints) + + if endpoints: + assert fvs['state'] == 'active' + else: + assert fvs['state'] == 'inactive' + + +def check_remove_state_db_routes(dvs, vnet, prefix): + state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(state_db, "VNET_ROUTE_TUNNEL_TABLE") + keys = tbl.getKeys() + + assert vnet + '|' + prefix not in keys + + +def check_routes_advertisement(dvs, prefix, profile=""): + state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(state_db, "ADVERTISE_NETWORK_TABLE") + keys = tbl.getKeys() + + assert prefix in keys + + if profile: + status, fvs = tbl.get(prefix) + assert status, "Got an error when get a key" + fvs = dict(fvs) + assert fvs['profile'] == profile + + +def check_remove_routes_advertisement(dvs, prefix): + state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(state_db, "ADVERTISE_NETWORK_TABLE") + keys = tbl.getKeys() + + assert prefix not in keys + + +def check_syslog(dvs, marker, err_log): + (exitcode, num) = dvs.runcmd(['sh', '-c', "awk \'/%s/,ENDFILE {print;}\' /var/log/syslog | grep \"%s\" | wc -l" % (marker, err_log)]) + assert num.strip() == "0" + + +def create_fvs(**kwargs): + return swsscommon.FieldValuePairs(list(kwargs.items())) + + +def create_subnet_decap_tunnel(dvs, tunnel_name, **kwargs): + """Create tunnel and verify all needed entries in state DB exists.""" + appdb = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + statedb = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) + fvs = create_fvs(**kwargs) + # create tunnel entry in DB + ps = swsscommon.ProducerStateTable(appdb, "TUNNEL_DECAP_TABLE") + ps.set(tunnel_name, fvs) + + # wait till config will be applied + time.sleep(1) + + # validate the tunnel entry in state db + tunnel_state_table = swsscommon.Table(statedb, "TUNNEL_DECAP_TABLE") + + tunnels = tunnel_state_table.getKeys() + for tunnel in tunnels: + status, fvs = tunnel_state_table.get(tunnel) + assert status == True + + for field, value in fvs: + if field == "tunnel_type": + assert value == "IPINIP" + elif field == "dscp_mode": + assert value == kwargs["dscp_mode"] + elif field == "ecn_mode": + assert value == kwargs["ecn_mode"] + elif field == "ttl_mode": + assert value == kwargs["ttl_mode"] + elif field == "encap_ecn_mode": + assert value == kwargs["encap_ecn_mode"] + else: + assert False, "Field %s is not tested" % field + + +def delete_subnet_decap_tunnel(dvs, tunnel_name): + """Delete tunnel and checks that state DB is cleared.""" + appdb = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + statedb = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) + tunnel_app_table = swsscommon.Table(appdb, "TUNNEL_DECAP_TABLE") + tunnel_state_table = swsscommon.Table(statedb, "TUNNEL_DECAP_TABLE") + + ps = swsscommon.ProducerStateTable(appdb, "TUNNEL_DECAP_TABLE") + ps._del(tunnel_name) + + # wait till config will be applied + time.sleep(1) + + assert len(tunnel_app_table.getKeys()) == 0 + assert len(tunnel_state_table.getKeys()) == 0 + + +loopback_id = 0 +def_vr_id = 0 +switch_mac = None + +def update_bgp_global_dev_state(dvs, state): + config_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + create_entry_tbl( + config_db, + "BGP_DEVICE_GLOBAL",'|',"STATE", + [ + ("tsa_enabled", state), + ] + ) + +def set_tsa(dvs): + update_bgp_global_dev_state(dvs, "true") + +def clear_tsa(dvs): + update_bgp_global_dev_state(dvs, "false") + +class VnetVxlanVrfTunnel(object): + + ASIC_TUNNEL_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL" + ASIC_TUNNEL_MAP = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP" + ASIC_TUNNEL_MAP_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY" + ASIC_TUNNEL_TERM_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY" + ASIC_RIF_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE" + ASIC_VRF_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER" + ASIC_ROUTE_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY" + ASIC_NEXT_HOP = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP" + ASIC_VLAN_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_VLAN" + ASIC_NEXT_HOP_GROUP = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP" + ASIC_NEXT_HOP_GROUP_MEMBER = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER" + ASIC_BFD_SESSION = "ASIC_STATE:SAI_OBJECT_TYPE_BFD_SESSION" + APP_VNET_MONITOR = "VNET_MONITOR_TABLE" + + ecn_modes_map = { + "standard" : "SAI_TUNNEL_DECAP_ECN_MODE_STANDARD", + "copy_from_outer": "SAI_TUNNEL_DECAP_ECN_MODE_COPY_FROM_OUTER" + } + + dscp_modes_map = { + "pipe" : "SAI_TUNNEL_DSCP_MODE_PIPE_MODEL", + "uniform" : "SAI_TUNNEL_DSCP_MODE_UNIFORM_MODEL" + } + + ttl_modes_map = { + "pipe" : "SAI_TUNNEL_TTL_MODE_PIPE_MODEL", + "uniform" : "SAI_TUNNEL_TTL_MODE_UNIFORM_MODEL" + } + + def __init__(self): + self.tunnel_map_ids = set() + self.tunnel_map_entry_ids = set() + self.tunnel_ids = set() + self.tunnel_term_ids = set() + self.ipinip_tunnel_term_ids = {} + self.tunnel_map_map = {} + self.tunnel = {} + self.vnet_vr_ids = set() + self.vr_map = {} + self.nh_ids = {} + self.nhg_ids = {} + + def fetch_exist_entries(self, dvs): + self.vnet_vr_ids = get_exist_entries(dvs, self.ASIC_VRF_TABLE) + self.tunnel_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_TABLE) + self.tunnel_map_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_MAP) + self.tunnel_map_entry_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_MAP_ENTRY) + self.tunnel_term_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_TERM_ENTRY) + self.rifs = get_exist_entries(dvs, self.ASIC_RIF_TABLE) + self.routes = get_exist_entries(dvs, self.ASIC_ROUTE_ENTRY) + self.nhops = get_exist_entries(dvs, self.ASIC_NEXT_HOP) + self.nhgs = get_exist_entries(dvs, self.ASIC_NEXT_HOP_GROUP) + self.bfd_sessions = get_exist_entries(dvs, self.ASIC_BFD_SESSION) + + global loopback_id, def_vr_id, switch_mac + if not loopback_id: + loopback_id = get_lo(dvs) + + if not def_vr_id: + def_vr_id = get_default_vr_id(dvs) + + if switch_mac is None: + switch_mac = get_switch_mac(dvs) + + def check_ipinip_tunnel(self, dvs, tunnel_name, dscp_mode, ecn_mode, ttl_mode): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + tunnel_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TABLE, self.tunnel_ids) + tunnel_attrs = { + 'SAI_TUNNEL_ATTR_TYPE': 'SAI_TUNNEL_TYPE_IPINIP', + 'SAI_TUNNEL_ATTR_ENCAP_DSCP_MODE': self.dscp_modes_map[dscp_mode], + 'SAI_TUNNEL_ATTR_ENCAP_ECN_MODE': self.ecn_modes_map[ecn_mode], + 'SAI_TUNNEL_ATTR_ENCAP_TTL_MODE': self.ttl_modes_map[ttl_mode] + } + check_object(asic_db, self.ASIC_TUNNEL_TABLE, tunnel_id, tunnel_attrs) + + self.tunnel_ids.add(tunnel_id) + self.tunnel[tunnel_name] = tunnel_id + + def check_del_ipinip_tunnel(self, dvs, tunnel_name): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + tunnel_id = get_deleted_entries(asic_db, self.ASIC_TUNNEL_TABLE, self.tunnel_ids, 1)[0] + check_deleted_object(asic_db, self.ASIC_TUNNEL_TABLE, tunnel_id) + self.tunnel_ids.remove(tunnel_id) + assert tunnel_id == self.tunnel[tunnel_name] + self.tunnel.pop(tunnel_name) + + def check_ipinip_tunnel_decap_term(self, dvs, tunnel_name, dst_ip, src_ip): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + dst_ip = ipaddress.ip_network(dst_ip) + src_ip = ipaddress.ip_network(src_ip) + tunnel_term_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, self.tunnel_term_ids) + tunnel_term_attrs = { + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE': 'SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_MP2MP', + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE': 'SAI_TUNNEL_TYPE_IPINIP', + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP': str(dst_ip.network_address), + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP_MASK': str(dst_ip.netmask), + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_SRC_IP': str(src_ip.network_address), + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_SRC_IP_MASK': str(src_ip.netmask), + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID': self.tunnel[tunnel_name] + } + check_object(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, tunnel_term_id, tunnel_term_attrs) + + self.tunnel_term_ids.add(tunnel_term_id) + self.ipinip_tunnel_term_ids[(tunnel_name, src_ip, dst_ip)] = tunnel_term_id + + def check_del_ipinip_tunnel_decap_term(self, dvs, tunnel_name, dst_ip, src_ip): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + dst_ip = ipaddress.ip_network(dst_ip) + src_ip = ipaddress.ip_network(src_ip) + tunnel_term_id = get_deleted_entries(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, self.tunnel_term_ids, 1)[0] + check_deleted_object(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, tunnel_term_id) + self.tunnel_term_ids.remove(tunnel_term_id) + assert self.ipinip_tunnel_term_ids[(tunnel_name, src_ip, dst_ip)] == tunnel_term_id + self.ipinip_tunnel_term_ids.pop((tunnel_name, src_ip, dst_ip)) + + def check_vxlan_tunnel(self, dvs, tunnel_name, src_ip): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + global loopback_id, def_vr_id + + tunnel_map_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 4) + tunnel_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TABLE, self.tunnel_ids) + tunnel_term_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, self.tunnel_term_ids) + + # check that the vxlan tunnel termination are there + assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP) == (len(self.tunnel_map_ids) + 4), "The TUNNEL_MAP wasn't created" + assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) == len(self.tunnel_map_entry_ids), "The TUNNEL_MAP_ENTRY is created" + assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_TABLE) == (len(self.tunnel_ids) + 1), "The TUNNEL wasn't created" + assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_TERM_ENTRY) == (len(self.tunnel_term_ids) + 1), "The TUNNEL_TERM_TABLE_ENTRY wasm't created" + + check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[2], + { + 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID', + } + ) + + check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[3], + { + 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI', + } + ) + + check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[0], + { + 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VLAN_ID', + } + ) + + check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[1], + { + 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VLAN_ID_TO_VNI', + } + ) + + check_object(asic_db, self.ASIC_TUNNEL_TABLE, tunnel_id, + { + 'SAI_TUNNEL_ATTR_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', + 'SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE': loopback_id, + 'SAI_TUNNEL_ATTR_DECAP_MAPPERS': '2:%s,%s' % (tunnel_map_id[0], tunnel_map_id[2]), + 'SAI_TUNNEL_ATTR_ENCAP_MAPPERS': '2:%s,%s' % (tunnel_map_id[1], tunnel_map_id[3]), + 'SAI_TUNNEL_ATTR_ENCAP_SRC_IP': src_ip, + } + ) + + expected_attributes = { + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE': 'SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2MP', + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_VR_ID': def_vr_id, + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP': src_ip, + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID': tunnel_id, + } + + check_object(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, tunnel_term_id, expected_attributes) + + self.tunnel_map_ids.update(tunnel_map_id) + self.tunnel_ids.add(tunnel_id) + self.tunnel_term_ids.add(tunnel_term_id) + self.tunnel_map_map[tunnel_name] = tunnel_map_id + self.tunnel[tunnel_name] = tunnel_id + + def check_del_vxlan_tunnel(self, dvs): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + old_tunnel = get_deleted_entries(asic_db, self.ASIC_TUNNEL_TABLE, self.tunnel_ids, 1) + check_deleted_object(asic_db, self.ASIC_TUNNEL_TABLE, old_tunnel[0]) + self.tunnel_ids.remove(old_tunnel[0]) + + old_tunnel_maps = get_deleted_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 4) + for old_tunnel_map in old_tunnel_maps: + check_deleted_object(asic_db, self.ASIC_TUNNEL_MAP, old_tunnel_map) + self.tunnel_map_ids.remove(old_tunnel_map) + + def check_vxlan_tunnel_entry(self, dvs, tunnel_name, vnet_name, vni_id): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + time.sleep(2) + + if (self.tunnel_map_map.get(tunnel_name) is None): + tunnel_map_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 4) + else: + tunnel_map_id = self.tunnel_map_map[tunnel_name] + + tunnel_map_entry_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, self.tunnel_map_entry_ids, 2) + + # check that the vxlan tunnel termination are there + assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) == (len(self.tunnel_map_entry_ids) + 2), "The TUNNEL_MAP_ENTRY is created too early" + + check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[0], + { + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI', + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[3], + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_KEY': self.vr_map[vnet_name].get('ing'), + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_VALUE': vni_id, + } + ) + + check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[1], + { + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID', + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[2], + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vni_id, + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_VALUE': self.vr_map[vnet_name].get('egr'), + } + ) + + self.tunnel_map_entry_ids.update(tunnel_map_entry_id) + + def check_vnet_entry(self, dvs, name, peer_list=[]): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + #Assert if there are linklocal entries + tbl = swsscommon.Table(app_db, "VNET_ROUTE_TUNNEL_TABLE") + route_entries = tbl.getKeys() + assert "ff00::/8" not in route_entries + assert "fe80::/64" not in route_entries + + #Check virtual router objects + assert how_many_entries_exist(asic_db, self.ASIC_VRF_TABLE) == (len(self.vnet_vr_ids) + 1),\ + "The VR objects are not created" + + new_vr_ids = get_created_entries(asic_db, self.ASIC_VRF_TABLE, self.vnet_vr_ids, 1) + + self.vnet_vr_ids.update(new_vr_ids) + self.vr_map[name] = { 'ing':new_vr_ids[0], 'egr':new_vr_ids[0], 'peer':peer_list } + + def check_default_vnet_entry(self, dvs, name): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + #Check virtual router objects + assert how_many_entries_exist(asic_db, self.ASIC_VRF_TABLE) == (len(self.vnet_vr_ids)),\ + "Some VR objects are created" + #Mappers for default VNET is created with default VR objects. + self.vr_map[name] = { 'ing':list(self.vnet_vr_ids)[0], 'egr':list(self.vnet_vr_ids)[0], 'peer':[] } + + def check_del_vnet_entry(self, dvs, name): + # TODO: Implement for VRF VNET + return True + + def vnet_route_ids(self, dvs, name, local=False): + vr_set = set() + + vr_set.add(self.vr_map[name].get('ing')) + + try: + for peer in self.vr_map[name].get('peer'): + vr_set.add(self.vr_map[peer].get('ing')) + except IndexError: + pass + + return vr_set + + def check_router_interface(self, dvs, intf_name, name, vlan_oid=0): + # Check RIF in ingress VRF + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + global switch_mac + + expected_attr = { + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": self.vr_map[name].get('ing'), + "SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS": switch_mac, + "SAI_ROUTER_INTERFACE_ATTR_MTU": "9100", + } + + if vlan_oid: + expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_TYPE': 'SAI_ROUTER_INTERFACE_TYPE_VLAN'}) + expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_VLAN_ID': vlan_oid}) + else: + expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_TYPE': 'SAI_ROUTER_INTERFACE_TYPE_PORT'}) + + new_rif = get_created_entry(asic_db, self.ASIC_RIF_TABLE, self.rifs) + check_object(asic_db, self.ASIC_RIF_TABLE, new_rif, expected_attr) + + #IP2ME route will be created with every router interface + new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, 1) + + if vlan_oid: + expected_attr = { 'SAI_VLAN_ATTR_BROADCAST_FLOOD_CONTROL_TYPE': 'SAI_VLAN_FLOOD_CONTROL_TYPE_NONE' } + check_object(asic_db, self.ASIC_VLAN_TABLE, vlan_oid, expected_attr) + + expected_attr = { 'SAI_VLAN_ATTR_UNKNOWN_MULTICAST_FLOOD_CONTROL_TYPE': 'SAI_VLAN_FLOOD_CONTROL_TYPE_NONE' } + check_object(asic_db, self.ASIC_VLAN_TABLE, vlan_oid, expected_attr) + + check_linux_intf_arp_proxy(dvs, intf_name) + + self.rifs.add(new_rif) + self.routes.update(new_route) + + def check_del_router_interface(self, dvs, name): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + old_rif = get_deleted_entries(asic_db, self.ASIC_RIF_TABLE, self.rifs, 1) + check_deleted_object(asic_db, self.ASIC_RIF_TABLE, old_rif[0]) + + self.rifs.remove(old_rif[0]) + + def check_vnet_local_routes(self, dvs, name): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + vr_ids = self.vnet_route_ids(dvs, name, True) + count = len(vr_ids) + + new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) + + #Routes are not replicated to egress VRF, return if count is 0, else check peering + if not count: + return + + asic_vrs = set() + for idx in range(count): + rt_key = json.loads(new_route[idx]) + asic_vrs.add(rt_key['vr']) + + assert asic_vrs == vr_ids + + self.routes.update(new_route) + + def check_del_vnet_local_routes(self, dvs, name): + # TODO: Implement for VRF VNET + return True + + def check_vnet_routes(self, dvs, name, endpoint, tunnel, mac="", vni=0, route_ids=""): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + vr_ids = self.vnet_route_ids(dvs, name) + count = len(vr_ids) + + # Check routes in ingress VRF + expected_attr = { + "SAI_NEXT_HOP_ATTR_TYPE": "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP", + "SAI_NEXT_HOP_ATTR_IP": endpoint, + "SAI_NEXT_HOP_ATTR_TUNNEL_ID": self.tunnel[tunnel], + } + + if vni: + expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_VNI': vni}) + + if mac: + expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_MAC': mac}) + + if endpoint in self.nh_ids: + new_nh = self.nh_ids[endpoint] + else: + new_nh = get_created_entry(asic_db, self.ASIC_NEXT_HOP, self.nhops) + self.nh_ids[endpoint] = new_nh + self.nhops.add(new_nh) + + check_object(asic_db, self.ASIC_NEXT_HOP, new_nh, expected_attr) + if not route_ids: + new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) + else: + new_route = route_ids + + #Check if the route is in expected VRF + asic_vrs = set() + for idx in range(count): + check_object(asic_db, self.ASIC_ROUTE_ENTRY, new_route[idx], + { + "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": new_nh, + } + ) + rt_key = json.loads(new_route[idx]) + asic_vrs.add(rt_key['vr']) + + assert asic_vrs == vr_ids + + self.routes.update(new_route) + + return new_route + + def serialize_endpoint_group(self, endpoints): + endpoints.sort() + return ",".join(endpoints) + + def check_next_hop_group_member(self, dvs, nhg, ordered_ecmp, expected_endpoint, expected_attrs): + expected_endpoint_str = self.serialize_endpoint_group(expected_endpoint) + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + tbl_nhgm = swsscommon.Table(asic_db, self.ASIC_NEXT_HOP_GROUP_MEMBER) + tbl_nh = swsscommon.Table(asic_db, self.ASIC_NEXT_HOP) + entries = set(tbl_nhgm.getKeys()) + endpoints = [] + for entry in entries: + status, fvs = tbl_nhgm.get(entry) + fvs = dict(fvs) + assert status, "Got an error when get a key" + if fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID"] == nhg: + nh_key = fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID"] + status, nh_fvs = tbl_nh.get(nh_key) + nh_fvs = dict(nh_fvs) + assert status, "Got an error when get a key" + endpoint = nh_fvs["SAI_NEXT_HOP_ATTR_IP"] + endpoints.append(endpoint) + assert endpoint in expected_attrs + if ordered_ecmp == "true": + assert fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_SEQUENCE_ID"] == expected_attrs[endpoint]['SAI_NEXT_HOP_GROUP_MEMBER_ATTR_SEQUENCE_ID'] + del expected_attrs[endpoint]['SAI_NEXT_HOP_GROUP_MEMBER_ATTR_SEQUENCE_ID'] + else: + assert fvs.get("SAI_NEXT_HOP_GROUP_MEMBER_ATTR_SEQUENCE_ID") is None + + check_object(asic_db, self.ASIC_NEXT_HOP, nh_key, expected_attrs[endpoint]) + + assert self.serialize_endpoint_group(endpoints) == expected_endpoint_str + + def get_nexthop_groups(self, dvs, nhg): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + tbl_nhgm = swsscommon.Table(asic_db, self.ASIC_NEXT_HOP_GROUP_MEMBER) + tbl_nh = swsscommon.Table(asic_db, self.ASIC_NEXT_HOP) + nhg_data = {} + nhg_data['id'] = nhg + entries = set(tbl_nhgm.getKeys()) + nhg_data['endpoints'] = [] + for entry in entries: + status, fvs = tbl_nhgm.get(entry) + fvs = dict(fvs) + assert status, "Got an error when get a key" + if fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID"] == nhg: + nh_key = fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID"] + status, nh_fvs = tbl_nh.get(nh_key) + nh_fvs = dict(nh_fvs) + assert status, "Got an error when get a key" + endpoint = nh_fvs["SAI_NEXT_HOP_ATTR_IP"] + nhg_data['endpoints'].append(endpoint) + return nhg_data + def check_vnet_ecmp_routes(self, dvs, name, endpoints, tunnel, mac=[], vni=[], route_ids=[], nhg="", ordered_ecmp="false", nh_seq_id=None): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + endpoint_str = name + "|" + self.serialize_endpoint_group(endpoints) + + vr_ids = self.vnet_route_ids(dvs, name) + count = len(vr_ids) + + expected_attrs = {} + for idx, endpoint in enumerate(endpoints): + expected_attr = { + "SAI_NEXT_HOP_ATTR_TYPE": "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP", + "SAI_NEXT_HOP_ATTR_IP": endpoint, + "SAI_NEXT_HOP_ATTR_TUNNEL_ID": self.tunnel[tunnel], + } + if vni and vni[idx]: + expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_VNI': vni[idx]}) + if mac and mac[idx]: + expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_MAC': mac[idx]}) + if ordered_ecmp == "true" and nh_seq_id: + expected_attr.update({'SAI_NEXT_HOP_GROUP_MEMBER_ATTR_SEQUENCE_ID': nh_seq_id[idx]}) + expected_attrs[endpoint] = expected_attr + + if nhg: + new_nhg = nhg + elif endpoint_str in self.nhg_ids: + new_nhg = self.nhg_ids[endpoint_str] + else: + new_nhg = get_created_entry(asic_db, self.ASIC_NEXT_HOP_GROUP, self.nhgs) + self.nhg_ids[endpoint_str] = new_nhg + self.nhgs.add(new_nhg) + + + # Check routes in ingress VRF + expected_nhg_attr = { + "SAI_NEXT_HOP_GROUP_ATTR_TYPE": "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP" if ordered_ecmp == "false" else "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_ORDERED_ECMP", + } + check_object(asic_db, self.ASIC_NEXT_HOP_GROUP, new_nhg, expected_nhg_attr) + + # Check nexthop group member + self.check_next_hop_group_member(dvs, new_nhg, ordered_ecmp, endpoints, expected_attrs) + + if route_ids: + new_route = route_ids + else: + new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) + + #Check if the route is in expected VRF + asic_vrs = set() + for idx in range(count): + check_object(asic_db, self.ASIC_ROUTE_ENTRY, new_route[idx], + { + "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": new_nhg, + } + ) + rt_key = json.loads(new_route[idx]) + asic_vrs.add(rt_key['vr']) + + assert asic_vrs == vr_ids + + self.routes.update(new_route) + + return new_route, new_nhg + + def check_priority_vnet_ecmp_routes(self, dvs, name, endpoints_primary, tunnel, mac=[], vni=[], route_ids=[], count =1, prefix =""): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + endpoint_str_primary = name + "|" + self.serialize_endpoint_group(endpoints_primary) + new_nhgs = [] + expected_attrs_primary = {} + for idx, endpoint in enumerate(endpoints_primary): + expected_attr = { + "SAI_NEXT_HOP_ATTR_TYPE": "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP", + "SAI_NEXT_HOP_ATTR_IP": endpoint, + "SAI_NEXT_HOP_ATTR_TUNNEL_ID": self.tunnel[tunnel], + } + if vni and vni[idx]: + expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_VNI': vni[idx]}) + if mac and mac[idx]: + expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_MAC': mac[idx]}) + expected_attrs_primary[endpoint] = expected_attr + + if len(endpoints_primary) == 1: + if route_ids: + new_route = route_ids + else: + new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) + return new_route + else : + new_nhgs = get_all_created_entries(asic_db, self.ASIC_NEXT_HOP_GROUP, self.nhgs) + found_match = False + + for nhg in new_nhgs: + nhg_data = self.get_nexthop_groups(dvs, nhg) + eplist = self.serialize_endpoint_group(nhg_data['endpoints']) + if eplist == self.serialize_endpoint_group(endpoints_primary): + self.nhg_ids[endpoint_str_primary] = nhg + found_match = True + + assert found_match, "the expected Nexthop group was not found." + + # Check routes in ingress VRF + expected_nhg_attr = { + "SAI_NEXT_HOP_GROUP_ATTR_TYPE": "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP", + } + for nhg in new_nhgs: + check_object(asic_db, self.ASIC_NEXT_HOP_GROUP, nhg, expected_nhg_attr) + + # Check nexthop group member + self.check_next_hop_group_member(dvs, self.nhg_ids[endpoint_str_primary], "false", endpoints_primary, expected_attrs_primary) + + if route_ids: + new_route = route_ids + else: + new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) + + #Check if the route is in expected VRF + active_nhg = self.nhg_ids[endpoint_str_primary] + for idx in range(count): + if prefix != "" and prefix not in new_route[idx] : + continue + check_object(asic_db, self.ASIC_ROUTE_ENTRY, new_route[idx], + { + "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": active_nhg, + } + ) + rt_key = json.loads(new_route[idx]) + + + self.routes.update(new_route) + del self.nhg_ids[endpoint_str_primary] + return new_route + + def check_del_vnet_routes(self, dvs, name, prefixes=[], absent=False): + # TODO: Implement for VRF VNET + + def _access_function(): + route_entries = get_exist_entries(dvs, self.ASIC_ROUTE_ENTRY) + route_prefixes = [json.loads(route_entry)["dest"] for route_entry in route_entries] + return (all(prefix not in route_prefixes for prefix in prefixes), None) + + if absent: + return True if _access_function()== None else False + elif prefixes: + wait_for_result(_access_function) + + return True + + def check_custom_monitor_app_db(self, dvs, prefix, endpoint, packet_type, overlay_dmac): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + key = endpoint + ':' + prefix + check_object(app_db, self.APP_VNET_MONITOR, key, + { + "packet_type": packet_type, + "overlay_dmac" : overlay_dmac + } + ) + return True + + def check_custom_monitor_deleted(self, dvs, prefix, endpoint): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + key = endpoint + ':' + prefix + check_deleted_object(app_db, self.APP_VNET_MONITOR, key) From 793d739e7d2e99ee40314f5b791c2688200d5934 Mon Sep 17 00:00:00 2001 From: shahzad Iqbal Date: Sun, 3 Nov 2024 03:04:53 +0000 Subject: [PATCH 02/18] added some extra logs for debugging. --- orchagent/vnetorch.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index d56c44ab14..06409180e7 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -1147,7 +1147,18 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP } else { - gRouteOrch->removeRouteIfExists(ipPrefix); + SWSS_LOG_INFO("Attempting to remove BGP learnt route for prefix : %s\n", + ipPrefix.to_string().c_str()); + if (!gRouteOrch->removeRouteIfExists(ipPrefix)) + { + SWSS_LOG_ERROR("Couldnt Removed existing bgp route for prefix : %s\n", ipPrefix.to_string().c_str()); + return false; + } + else + { + SWSS_LOG_INFO("Successfully Removed existing bgp route for prefix : %s \n", + ipPrefix.to_string().c_str()); + } if (it_route == syncd_tunnel_routes_[vnet].end()) { route_status = add_route(vr_id, pfx, nh_id); @@ -1296,6 +1307,8 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP SWSS_LOG_ERROR("Route del failed for %s, vr_id '0x%" PRIx64, ipPrefix.to_string().c_str(), vr_id); return false; } + SWSS_LOG_INFO("Successfully deled route for %s", ipPrefix.to_string().c_str()); + } } @@ -2328,6 +2341,8 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) for (auto ip_pfx : syncd_nexthop_groups_[vnet][nexthops].tunnel_routes) { // remove the bgp learnt routr first if any and then add the tunnel route. + SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", + ip_pfx.to_string().c_str()); if (!gRouteOrch->removeRouteIfExists(ip_pfx)) { SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", ip_pfx.to_string().c_str()); @@ -2344,12 +2359,18 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) SWSS_LOG_NOTICE("Failed to create tunnel route in hardware for prefix : %s\n", ip_pfx.to_string().c_str()); failed = true; } + else + { + SWSS_LOG_INFO("Successfully created tunnel route in hardware for prefix : %s\n", + ip_pfx.to_string().c_str()); + } } } if (failed) { // This is an unrecoverable error, Throw a LOG_ERROR and return SWSS_LOG_ERROR("Inconsistant Hardware State. Failed to create tunnel routes\n"); + return; } } else From e9ea1bd391cca7724bc2933a688d612bc4373421 Mon Sep 17 00:00:00 2001 From: siqbal1986 Date: Wed, 6 Nov 2024 02:04:36 +0000 Subject: [PATCH 03/18] bug fixes. added one more test. --- orchagent/vnetorch.cpp | 56 ++++++++++++----- tests/test_vnet.py | 12 ++-- tests/test_vnet2.py | 140 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 175 insertions(+), 33 deletions(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index 06409180e7..487528a99e 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -1151,14 +1151,11 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP ipPrefix.to_string().c_str()); if (!gRouteOrch->removeRouteIfExists(ipPrefix)) { - SWSS_LOG_ERROR("Couldnt Removed existing bgp route for prefix : %s\n", ipPrefix.to_string().c_str()); + SWSS_LOG_ERROR("Couldn't Removed existing bgp route for prefix : %s\n", ipPrefix.to_string().c_str()); return false; } - else - { - SWSS_LOG_INFO("Successfully Removed existing bgp route for prefix : %s \n", - ipPrefix.to_string().c_str()); - } + SWSS_LOG_INFO("Successfully Removed existing bgp route for prefix : %s \n", + ipPrefix.to_string().c_str()); if (it_route == syncd_tunnel_routes_[vnet].end()) { route_status = add_route(vr_id, pfx, nh_id); @@ -1307,7 +1304,7 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP SWSS_LOG_ERROR("Route del failed for %s, vr_id '0x%" PRIx64, ipPrefix.to_string().c_str(), vr_id); return false; } - SWSS_LOG_INFO("Successfully deled route for %s", ipPrefix.to_string().c_str()); + SWSS_LOG_INFO("Successfully deleted the route for %s", ipPrefix.to_string().c_str()); } } @@ -2286,11 +2283,13 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) } // when we add the first nexthop to the route, we dont create a nexthop group, we call the updateTunnelRoute with NHG with one member. // when adding the 2nd, 3rd ... members we create each NH using this create_next_hop_group_member call but give it the reference of next_hop_group_id. - // this way we dont have to update the route, the syncd does it by itself. we only call the updateTunnelRoute to add/remove when adding the route and - // removing it fully. + // this way we dont have to update the route, the syncd does it by itself. we only call the updateTunnelRoute to add/remove when adding or removing the + // route fully. + bool failed = false; if (state == SAI_BFD_SESSION_STATE_UP) { + SWSS_LOG_INFO("Processing BFD state change to UP.\n"); sai_object_id_t next_hop_group_member_id = SAI_NULL_OBJECT_ID; if (nexthops.getSize() > 1) { @@ -2340,19 +2339,21 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) { for (auto ip_pfx : syncd_nexthop_groups_[vnet][nexthops].tunnel_routes) { - // remove the bgp learnt routr first if any and then add the tunnel route. - SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", - ip_pfx.to_string().c_str()); - if (!gRouteOrch->removeRouteIfExists(ip_pfx)) + // remove the bgp learnt route first if any exists and then add the tunnel route. + auto prefixStr = ip_pfx.to_string(); + auto nhStr = nexthops.to_string(); + SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", prefixStr.c_str()); + if (gRouteOrch && !gRouteOrch->removeRouteIfExists(ip_pfx)) { - SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", ip_pfx.to_string().c_str()); + SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", prefixStr.c_str()); failed = true; break; } string op = SET_COMMAND; + SWSS_LOG_NOTICE("Adding Vnet route for prefix : %s with nexthops %s\n", - ip_pfx.to_string().c_str(), - nexthops.to_string().c_str()); + prefixStr.c_str(), + nhStr.c_str()); if (!updateTunnelRoute(vnet, ip_pfx, nexthops, op)) { @@ -2362,7 +2363,7 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) else { SWSS_LOG_INFO("Successfully created tunnel route in hardware for prefix : %s\n", - ip_pfx.to_string().c_str()); + prefixStr.c_str()); } } } @@ -2380,6 +2381,7 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) } else { + SWSS_LOG_INFO("Processing BFD state change to Down.\n"); if (nexthops.getSize() > 1 && nhg_info.active_members.find(endpoint) != nhg_info.active_members.end()) { sai_object_id_t nexthop_id = nhg_info.active_members[endpoint]; @@ -2397,6 +2399,7 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) } vrf_obj->removeTunnelNextHop(endpoint); + SWSS_LOG_INFO("Successfully removed Nexthop. %s\n",endpoint.to_string().c_str() ); gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP_MEMBER); } @@ -2426,6 +2429,8 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) for (auto ip_pfx : syncd_nexthop_groups_[vnet][nexthops].tunnel_routes) { string profile = vrf_obj->getProfile(ip_pfx); + SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile \n", + ip_pfx.to_string().c_str(), profile.c_str()); postRouteState(vnet, ip_pfx, nexthops, profile); } } @@ -2565,11 +2570,21 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) if (active_nhg_size > 0) { // we need to replace the nhg in the route + SWSS_LOG_NOTICE("Replacing Nexthop Group for prefix: %s \n", + prefix.to_string().c_str, nhg_custom.to_string().c_str()); route_status = update_route(vr_id, pfx, nh_id); } else { // we need to readd the route. + SWSS_LOG_NOTICE("Adding Custom monitored Route with prefix: %s and NExthop %s \n", + prefix.to_string().c_str, nhg_custom.to_string().c_str()); + SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", prefixStr.c_str()); + if (gRouteOrch && !gRouteOrch->removeRouteIfExists(prefix)) + { + SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", prefix.c_str()); + route_status = false; + } route_status = add_route(vr_id, pfx, nh_id); } if (!route_status) @@ -2625,6 +2640,8 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) if (nhg_custom.getSize() == 0 && active_nhg_size > 0) { vrf_obj->removeRoute(prefix); + SWSS_LOG_NOTICE("Route prefix id no longer active: %s \n", + prefix.to_string().c_str()); removeRouteState(vnet, prefix); if (prefix_to_adv_prefix_.find(prefix) != prefix_to_adv_prefix_.end()) { @@ -2633,6 +2650,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) if (adv_prefix_refcount_[adv_pfx] == 0) { adv_prefix_refcount_.erase(adv_pfx); + SWSS_LOG_NOTICE("Stopping advertisement of prefix Range: %s \n",adv_pfx.to_string().c_str()); } } } @@ -2645,10 +2663,14 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) } adv_prefix_refcount_[adv_prefix] += 1; string profile = vrf_obj->getProfile(prefix); + SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile \n", + prefix.to_string().c_str(), profile.c_str()); postRouteState(vnet, prefix, nhg_custom, profile); } else { + SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile \n", + prefix.to_string().c_str(), profile.c_str()); string profile = vrf_obj->getProfile(prefix); postRouteState(vnet, prefix, nhg_custom, profile); } diff --git a/tests/test_vnet.py b/tests/test_vnet.py index 75e9aeeabe..caad0b4a25 100644 --- a/tests/test_vnet.py +++ b/tests/test_vnet.py @@ -2334,9 +2334,9 @@ def test_vnet_orch_24(self, dvs, testlog): vnet_obj.fetch_exist_entries(dvs) # create vnet route - create_vnet_routes(dvs, "100.100.1.0/24", 'Vnet_2000', '10.10.10.6') - vnet_obj.check_vnet_routes(dvs, 'Vnet_2000', '10.10.10.6', tunnel_name) - check_state_db_routes(dvs, 'Vnet_2000', "100.100.1.0/24", ['10.10.10.6']) + create_vnet_routes(dvs, "100.100.1.0/24", 'Vnet_2000', '10.10.10.3') + vnet_obj.check_vnet_routes(dvs, 'Vnet_2000', '10.10.10.3', tunnel_name) + check_state_db_routes(dvs, 'Vnet_2000', "100.100.1.0/24", ['10.10.10.3']) time.sleep(2) # create l3 interface @@ -2349,14 +2349,14 @@ def test_vnet_orch_24(self, dvs, testlog): self.set_admin_status("Ethernet0", "up") # set ip address and default route - dvs.servers[0].runcmd("ip address add 10.10.10.6/24 dev eth0") + dvs.servers[0].runcmd("ip address add 10.10.10.3/24 dev eth0") dvs.servers[0].runcmd("ip route add default via 10.10.10.1") marker = dvs.add_log_marker("/var/log/syslog") time.sleep(2) # add another route for same prefix as vnet route - dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 100.100.1.0/24 10.10.10.6\"") + dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 100.100.1.0/24 10.10.10.3\"") # check application database self.pdb.wait_for_entry("ROUTE_TABLE", "100.100.1.0/24") @@ -2369,7 +2369,7 @@ def test_vnet_orch_24(self, dvs, testlog): check_syslog(dvs, marker, log_string) # remove route entry - dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 100.100.1.0/24 10.10.10.6\"") + dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 100.100.1.0/24 10.10.10.3\"") # delete vnet route delete_vnet_routes(dvs, "100.100.1.0/24", 'Vnet_2000') diff --git a/tests/test_vnet2.py b/tests/test_vnet2.py index 329b8f1999..efc6ec4695 100644 --- a/tests/test_vnet2.py +++ b/tests/test_vnet2.py @@ -89,8 +89,8 @@ def _access_function(): def test_vnet_orch_1(self, dvs, testlog): vnet_obj = self.get_vnet_obj() - tunnel_name = 'tunnel_29' - vnet_name = 'Vnet29' + tunnel_name = 'tunnel_1' + vnet_name = 'Vnet1' self.setup_db(dvs) vnet_obj.fetch_exist_entries(dvs) # create l3 interface and bring it up @@ -106,9 +106,9 @@ def test_vnet_orch_1(self, dvs, testlog): # create vxlan tunnel and verfiy it create_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') - create_vnet_entry(dvs, vnet_name, tunnel_name, '10029', "") + create_vnet_entry(dvs, vnet_name, tunnel_name, '1001', "") vnet_obj.check_vnet_entry(dvs, vnet_name) - vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '10029') + vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '1001') vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') vnet_obj.fetch_exist_entries(dvs) @@ -213,8 +213,8 @@ def test_vnet_orch_1(self, dvs, testlog): Test 2 - Test for vnet tunnel routes interaction with regular route with endpoints bieng up. Add the conflicting route and then add the vnet route with same nexthops. Bring up the bfd sessions and check the vnet route is programmed in hardware. - Add the 2nd conflicting route and then add the 2nd vnet route with same nexthops. - This way we check if the preceding route works of mexthops are already UP. + Add the 2nd conflicting route and then add the 2nd vnet route with same nexthops as first vnet route. + This way we check if the newly added route works when the nexthops are already UP. Verify the vnet routes are programmed in hardware. Remove all the vnet route and check the vnet route is removed. Remove all the conflicting route and check the conflicting route is removed. @@ -222,8 +222,8 @@ def test_vnet_orch_1(self, dvs, testlog): def test_vnet_orch_2(self, dvs, testlog): vnet_obj = self.get_vnet_obj() - tunnel_name = 'tunnel_30' - vnet_name = 'Vnet30' + tunnel_name = 'tunnel_2' + vnet_name = 'Vnet2' self.setup_db(dvs) vnet_obj.fetch_exist_entries(dvs) @@ -240,9 +240,9 @@ def test_vnet_orch_2(self, dvs, testlog): # create vxlan tunnel and verfiy it create_vxlan_tunnel(dvs, tunnel_name, '9.8.8.9') - create_vnet_entry(dvs, vnet_name, tunnel_name, '10030', "") + create_vnet_entry(dvs, vnet_name, tunnel_name, '1002', "") vnet_obj.check_vnet_entry(dvs, vnet_name) - vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '10030') + vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '1002') vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.8.8.9') vnet_obj.fetch_exist_entries(dvs) @@ -314,6 +314,126 @@ def test_vnet_orch_2(self, dvs, testlog): vnet_obj.check_del_vnet_entry(dvs, vnet_name) delete_vxlan_tunnel(dvs, tunnel_name) + + ''' + Test 3 - Test for vnet tunnel routes (custom monitoring) interaction with regular route. + Add the conflicting route and then add the vnet route with same nexthops. + Bring up the bfd sessions and check the vnet route is programmed in hardware. + Remove the vnet route and check the vnet route is removed. + Remove the conflicting route and check the conflicting route is removed. + ''' + def test_vnet_orch_3(self, dvs, testlog): + vnet_obj = self.get_vnet_obj() + + tunnel_name = 'tunnel_3' + vnet_name = 'Vnet3' + self.setup_db(dvs) + vnet_obj.fetch_exist_entries(dvs) + # create l3 interface and bring it up + self.create_l3_intf("Ethernet0", "") + self.add_ip_address("Ethernet0", "10.10.10.1/24") + self.set_admin_status("Ethernet0", "down") + time.sleep(1) + self.set_admin_status("Ethernet0", "up") + + # set ip address and default route + dvs.servers[0].runcmd("ip address add 10.10.10.7/24 dev eth0") + dvs.servers[0].runcmd("ip route add default via 10.10.10.1") + + # create vxlan tunnel and verfiy it + create_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') + create_vnet_entry(dvs, vnet_name, tunnel_name, '1003', "") + vnet_obj.check_vnet_entry(dvs, vnet_name) + vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '1003') + vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') + + vnet_obj.fetch_exist_entries(dvs) + + # add conflicting route + dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 105.100.1.1/32 10.10.10.7\"") + + # check ASIC route database + self.check_route_entries(["105.100.1.1/32"]) + + create_vnet_routes(dvs, "105.100.1.1/32", vnet_name, '9.7.0.1,9.7.0.2,9.7.0.3,9.7.0.4', ep_monitor='9.1.2.1,9.1.2.2,9.1.2.3,9.1.2.3',primary='9.7.0.1,9.7.0.2', monitoring='custom') + + # default bfd status is down, route should not be programmed in this status + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["105.100.1.1/32"], absent=True) + check_state_db_routes(dvs, vnet_name, "105.100.1.1/32", []) + check_remove_routes_advertisement(dvs, "105.100.1.1/32") + + # Route should be properly configured when all bfd session states go up + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'Up') + time.sleep(1) + route1 = vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2'], tunnel_name) + + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.3', 'Up') + time.sleep(1) + route1= vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2'], tunnel_name, route_ids=route1) + + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'Up') + time.sleep(1) + route1= vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2,9.7.0.1'], tunnel_name, route_ids=route1) + check_state_db_routes(dvs, vnet_name, "105.100.1.1/32", ['9.7.0.1', '9.7.0.2']) + + # Remove all endpoint from group route shouldnt come back up. + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'Down') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'Down') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.3', 'Down') + time.sleep(1) + # after removal of vnet route, conflicting route is not getting programmed as its not a bgp learnt route. + self.check_route_entries(["105.100.1.1/32"], absent=True) + # Remove tunnel route 1 + delete_vnet_routes(dvs, "105.100.1.1/32", vnet_name) + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["105.100.1.1/32"]) + check_remove_state_db_routes(dvs, vnet_name, "105.100.1.1/32") + check_remove_routes_advertisement(dvs, "105.100.1.1/32") + + # Check the previous nexthop group is removed + vnet_obj.fetch_exist_entries(dvs) + assert nhg1_1 not in vnet_obj.nhgs + + vnet_obj.nhg_ids = {} + vnet_obj.fetch_exist_entries(dvs) + # readd the same route. + create_vnet_routes(dvs, "105.100.1.1/32", vnet_name, '9.7.0.1,9.7.0.2,9.7.0.3,9.7.0.4', ep_monitor='9.1.2.1,9.1.2.2,9.1.2.3,9.1.2.3',primary='9.7.0.1,9.7.0.2', monitoring='custom') + + # default bfd status is down, route should not be programmed in this status + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["105.100.1.1/32"], absent=True) + check_state_db_routes(dvs, vnet_name, "105.100.1.1/32", []) + check_remove_routes_advertisement(dvs, "105.100.1.1/32") + + # Route should be properly configured when all bfd session states go up + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'Up') + time.sleep(1) + route1 = vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2'], tunnel_name) + + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'Up') + time.sleep(1) + route1= vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2,9.7.0.1'], tunnel_name, route_ids=route1) + + # Remove all endpoint from group route shouldnt come back up. + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'Down') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'Down') + + time.sleep(1) + # after removal of vnet route, conflicting route is not getting programmed as its not a bgp learnt route. + self.check_route_entries(["105.100.1.1/32"], absent=True) + # Remove tunnel route 1 + delete_vnet_routes(dvs, "105.100.1.1/32", vnet_name) + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["105.100.1.1/32"]) + check_remove_state_db_routes(dvs, vnet_name, "105.100.1.1/32") + check_remove_routes_advertisement(dvs, "105.100.1.1/32") + + # Check the previous nexthop group is removed + vnet_obj.fetch_exist_entries(dvs) + assert nhg1_1 not in vnet_obj.nhgs + + dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 105.100.1.1/32\"") + delete_vnet_entry(dvs, vnet_name) + vnet_obj.check_del_vnet_entry(dvs, vnet_name) + delete_vxlan_tunnel(dvs, tunnel_name) + # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying def test_nonflaky_dummy(): From d73e33a849dbf33e421a9624f0e83e2b0c2fdfb0 Mon Sep 17 00:00:00 2001 From: siqbal1986 Date: Wed, 6 Nov 2024 02:34:22 +0000 Subject: [PATCH 04/18] fix for build --- orchagent/vnetorch.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index 487528a99e..b8652fd84e 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -2571,18 +2571,18 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) { // we need to replace the nhg in the route SWSS_LOG_NOTICE("Replacing Nexthop Group for prefix: %s \n", - prefix.to_string().c_str, nhg_custom.to_string().c_str()); + prefix.to_string().c_str(), nhg_custom.to_string().c_str()); route_status = update_route(vr_id, pfx, nh_id); } else { // we need to readd the route. SWSS_LOG_NOTICE("Adding Custom monitored Route with prefix: %s and NExthop %s \n", - prefix.to_string().c_str, nhg_custom.to_string().c_str()); - SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", prefixStr.c_str()); + prefix.to_string().c_str(), nhg_custom.to_string().c_str()); + SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", prefix.to_string().c_str()); if (gRouteOrch && !gRouteOrch->removeRouteIfExists(prefix)) { - SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", prefix.c_str()); + SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", prefix.to_string().c_str()); route_status = false; } route_status = add_route(vr_id, pfx, nh_id); @@ -2670,7 +2670,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) else { SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile \n", - prefix.to_string().c_str(), profile.c_str()); + prefix.to_string().c_str(), profile.to_string().c_str()); string profile = vrf_obj->getProfile(prefix); postRouteState(vnet, prefix, nhg_custom, profile); } From 7ab637b01347851689a3beb20a18c10d72c72682 Mon Sep 17 00:00:00 2001 From: siqbal1986 Date: Wed, 6 Nov 2024 02:53:58 +0000 Subject: [PATCH 05/18] fix --- orchagent/vnetorch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index b8652fd84e..29ff71c68c 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -2669,9 +2669,9 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) } else { + string profile = vrf_obj->getProfile(prefix); SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile \n", prefix.to_string().c_str(), profile.to_string().c_str()); - string profile = vrf_obj->getProfile(prefix); postRouteState(vnet, prefix, nhg_custom, profile); } } From a2c950f6574befe5aab43d433b5b59a6022d4dd7 Mon Sep 17 00:00:00 2001 From: siqbal1986 Date: Wed, 6 Nov 2024 04:08:58 +0000 Subject: [PATCH 06/18] another fix --- orchagent/vnetorch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index 29ff71c68c..bfe87a00a8 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -2671,7 +2671,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) { string profile = vrf_obj->getProfile(prefix); SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile \n", - prefix.to_string().c_str(), profile.to_string().c_str()); + prefix.to_string().c_str(), profile.c_str()); postRouteState(vnet, prefix, nhg_custom, profile); } } From cba6fc909065f893221eeec8a31ef8982b5426db Mon Sep 17 00:00:00 2001 From: siqbal1986 Date: Wed, 6 Nov 2024 04:49:13 +0000 Subject: [PATCH 07/18] compiler --- orchagent/vnetorch.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index bfe87a00a8..e2e63b3fbf 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -2399,7 +2399,7 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) } vrf_obj->removeTunnelNextHop(endpoint); - SWSS_LOG_INFO("Successfully removed Nexthop. %s\n",endpoint.to_string().c_str() ); + SWSS_LOG_INFO("Successfully removed Nexthop: %s\n",endpoint.to_string().c_str() ); gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP_MEMBER); } @@ -2429,7 +2429,7 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) for (auto ip_pfx : syncd_nexthop_groups_[vnet][nexthops].tunnel_routes) { string profile = vrf_obj->getProfile(ip_pfx); - SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile \n", + SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile: %s \n", ip_pfx.to_string().c_str(), profile.c_str()); postRouteState(vnet, ip_pfx, nexthops, profile); } @@ -2570,14 +2570,14 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) if (active_nhg_size > 0) { // we need to replace the nhg in the route - SWSS_LOG_NOTICE("Replacing Nexthop Group for prefix: %s \n", + SWSS_LOG_NOTICE("Replacing Nexthop Group for prefix: %s , nexthop group: %s\n", prefix.to_string().c_str(), nhg_custom.to_string().c_str()); route_status = update_route(vr_id, pfx, nh_id); } else { // we need to readd the route. - SWSS_LOG_NOTICE("Adding Custom monitored Route with prefix: %s and NExthop %s \n", + SWSS_LOG_NOTICE("Adding Custom monitored Route with prefix: %s and Nexthop %s \n", prefix.to_string().c_str(), nhg_custom.to_string().c_str()); SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", prefix.to_string().c_str()); if (gRouteOrch && !gRouteOrch->removeRouteIfExists(prefix)) @@ -2640,7 +2640,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) if (nhg_custom.getSize() == 0 && active_nhg_size > 0) { vrf_obj->removeRoute(prefix); - SWSS_LOG_NOTICE("Route prefix id no longer active: %s \n", + SWSS_LOG_NOTICE("Route prefix no longer active: %s \n", prefix.to_string().c_str()); removeRouteState(vnet, prefix); if (prefix_to_adv_prefix_.find(prefix) != prefix_to_adv_prefix_.end()) @@ -2663,14 +2663,14 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) } adv_prefix_refcount_[adv_prefix] += 1; string profile = vrf_obj->getProfile(prefix); - SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile \n", + SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile:%s \n", prefix.to_string().c_str(), profile.c_str()); postRouteState(vnet, prefix, nhg_custom, profile); } else { string profile = vrf_obj->getProfile(prefix); - SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile \n", + SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile: %s\n", prefix.to_string().c_str(), profile.c_str()); postRouteState(vnet, prefix, nhg_custom, profile); } From 21937a7c9c64700f2a4f6f06ac625434d566584b Mon Sep 17 00:00:00 2001 From: shahzad Iqbal Date: Thu, 7 Nov 2024 00:59:47 +0000 Subject: [PATCH 08/18] testfix --- tests/test_vnet2.py | 74 ++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/tests/test_vnet2.py b/tests/test_vnet2.py index efc6ec4695..7954d84518 100644 --- a/tests/test_vnet2.py +++ b/tests/test_vnet2.py @@ -95,14 +95,14 @@ def test_vnet_orch_1(self, dvs, testlog): vnet_obj.fetch_exist_entries(dvs) # create l3 interface and bring it up self.create_l3_intf("Ethernet0", "") - self.add_ip_address("Ethernet0", "10.10.10.1/24") + self.add_ip_address("Ethernet0", "20.20.20.1/24") self.set_admin_status("Ethernet0", "down") time.sleep(1) self.set_admin_status("Ethernet0", "up") # set ip address and default route - dvs.servers[0].runcmd("ip address add 10.10.10.5/24 dev eth0") - dvs.servers[0].runcmd("ip route add default via 10.10.10.1") + dvs.servers[0].runcmd("ip address add 20.20.20.5/24 dev eth0") + dvs.servers[0].runcmd("ip route add default via 20.20.20.1") # create vxlan tunnel and verfiy it create_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') @@ -114,7 +114,7 @@ def test_vnet_orch_1(self, dvs, testlog): vnet_obj.fetch_exist_entries(dvs) # add conflicting route - dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 103.100.1.1/32 10.10.10.5\"") + dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 103.100.1.1/32 20.20.20.5\"") # check ASIC route database self.check_route_entries(["103.100.1.1/32"]) @@ -229,14 +229,14 @@ def test_vnet_orch_2(self, dvs, testlog): # create l3 interface and bring it up self.create_l3_intf("Ethernet0", "") - self.add_ip_address("Ethernet0", "10.10.10.1/24") + self.add_ip_address("Ethernet0", "20.20.20.1/24") self.set_admin_status("Ethernet0", "down") time.sleep(1) self.set_admin_status("Ethernet0", "up") # set ip address and default route - dvs.servers[0].runcmd("ip address add 10.10.10.6/24 dev eth0") - dvs.servers[0].runcmd("ip route add default via 10.10.10.1") + dvs.servers[0].runcmd("ip address add 20.20.20.6/24 dev eth0") + dvs.servers[0].runcmd("ip route add default via 20.20.20.1") # create vxlan tunnel and verfiy it create_vxlan_tunnel(dvs, tunnel_name, '9.8.8.9') @@ -247,7 +247,7 @@ def test_vnet_orch_2(self, dvs, testlog): vnet_obj.fetch_exist_entries(dvs) # add conflicting route - dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 200.100.1.1/32 10.10.10.6\"") + dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 200.100.1.1/32 20.20.20.6\"") # check ASIC route database self.check_route_entries(["200.100.1.1/32"]) @@ -274,12 +274,12 @@ def test_vnet_orch_2(self, dvs, testlog): check_state_db_routes(dvs, vnet_name, "200.100.1.1/32", ['9.0.0.1', '9.0.0.2', '9.0.0.3']) # create a new regular and vnet route with same different prefix but same nexthops as before. - dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 200.200.1.1/32 10.10.10.6\"") + dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 200.200.1.1/32 20.20.20.6\"") # check ASIC route database self.check_route_entries(["200.200.1.1/32"]) create_vnet_routes(dvs, "200.200.1.1/32", vnet_name, '9.0.0.1,9.0.0.2,9.0.0.3', ep_monitor='9.1.0.1,9.1.0.2,9.1.0.3') - dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 200.100.1.1/32 10.10.10.6\"") + dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 200.100.1.1/32 20.20.20.6\"") # Remove all endpoint from group route shouldnt come back up. update_bfd_session_state(dvs, '9.1.0.2', 'Down') @@ -331,18 +331,18 @@ def test_vnet_orch_3(self, dvs, testlog): vnet_obj.fetch_exist_entries(dvs) # create l3 interface and bring it up self.create_l3_intf("Ethernet0", "") - self.add_ip_address("Ethernet0", "10.10.10.1/24") + self.add_ip_address("Ethernet0", "20.20.20.1/24") self.set_admin_status("Ethernet0", "down") time.sleep(1) self.set_admin_status("Ethernet0", "up") # set ip address and default route - dvs.servers[0].runcmd("ip address add 10.10.10.7/24 dev eth0") - dvs.servers[0].runcmd("ip route add default via 10.10.10.1") + dvs.servers[0].runcmd("ip address add 20.20.20.7/24 dev eth0") + dvs.servers[0].runcmd("ip route add default via 20.20.20.1") # create vxlan tunnel and verfiy it create_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') - create_vnet_entry(dvs, vnet_name, tunnel_name, '1003', "") + create_vnet_entry(dvs, vnet_name, tunnel_name, '1003', "", advertise_prefix=True, overlay_dmac="22:33:33:44:44:66") vnet_obj.check_vnet_entry(dvs, vnet_name) vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '1003') vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') @@ -350,36 +350,24 @@ def test_vnet_orch_3(self, dvs, testlog): vnet_obj.fetch_exist_entries(dvs) # add conflicting route - dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 105.100.1.1/32 10.10.10.7\"") + dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 105.100.1.1/32 20.20.20.7\"") # check ASIC route database self.check_route_entries(["105.100.1.1/32"]) - create_vnet_routes(dvs, "105.100.1.1/32", vnet_name, '9.7.0.1,9.7.0.2,9.7.0.3,9.7.0.4', ep_monitor='9.1.2.1,9.1.2.2,9.1.2.3,9.1.2.3',primary='9.7.0.1,9.7.0.2', monitoring='custom') - - # default bfd status is down, route should not be programmed in this status - vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["105.100.1.1/32"], absent=True) - check_state_db_routes(dvs, vnet_name, "105.100.1.1/32", []) - check_remove_routes_advertisement(dvs, "105.100.1.1/32") - - # Route should be properly configured when all bfd session states go up - update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'Up') + create_vnet_routes(dvs, "105.100.1.1/32", vnet_name, '9.7.0.1,9.7.0.2,9.7.0.3,9.7.0.4', ep_monitor='9.1.2.1,9.1.2.2,9.1.2.3,9.1.2.4',profile = "test_prf", primary='9.7.0.1,9.7.0.2', monitoring='custom',adv_prefix='105.100.1.1/32') + # Route should be properly configured when all monitor session states go up + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'up') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.3', 'up') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'up') time.sleep(1) - route1 = vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2'], tunnel_name) - - update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.3', 'Up') - time.sleep(1) - route1= vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2'], tunnel_name, route_ids=route1) - - update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'Up') - time.sleep(1) - route1= vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2,9.7.0.1'], tunnel_name, route_ids=route1) + route1= vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2,9.7.0.1'], tunnel_name) check_state_db_routes(dvs, vnet_name, "105.100.1.1/32", ['9.7.0.1', '9.7.0.2']) # Remove all endpoint from group route shouldnt come back up. - update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'Down') - update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'Down') - update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.3', 'Down') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'down') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'down') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.3', 'down') time.sleep(1) # after removal of vnet route, conflicting route is not getting programmed as its not a bgp learnt route. self.check_route_entries(["105.100.1.1/32"], absent=True) @@ -391,12 +379,11 @@ def test_vnet_orch_3(self, dvs, testlog): # Check the previous nexthop group is removed vnet_obj.fetch_exist_entries(dvs) - assert nhg1_1 not in vnet_obj.nhgs vnet_obj.nhg_ids = {} vnet_obj.fetch_exist_entries(dvs) # readd the same route. - create_vnet_routes(dvs, "105.100.1.1/32", vnet_name, '9.7.0.1,9.7.0.2,9.7.0.3,9.7.0.4', ep_monitor='9.1.2.1,9.1.2.2,9.1.2.3,9.1.2.3',primary='9.7.0.1,9.7.0.2', monitoring='custom') + create_vnet_routes(dvs, "105.100.1.1/32", vnet_name, '9.7.0.1,9.7.0.2,9.7.0.3,9.7.0.4', ep_monitor='9.1.2.1,9.1.2.2,9.1.2.3,9.1.2.4',primary='9.7.0.1,9.7.0.2', monitoring='custom') # default bfd status is down, route should not be programmed in this status vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["105.100.1.1/32"], absent=True) @@ -404,17 +391,17 @@ def test_vnet_orch_3(self, dvs, testlog): check_remove_routes_advertisement(dvs, "105.100.1.1/32") # Route should be properly configured when all bfd session states go up - update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'Up') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'up') time.sleep(1) route1 = vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2'], tunnel_name) - update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'Up') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'up') time.sleep(1) - route1= vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2,9.7.0.1'], tunnel_name, route_ids=route1) + vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.7.0.2,9.7.0.1'], tunnel_name) # Remove all endpoint from group route shouldnt come back up. - update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'Down') - update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'Down') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.2', 'down') + update_monitor_session_state(dvs, "105.100.1.1/32", '9.1.2.1', 'down') time.sleep(1) # after removal of vnet route, conflicting route is not getting programmed as its not a bgp learnt route. @@ -427,7 +414,6 @@ def test_vnet_orch_3(self, dvs, testlog): # Check the previous nexthop group is removed vnet_obj.fetch_exist_entries(dvs) - assert nhg1_1 not in vnet_obj.nhgs dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 105.100.1.1/32\"") delete_vnet_entry(dvs, vnet_name) From efce67474d09585870a2891fd20f8982edd91ae9 Mon Sep 17 00:00:00 2001 From: siqbal1986 Date: Thu, 7 Nov 2024 19:06:24 +0000 Subject: [PATCH 09/18] more logs for debugging --- orchagent/vnetorch.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index e2e63b3fbf..f6fe424ab4 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -989,6 +989,7 @@ bool VNetRouteOrch::selectNextHopGroup(const string& vnet, // This is followed by an attempt to create a NHG which can be subset of nexthops_primary // depending on the endpoint monitor state. If no NHG from primary is created, we attempt // the same for secondary. + SWSS_LOG_NOTICE("Route recieved with monitoring %s and secondary NHG %s.\n",monitoring.c_str(), nexthops_secondary.to_string().c_str()); if(nexthops_secondary.getSize() != 0 && monitoring == "custom") { auto it_route = syncd_tunnel_routes_[vnet].find(ipPrefix); @@ -2534,13 +2535,14 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) else { //both HHG's are inactive, need to remove the route. + SWSS_LOG_INFO(" Route needs to be removed due ot no active NHG.\n"); updateRoute = true; } if (nhg_custom.getSize() == 0) { // nhg_custom is empty. we shall create a dummy empty NHG for book keeping. - SWSS_LOG_INFO(" Neither Primary or Secondary endpoints are up."); + SWSS_LOG_INFO(" Neither Primary or Secondary endpoints are up.\n"); if (!hasNextHopGroup(vnet, nhg_custom)) { NextHopGroupInfo next_hop_group_entry; @@ -2558,6 +2560,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) { if (active_nhg_size > 0) { + SWSS_LOG_INFO(" Removing the route for prefix %s.",prefix.to_string().c_str()); // we need to remove the route del_route(vr_id, pfx); } @@ -2613,6 +2616,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) if(--syncd_nexthop_groups_[vnet][active_nhg].ref_count == 0) { + SWSS_LOG_INFO("refcount for NHG is zero %s\n",active_nhg.to_string().c_str()); if (active_nhg_size > 1) { removeNextHopGroup(vnet, active_nhg, vrf_obj); @@ -2629,8 +2633,10 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) } else { + SWSS_LOG_INFO("Prefix %s no longer references NHG %s \n",prefix.to_string().c_str(), active_nhg.to_string().c_str()); syncd_nexthop_groups_[vnet][active_nhg].tunnel_routes.erase(prefix); } + SWSS_LOG_INFO("Prefix %s references NHG %s \n",prefix.to_string().c_str(), nhg_custom.to_string().c_str()); syncd_nexthop_groups_[vnet][nhg_custom].tunnel_routes.insert(prefix); syncd_tunnel_routes_[vnet][prefix].nhg_key = nhg_custom; if (nhg_custom != active_nhg) @@ -2640,8 +2646,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) if (nhg_custom.getSize() == 0 && active_nhg_size > 0) { vrf_obj->removeRoute(prefix); - SWSS_LOG_NOTICE("Route prefix no longer active: %s \n", - prefix.to_string().c_str()); + SWSS_LOG_NOTICE("Route prefix no longer active: %s \n", prefix.to_string().c_str()); removeRouteState(vnet, prefix); if (prefix_to_adv_prefix_.find(prefix) != prefix_to_adv_prefix_.end()) { From 14fdc6631728cab90cfbe404eb4a7f8f57d06f1c Mon Sep 17 00:00:00 2001 From: siqbal1986 Date: Sun, 10 Nov 2024 01:45:38 +0000 Subject: [PATCH 10/18] fixed a bug found during testing --- orchagent/vnetorch.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index f6fe424ab4..5c3cfddf2a 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -1148,15 +1148,16 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP } else { + auto ipPrefixsubnet = ipPrefix.getSubnet(); SWSS_LOG_INFO("Attempting to remove BGP learnt route for prefix : %s\n", - ipPrefix.to_string().c_str()); - if (!gRouteOrch->removeRouteIfExists(ipPrefix)) + ipPrefixsubnet.to_string().c_str()); + if (gRouteOrch && !gRouteOrch->removeRouteIfExists(ipPrefixsubnet)) { - SWSS_LOG_ERROR("Couldn't Removed existing bgp route for prefix : %s\n", ipPrefix.to_string().c_str()); + SWSS_LOG_ERROR("Couldn't Removed existing bgp route for prefix : %s\n", ipPrefixsubnet.to_string().c_str()); return false; } SWSS_LOG_INFO("Successfully Removed existing bgp route for prefix : %s \n", - ipPrefix.to_string().c_str()); + ipPrefixsubnet.to_string().c_str()); if (it_route == syncd_tunnel_routes_[vnet].end()) { route_status = add_route(vr_id, pfx, nh_id); @@ -2341,20 +2342,19 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) for (auto ip_pfx : syncd_nexthop_groups_[vnet][nexthops].tunnel_routes) { // remove the bgp learnt route first if any exists and then add the tunnel route. - auto prefixStr = ip_pfx.to_string(); - auto nhStr = nexthops.to_string(); - SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", prefixStr.c_str()); - if (gRouteOrch && !gRouteOrch->removeRouteIfExists(ip_pfx)) + auto ipPrefixsubnet = ip_pfx.getSubnet(); + auto prefixStr = ip_pfx.to_string().c_str(); + auto nhStr = nexthops.to_string().c_str(); + SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", ipPrefixsubnet.to_string().c_str()); + if (gRouteOrch && !gRouteOrch->removeRouteIfExists(ipPrefixsubnet)) { - SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", prefixStr.c_str()); + SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", ipPrefixsubnet.to_string().c_str()); failed = true; break; } string op = SET_COMMAND; - SWSS_LOG_NOTICE("Adding Vnet route for prefix : %s with nexthops %s\n", - prefixStr.c_str(), - nhStr.c_str()); + SWSS_LOG_NOTICE("Adding Vnet route for prefix : %s with nexthops %s\n", prefixStr, nhStr); if (!updateTunnelRoute(vnet, ip_pfx, nexthops, op)) { @@ -2363,8 +2363,7 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) } else { - SWSS_LOG_INFO("Successfully created tunnel route in hardware for prefix : %s\n", - prefixStr.c_str()); + SWSS_LOG_INFO("Successfully created tunnel route in hardware for prefix : %s\n", prefixStr); } } } @@ -2582,10 +2581,11 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) // we need to readd the route. SWSS_LOG_NOTICE("Adding Custom monitored Route with prefix: %s and Nexthop %s \n", prefix.to_string().c_str(), nhg_custom.to_string().c_str()); - SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", prefix.to_string().c_str()); - if (gRouteOrch && !gRouteOrch->removeRouteIfExists(prefix)) + auto ipPrefixsubnet = prefix.getSubnet(); + SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", ipPrefixsubnet.to_string().c_str()); + if (gRouteOrch && !gRouteOrch->removeRouteIfExists(ipPrefixsubnet)) { - SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", prefix.to_string().c_str()); + SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", ipPrefixsubnet.to_string().c_str()); route_status = false; } route_status = add_route(vr_id, pfx, nh_id); From b756428751fb2b2558c984c27b0e516fadc2b9b9 Mon Sep 17 00:00:00 2001 From: shahzad Iqbal Date: Sat, 16 Nov 2024 23:55:08 +0000 Subject: [PATCH 11/18] improved the logs. --- orchagent/vnetorch.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index 5c3cfddf2a..d2107a1267 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -2125,7 +2125,10 @@ void VNetRouteOrch::postRouteState(const string& vnet, IpPrefix& ipPrefix, NextH route_state = "active"; prefix_to_use = adv_pfx; } - } + } + SWSS_LOG_NOTICE("advertisement of prefix: %s with profile: %s %s via %s\n", + ipPrefix.to_string().c_str(), profile.c_str(), + route_state.c_str(), prefix_to_use.to_string().c_str()); if (vnet_orch_->getAdvertisePrefix(vnet)) { if (route_state == "active") @@ -2151,6 +2154,7 @@ void VNetRouteOrch::removeRouteState(const string& vnet, IpPrefix& ipPrefix) { const string state_db_key = vnet + state_db_key_delimiter + ipPrefix.to_string(); state_vnet_rt_tunnel_table_->del(state_db_key); + SWSS_LOG_NOTICE("Stopping advertisement of prefix: %s\n", ipPrefix.to_string().c_str()); if(prefix_to_adv_prefix_.find(ipPrefix) !=prefix_to_adv_prefix_.end()) { @@ -2429,8 +2433,6 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) for (auto ip_pfx : syncd_nexthop_groups_[vnet][nexthops].tunnel_routes) { string profile = vrf_obj->getProfile(ip_pfx); - SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile: %s \n", - ip_pfx.to_string().c_str(), profile.c_str()); postRouteState(vnet, ip_pfx, nexthops, profile); } } @@ -2668,15 +2670,11 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) } adv_prefix_refcount_[adv_prefix] += 1; string profile = vrf_obj->getProfile(prefix); - SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile:%s \n", - prefix.to_string().c_str(), profile.c_str()); postRouteState(vnet, prefix, nhg_custom, profile); } else { string profile = vrf_obj->getProfile(prefix); - SWSS_LOG_NOTICE("Starting advertisement of prefix: %s with profile: %s\n", - prefix.to_string().c_str(), profile.c_str()); postRouteState(vnet, prefix, nhg_custom, profile); } } From f671f71aa8d9bc0d89c7f3f58f13e7e9a36b6afc Mon Sep 17 00:00:00 2001 From: shahzad Iqbal Date: Fri, 22 Nov 2024 19:27:50 +0000 Subject: [PATCH 12/18] fix a bug. --- orchagent/vnetorch.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index d2107a1267..bbd15af74c 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -773,6 +773,8 @@ bool VNetRouteOrch::addNextHopGroup(const string& vnet, const NextHopGroupKey &n { continue; } + SWSS_LOG_INFO("monitoring(%s), nexthop exists %d", it.ip_address.to_string().c_str(), + nexthop_info_[vnet].find(it.ip_address) != nexthop_info_[vnet].end() ); sai_object_id_t next_hop_id = vrf_obj->getTunnelNextHop(it); next_hop_ids.push_back(next_hop_id); nhopgroup_members_set[next_hop_id] = it; @@ -926,6 +928,7 @@ bool VNetRouteOrch::createNextHopGroup(const string& vnet, next_hop_group_entry.ref_count = 0; if (monitoring == "custom" || nexthop_info_[vnet].find(nexthop.ip_address) == nexthop_info_[vnet].end() || nexthop_info_[vnet][nexthop.ip_address].bfd_state == SAI_BFD_SESSION_STATE_UP) { + SWSS_LOG_INFO("Adding next hop to the active group %s", nexthop.ip_address.to_string().c_str()); next_hop_group_entry.active_members[nexthop] = SAI_NULL_OBJECT_ID; } syncd_nexthop_groups_[vnet][nexthops] = next_hop_group_entry; @@ -1893,6 +1896,7 @@ void VNetRouteOrch::removeBfdSession(const string& vnet, const NextHopKey& endpo { SWSS_LOG_ERROR("BFD session for endpoint %s does not exist", endpoint_addr.to_string().c_str()); } + SWSS_LOG_INFO("removing nexthop info for endpoint %s", endpoint_addr.to_string().c_str()); nexthop_info_[vnet].erase(endpoint_addr); string key = "default:default:" + monitor_addr.to_string(); @@ -2118,15 +2122,17 @@ void VNetRouteOrch::postRouteState(const string& vnet, IpPrefix& ipPrefix, NextH auto prefix_to_use = ipPrefix; if (prefix_to_adv_prefix_.find(ipPrefix) != prefix_to_adv_prefix_.end()) { - route_state = ""; auto adv_pfx = prefix_to_adv_prefix_[ipPrefix]; - if (adv_prefix_refcount_[adv_pfx] == 1) + if (route_state == "active" and adv_prefix_refcount_[adv_pfx] == 1) { - route_state = "active"; prefix_to_use = adv_pfx; } + else + { + route_state = ""; + } } - SWSS_LOG_NOTICE("advertisement of prefix: %s with profile: %s %s via %s\n", + SWSS_LOG_NOTICE("advertisement of prefix: %s with profile:%s, status: %s via %s\n", ipPrefix.to_string().c_str(), profile.c_str(), route_state.c_str(), prefix_to_use.to_string().c_str()); if (vnet_orch_->getAdvertisePrefix(vnet)) From bbce5e0f70f628e6793f0cc86e7445ec280300ed Mon Sep 17 00:00:00 2001 From: shahzad Iqbal Date: Thu, 28 Nov 2024 21:17:39 +0000 Subject: [PATCH 13/18] cleanup --- orchagent/routeorch.cpp | 29 ++++++++++- orchagent/routeorch.h | 3 +- orchagent/vnetorch.cpp | 111 +++++++++++++++++++++++----------------- 3 files changed, 95 insertions(+), 48 deletions(-) diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index 7e269938b8..c730252293 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -2639,7 +2639,34 @@ bool RouteOrch::removeRoutePost(const RouteBulkContext& ctx) return true; } -bool RouteOrch::removeRouteIfExists(const IpPrefix& prefix) +bool RouteOrch::isBgpRouteExists(const IpPrefix& prefix) +{ + SWSS_LOG_ENTER(); + + sai_object_id_t& vrf_id = gVirtualRouterId; + + sai_route_entry_t route_entry; + route_entry.vr_id = vrf_id; + route_entry.switch_id = gSwitchId; + copy(route_entry.destination, prefix); + auto it_route_table = m_syncdRoutes.find(vrf_id); + if (it_route_table == m_syncdRoutes.end()) + { + SWSS_LOG_INFO("Failed to find route table, vrf_id 0x%" PRIx64 "\n", vrf_id); + return true; + } + auto it_route = it_route_table->second.find(prefix); + size_t creating = gRouteBulker.creating_entries_count(route_entry); + if (it_route == it_route_table->second.end() && creating == 0) + { + SWSS_LOG_INFO("No Route exists for vrf_id 0x%" PRIx64 ", prefix %s\n", vrf_id, + prefix.to_string().c_str()); + return false; + } + return true; +} + +bool RouteOrch::removeRoutePrefix(const IpPrefix& prefix) { // This function removes the route if it exists. diff --git a/orchagent/routeorch.h b/orchagent/routeorch.h index d047c85e21..a003c513d6 100644 --- a/orchagent/routeorch.h +++ b/orchagent/routeorch.h @@ -215,7 +215,8 @@ class RouteOrch : public Orch, public Subject const NextHopGroupKey getSyncdRouteNhgKey(sai_object_id_t vrf_id, const IpPrefix& ipPrefix); bool createFineGrainedNextHopGroup(sai_object_id_t &next_hop_group_id, vector &nhg_attrs); bool removeFineGrainedNextHopGroup(sai_object_id_t &next_hop_group_id); - bool removeRouteIfExists(const IpPrefix& prefix); + bool isBgpRouteExists(const IpPrefix& prefix); + bool removeRoutePrefix(const IpPrefix& prefix); void addLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix); void delLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix); diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index bbd15af74c..81e3f9bc8a 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -773,8 +773,6 @@ bool VNetRouteOrch::addNextHopGroup(const string& vnet, const NextHopGroupKey &n { continue; } - SWSS_LOG_INFO("monitoring(%s), nexthop exists %d", it.ip_address.to_string().c_str(), - nexthop_info_[vnet].find(it.ip_address) != nexthop_info_[vnet].end() ); sai_object_id_t next_hop_id = vrf_obj->getTunnelNextHop(it); next_hop_ids.push_back(next_hop_id); nhopgroup_members_set[next_hop_id] = it; @@ -928,7 +926,7 @@ bool VNetRouteOrch::createNextHopGroup(const string& vnet, next_hop_group_entry.ref_count = 0; if (monitoring == "custom" || nexthop_info_[vnet].find(nexthop.ip_address) == nexthop_info_[vnet].end() || nexthop_info_[vnet][nexthop.ip_address].bfd_state == SAI_BFD_SESSION_STATE_UP) { - SWSS_LOG_INFO("Adding next hop to the active group %s", nexthop.ip_address.to_string().c_str()); + SWSS_LOG_INFO("Adding nexthop: %s to the active group", nexthop.ip_address.to_string().c_str()); next_hop_group_entry.active_members[nexthop] = SAI_NULL_OBJECT_ID; } syncd_nexthop_groups_[vnet][nexthops] = next_hop_group_entry; @@ -992,7 +990,8 @@ bool VNetRouteOrch::selectNextHopGroup(const string& vnet, // This is followed by an attempt to create a NHG which can be subset of nexthops_primary // depending on the endpoint monitor state. If no NHG from primary is created, we attempt // the same for secondary. - SWSS_LOG_NOTICE("Route recieved with monitoring %s and secondary NHG %s.\n",monitoring.c_str(), nexthops_secondary.to_string().c_str()); + SWSS_LOG_NOTICE("Route recieved with monitoring (%s) and secondary nexthop group: %s.\n",monitoring.c_str(), + nexthops_secondary.to_string().c_str()); if(nexthops_secondary.getSize() != 0 && monitoring == "custom") { auto it_route = syncd_tunnel_routes_[vnet].find(ipPrefix); @@ -1151,16 +1150,22 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP } else { - auto ipPrefixsubnet = ipPrefix.getSubnet(); - SWSS_LOG_INFO("Attempting to remove BGP learnt route for prefix : %s\n", - ipPrefixsubnet.to_string().c_str()); - if (gRouteOrch && !gRouteOrch->removeRouteIfExists(ipPrefixsubnet)) + auto prefixToRemove = ipPrefix; + if (adv_prefix.to_string() != ipPrefix.to_string()) { - SWSS_LOG_ERROR("Couldn't Removed existing bgp route for prefix : %s\n", ipPrefixsubnet.to_string().c_str()); - return false; + prefixToRemove = adv_prefix; + } + auto prefixSubnet = prefixToRemove.getSubnet(); + if(gRouteOrch && gRouteOrch->isBgpRouteExists(prefixSubnet)) + { + if (!gRouteOrch->removeRoutePrefix(prefixSubnet)) + { + SWSS_LOG_ERROR("Could not remove existing bgp route for prefix: %s\n", prefixSubnet.to_string().c_str()); + return false; + } + SWSS_LOG_INFO("Successfully removed existing bgp route for prefix: %s\n", + prefixSubnet.to_string().c_str()); } - SWSS_LOG_INFO("Successfully Removed existing bgp route for prefix : %s \n", - ipPrefixsubnet.to_string().c_str()); if (it_route == syncd_tunnel_routes_[vnet].end()) { route_status = add_route(vr_id, pfx, nh_id); @@ -1309,7 +1314,7 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP SWSS_LOG_ERROR("Route del failed for %s, vr_id '0x%" PRIx64, ipPrefix.to_string().c_str(), vr_id); return false; } - SWSS_LOG_INFO("Successfully deleted the route for %s", ipPrefix.to_string().c_str()); + SWSS_LOG_INFO("Successfully deleted the route for prefix: %s", ipPrefix.to_string().c_str()); } } @@ -1896,7 +1901,7 @@ void VNetRouteOrch::removeBfdSession(const string& vnet, const NextHopKey& endpo { SWSS_LOG_ERROR("BFD session for endpoint %s does not exist", endpoint_addr.to_string().c_str()); } - SWSS_LOG_INFO("removing nexthop info for endpoint %s", endpoint_addr.to_string().c_str()); + SWSS_LOG_INFO("Removing nexthop info for endpoint: %s\n", endpoint_addr.to_string().c_str()); nexthop_info_[vnet].erase(endpoint_addr); string key = "default:default:" + monitor_addr.to_string(); @@ -2132,7 +2137,7 @@ void VNetRouteOrch::postRouteState(const string& vnet, IpPrefix& ipPrefix, NextH route_state = ""; } } - SWSS_LOG_NOTICE("advertisement of prefix: %s with profile:%s, status: %s via %s\n", + SWSS_LOG_NOTICE("Advertisement of prefix: %s with profile: %s, status: %s via prefix: %s\n", ipPrefix.to_string().c_str(), profile.c_str(), route_state.c_str(), prefix_to_use.to_string().c_str()); if (vnet_orch_->getAdvertisePrefix(vnet)) @@ -2160,7 +2165,7 @@ void VNetRouteOrch::removeRouteState(const string& vnet, IpPrefix& ipPrefix) { const string state_db_key = vnet + state_db_key_delimiter + ipPrefix.to_string(); state_vnet_rt_tunnel_table_->del(state_db_key); - SWSS_LOG_NOTICE("Stopping advertisement of prefix: %s\n", ipPrefix.to_string().c_str()); + SWSS_LOG_NOTICE("Advertisement of prefix: %s stopped.\n", ipPrefix.to_string().c_str()); if(prefix_to_adv_prefix_.find(ipPrefix) !=prefix_to_adv_prefix_.end()) { @@ -2301,7 +2306,6 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) bool failed = false; if (state == SAI_BFD_SESSION_STATE_UP) { - SWSS_LOG_INFO("Processing BFD state change to UP.\n"); sai_object_id_t next_hop_group_member_id = SAI_NULL_OBJECT_ID; if (nexthops.getSize() > 1) { @@ -2353,34 +2357,43 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) { // remove the bgp learnt route first if any exists and then add the tunnel route. auto ipPrefixsubnet = ip_pfx.getSubnet(); - auto prefixStr = ip_pfx.to_string().c_str(); - auto nhStr = nexthops.to_string().c_str(); - SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", ipPrefixsubnet.to_string().c_str()); - if (gRouteOrch && !gRouteOrch->removeRouteIfExists(ipPrefixsubnet)) + auto prefixStr = ip_pfx.to_string(); + auto nhStr = nexthops.to_string(); + if (prefix_to_adv_prefix_.find(ip_pfx) != prefix_to_adv_prefix_.end()) { - SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", ipPrefixsubnet.to_string().c_str()); - failed = true; - break; + auto adv_prefix = prefix_to_adv_prefix_[ip_pfx]; + if(adv_prefix.to_string() != prefixStr) + { + ipPrefixsubnet = adv_prefix.getSubnet(); + } + } + if(gRouteOrch && gRouteOrch->isBgpRouteExists(ipPrefixsubnet)) + { + if (!gRouteOrch->removeRoutePrefix(ipPrefixsubnet)) + { + SWSS_LOG_ERROR("Could not remove existing bgp route for prefix: %s\n", prefixStr.c_str()); + return; + } + SWSS_LOG_INFO("Successfully removed existing bgp route for prefix: %s\n", prefixStr.c_str()); } string op = SET_COMMAND; - - SWSS_LOG_NOTICE("Adding Vnet route for prefix : %s with nexthops %s\n", prefixStr, nhStr); + SWSS_LOG_INFO("Adding Vnet route for prefix:%s with nexthop group: %s\n", prefixStr.c_str(), nhStr.c_str()); if (!updateTunnelRoute(vnet, ip_pfx, nexthops, op)) { - SWSS_LOG_NOTICE("Failed to create tunnel route in hardware for prefix : %s\n", ip_pfx.to_string().c_str()); + SWSS_LOG_NOTICE("Failed to create tunnel route in hardware for prefix: %s\n", prefixStr.c_str()); failed = true; } else { - SWSS_LOG_INFO("Successfully created tunnel route in hardware for prefix : %s\n", prefixStr); + SWSS_LOG_INFO("Successfully created tunnel route in hardware for prefix: %s\n", prefixStr.c_str()); } } } if (failed) { // This is an unrecoverable error, Throw a LOG_ERROR and return - SWSS_LOG_ERROR("Inconsistant Hardware State. Failed to create tunnel routes\n"); + SWSS_LOG_ERROR("Inconsistant Hardware State. Failed to create tunnel routes.\n"); return; } } @@ -2391,7 +2404,6 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) } else { - SWSS_LOG_INFO("Processing BFD state change to Down.\n"); if (nexthops.getSize() > 1 && nhg_info.active_members.find(endpoint) != nhg_info.active_members.end()) { sai_object_id_t nexthop_id = nhg_info.active_members[endpoint]; @@ -2409,7 +2421,7 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) } vrf_obj->removeTunnelNextHop(endpoint); - SWSS_LOG_INFO("Successfully removed Nexthop: %s\n",endpoint.to_string().c_str() ); + SWSS_LOG_INFO("Successfully removed nexthop: %s\n",endpoint.to_string().c_str() ); gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP_MEMBER); } @@ -2425,7 +2437,7 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) { for (auto ip_pfx : syncd_nexthop_groups_[vnet][nexthops].tunnel_routes) { - SWSS_LOG_NOTICE("Removing Vnet route for prefix : %s due to no nexthops.\n",ip_pfx.to_string().c_str()); + SWSS_LOG_NOTICE("Removing Vnet route for prefix : %s due to no active nexthops.\n",ip_pfx.to_string().c_str()); string op = DEL_COMMAND; updateTunnelRoute(vnet, ip_pfx, nexthops, op); } @@ -2542,7 +2554,6 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) else { //both HHG's are inactive, need to remove the route. - SWSS_LOG_INFO(" Route needs to be removed due ot no active NHG.\n"); updateRoute = true; } @@ -2567,7 +2578,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) { if (active_nhg_size > 0) { - SWSS_LOG_INFO(" Removing the route for prefix %s.",prefix.to_string().c_str()); + SWSS_LOG_INFO(" Removing the route for prefix: %s.",prefix.to_string().c_str()); // we need to remove the route del_route(vr_id, pfx); } @@ -2580,21 +2591,31 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) if (active_nhg_size > 0) { // we need to replace the nhg in the route - SWSS_LOG_NOTICE("Replacing Nexthop Group for prefix: %s , nexthop group: %s\n", + SWSS_LOG_INFO("Replacing nexthop group for prefix: %s, nexthop group: %s\n", prefix.to_string().c_str(), nhg_custom.to_string().c_str()); route_status = update_route(vr_id, pfx, nh_id); } else { // we need to readd the route. - SWSS_LOG_NOTICE("Adding Custom monitored Route with prefix: %s and Nexthop %s \n", + SWSS_LOG_NOTICE("Adding Custom monitored Route with prefix: %s and nexthop group: %s\n", prefix.to_string().c_str(), nhg_custom.to_string().c_str()); - auto ipPrefixsubnet = prefix.getSubnet(); - SWSS_LOG_INFO("Attempting to remove BGP learnt route if it exists for prefix: %s\n", ipPrefixsubnet.to_string().c_str()); - if (gRouteOrch && !gRouteOrch->removeRouteIfExists(ipPrefixsubnet)) + auto prefixsubnet = prefix.getSubnet(); + if (prefix_to_adv_prefix_.find(prefix) != prefix_to_adv_prefix_.end()) { - SWSS_LOG_NOTICE("Couldnt Removed bgp route for prefix : %s\n", ipPrefixsubnet.to_string().c_str()); - route_status = false; + auto adv_prefix = prefix_to_adv_prefix_[prefix]; + if(adv_prefix.to_string() != prefix.to_string()) + { + prefixsubnet = adv_prefix.getSubnet(); + } + } + if (gRouteOrch && gRouteOrch->isBgpRouteExists(prefixsubnet)) + { + if (!gRouteOrch->removeRoutePrefix(prefixsubnet)) + { + SWSS_LOG_ERROR("Could not remove existing bgp route for prefix: %s\n", prefix.to_string().c_str()); + } + SWSS_LOG_INFO("Successfully removed existing bgp route for prefix: %s\n", prefix.to_string().c_str()); } route_status = add_route(vr_id, pfx, nh_id); } @@ -2624,7 +2645,6 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) if(--syncd_nexthop_groups_[vnet][active_nhg].ref_count == 0) { - SWSS_LOG_INFO("refcount for NHG is zero %s\n",active_nhg.to_string().c_str()); if (active_nhg_size > 1) { removeNextHopGroup(vnet, active_nhg, vrf_obj); @@ -2641,10 +2661,10 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) } else { - SWSS_LOG_INFO("Prefix %s no longer references NHG %s \n",prefix.to_string().c_str(), active_nhg.to_string().c_str()); + SWSS_LOG_INFO("Prefix %s no longer references nexthop group: %s\n",prefix.to_string().c_str(), active_nhg.to_string().c_str()); syncd_nexthop_groups_[vnet][active_nhg].tunnel_routes.erase(prefix); } - SWSS_LOG_INFO("Prefix %s references NHG %s \n",prefix.to_string().c_str(), nhg_custom.to_string().c_str()); + SWSS_LOG_INFO("Prefix %s now references nexthop group: %s\n",prefix.to_string().c_str(), nhg_custom.to_string().c_str()); syncd_nexthop_groups_[vnet][nhg_custom].tunnel_routes.insert(prefix); syncd_tunnel_routes_[vnet][prefix].nhg_key = nhg_custom; if (nhg_custom != active_nhg) @@ -2654,7 +2674,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) if (nhg_custom.getSize() == 0 && active_nhg_size > 0) { vrf_obj->removeRoute(prefix); - SWSS_LOG_NOTICE("Route prefix no longer active: %s \n", prefix.to_string().c_str()); + SWSS_LOG_NOTICE("Route prefix is no longer active: %s\n", prefix.to_string().c_str()); removeRouteState(vnet, prefix); if (prefix_to_adv_prefix_.find(prefix) != prefix_to_adv_prefix_.end()) { @@ -2663,7 +2683,6 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) if (adv_prefix_refcount_[adv_pfx] == 0) { adv_prefix_refcount_.erase(adv_pfx); - SWSS_LOG_NOTICE("Stopping advertisement of prefix Range: %s \n",adv_pfx.to_string().c_str()); } } } From a10fb7bf5c673012d20e63905a2994cc7fa22b58 Mon Sep 17 00:00:00 2001 From: shahzad Iqbal Date: Thu, 28 Nov 2024 21:36:15 +0000 Subject: [PATCH 14/18] missed a typo --- orchagent/vnetorch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index 81e3f9bc8a..472affa2a8 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -2393,7 +2393,7 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) if (failed) { // This is an unrecoverable error, Throw a LOG_ERROR and return - SWSS_LOG_ERROR("Inconsistant Hardware State. Failed to create tunnel routes.\n"); + SWSS_LOG_ERROR("Inconsistent hardware State. Failed to create tunnel routes.\n"); return; } } From 926fbcae65a697afc33993dc299935be9a465a18 Mon Sep 17 00:00:00 2001 From: shahzad Iqbal Date: Thu, 28 Nov 2024 23:16:06 +0000 Subject: [PATCH 15/18] alignment fix --- orchagent/routeorch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index c730252293..a8bc9c97a3 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -2676,7 +2676,7 @@ bool RouteOrch::removeRoutePrefix(const IpPrefix& prefix) context.vrf_id = gVirtualRouterId; if (removeRoute(context)) { - SWSS_LOG_INFO("Could not find the route with prefix %s", prefix.to_string().c_str()); + SWSS_LOG_INFO("Could not find the route with prefix %s", prefix.to_string().c_str()); return true; } gRouteBulker.flush(); From 7a1ef6f6641906e91afa7884e16ca071a8d11616 Mon Sep 17 00:00:00 2001 From: shahzad Iqbal Date: Fri, 29 Nov 2024 00:01:14 +0000 Subject: [PATCH 16/18] removed extra log --- orchagent/vnetorch.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index 472affa2a8..10ed65627c 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -990,8 +990,7 @@ bool VNetRouteOrch::selectNextHopGroup(const string& vnet, // This is followed by an attempt to create a NHG which can be subset of nexthops_primary // depending on the endpoint monitor state. If no NHG from primary is created, we attempt // the same for secondary. - SWSS_LOG_NOTICE("Route recieved with monitoring (%s) and secondary nexthop group: %s.\n",monitoring.c_str(), - nexthops_secondary.to_string().c_str()); + if(nexthops_secondary.getSize() != 0 && monitoring == "custom") { auto it_route = syncd_tunnel_routes_[vnet].find(ipPrefix); From 9b23cbccf490f4ec3b2541d08f8d28a120726236 Mon Sep 17 00:00:00 2001 From: shahzad Iqbal Date: Fri, 29 Nov 2024 05:29:35 +0000 Subject: [PATCH 17/18] renamed a function and updated a test --- orchagent/routeorch.cpp | 2 +- orchagent/routeorch.h | 2 +- orchagent/vnetorch.cpp | 6 +++--- tests/test_vnet2.py | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index a8bc9c97a3..070054c7af 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -2639,7 +2639,7 @@ bool RouteOrch::removeRoutePost(const RouteBulkContext& ctx) return true; } -bool RouteOrch::isBgpRouteExists(const IpPrefix& prefix) +bool RouteOrch::hasBgpRoute(const IpPrefix& prefix) { SWSS_LOG_ENTER(); diff --git a/orchagent/routeorch.h b/orchagent/routeorch.h index a003c513d6..a8c450a2de 100644 --- a/orchagent/routeorch.h +++ b/orchagent/routeorch.h @@ -215,7 +215,7 @@ class RouteOrch : public Orch, public Subject const NextHopGroupKey getSyncdRouteNhgKey(sai_object_id_t vrf_id, const IpPrefix& ipPrefix); bool createFineGrainedNextHopGroup(sai_object_id_t &next_hop_group_id, vector &nhg_attrs); bool removeFineGrainedNextHopGroup(sai_object_id_t &next_hop_group_id); - bool isBgpRouteExists(const IpPrefix& prefix); + bool hasBgpRoute(const IpPrefix& prefix); bool removeRoutePrefix(const IpPrefix& prefix); void addLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix); diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index 10ed65627c..afc30ec577 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -1155,7 +1155,7 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP prefixToRemove = adv_prefix; } auto prefixSubnet = prefixToRemove.getSubnet(); - if(gRouteOrch && gRouteOrch->isBgpRouteExists(prefixSubnet)) + if(gRouteOrch && gRouteOrch->hasBgpRoute(prefixSubnet)) { if (!gRouteOrch->removeRoutePrefix(prefixSubnet)) { @@ -2366,7 +2366,7 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) ipPrefixsubnet = adv_prefix.getSubnet(); } } - if(gRouteOrch && gRouteOrch->isBgpRouteExists(ipPrefixsubnet)) + if(gRouteOrch && gRouteOrch->hasBgpRoute(ipPrefixsubnet)) { if (!gRouteOrch->removeRoutePrefix(ipPrefixsubnet)) { @@ -2608,7 +2608,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) prefixsubnet = adv_prefix.getSubnet(); } } - if (gRouteOrch && gRouteOrch->isBgpRouteExists(prefixsubnet)) + if (gRouteOrch && gRouteOrch->hasBgpRoute(prefixsubnet)) { if (!gRouteOrch->removeRoutePrefix(prefixsubnet)) { diff --git a/tests/test_vnet2.py b/tests/test_vnet2.py index 7954d84518..9ed200f199 100644 --- a/tests/test_vnet2.py +++ b/tests/test_vnet2.py @@ -341,11 +341,11 @@ def test_vnet_orch_3(self, dvs, testlog): dvs.servers[0].runcmd("ip route add default via 20.20.20.1") # create vxlan tunnel and verfiy it - create_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') - create_vnet_entry(dvs, vnet_name, tunnel_name, '1003', "", advertise_prefix=True, overlay_dmac="22:33:33:44:44:66") + create_vxlan_tunnel(dvs, tunnel_name, '19.19.19.19') + create_vnet_entry(dvs, vnet_name, tunnel_name, '1003', "", '', advertise_prefix=True, overlay_dmac="22:33:33:44:44:66") vnet_obj.check_vnet_entry(dvs, vnet_name) vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '1003') - vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') + vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '19.19.19.19') vnet_obj.fetch_exist_entries(dvs) From e95c56f4bbcae878db43cd8c207c7f2406b0fa3c Mon Sep 17 00:00:00 2001 From: shahzad Iqbal Date: Sat, 30 Nov 2024 18:08:30 +0000 Subject: [PATCH 18/18] fixed a bug causing test failure. --- orchagent/vnetorch.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index afc30ec577..f148cf7784 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -913,7 +913,7 @@ bool VNetRouteOrch::createNextHopGroup(const string& vnet, VNetVrfObject *vrf_obj, const string& monitoring) { - + SWSS_LOG_INFO("Creating nexthop group from nexthops(%s)\n", nexthops.to_string().c_str()); if (nexthops.getSize() == 0) { return true; @@ -2512,6 +2512,8 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) copy(pfx, prefix); NextHopGroupKey nhg_custom_primary = getActiveNHSet( vnet, primary, prefix); NextHopGroupKey nhg_custom_secondary = getActiveNHSet( vnet, secondary, prefix); + SWSS_LOG_INFO("Primary active(%s), Secondary active (%s), Current active(%s)\n", nhg_custom_primary.to_string().c_str(), + nhg_custom_secondary.to_string().c_str(), active_nhg.to_string().c_str()); if (nhg_custom_primary.getSize() > 0) { if (nhg_custom_primary != active_nhg ) @@ -2599,15 +2601,16 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) // we need to readd the route. SWSS_LOG_NOTICE("Adding Custom monitored Route with prefix: %s and nexthop group: %s\n", prefix.to_string().c_str(), nhg_custom.to_string().c_str()); - auto prefixsubnet = prefix.getSubnet(); + auto prefixToUse = prefix; if (prefix_to_adv_prefix_.find(prefix) != prefix_to_adv_prefix_.end()) { auto adv_prefix = prefix_to_adv_prefix_[prefix]; if(adv_prefix.to_string() != prefix.to_string()) { - prefixsubnet = adv_prefix.getSubnet(); + prefixToUse = adv_prefix; } } + auto prefixsubnet = prefixToUse.getSubnet(); if (gRouteOrch && gRouteOrch->hasBgpRoute(prefixsubnet)) { if (!gRouteOrch->removeRoutePrefix(prefixsubnet)) @@ -2687,12 +2690,15 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) } else if (nhg_custom.getSize() > 0 && active_nhg_size == 0) { - auto adv_prefix = prefix_to_adv_prefix_[prefix]; - if (adv_prefix_refcount_.find(adv_prefix) == adv_prefix_refcount_.end()) + if (prefix_to_adv_prefix_.find(prefix) != prefix_to_adv_prefix_.end()) { - adv_prefix_refcount_[adv_prefix] = 0; + auto adv_prefix = prefix_to_adv_prefix_[prefix]; + if (adv_prefix_refcount_.find(adv_prefix) == adv_prefix_refcount_.end()) + { + adv_prefix_refcount_[adv_prefix] = 0; + } + adv_prefix_refcount_[adv_prefix] += 1; } - adv_prefix_refcount_[adv_prefix] += 1; string profile = vrf_obj->getProfile(prefix); postRouteState(vnet, prefix, nhg_custom, profile); }