From 8d57ae04c19af2472d063ef5a1cbc1598df241b4 Mon Sep 17 00:00:00 2001 From: Prince Sunny Date: Tue, 9 Oct 2018 22:04:45 -0700 Subject: [PATCH] VNET/VRF Changes (#632) * VNET/VRF Changes (#6) * VRF changes * Fixed an IPv6 address parsing issue * Updated logs, removed intfmgr changes in favour of PR #635 * Updated VRF table name * Addressed review comment, test fixes * Remove extra semi-colon * Route handling, review comments (#8) * Vnet route table handling * Addressed review comments * Fix for interface routes, add debug logs --- orchagent/Makefile.am | 2 + orchagent/intfsorch.cpp | 89 ++++-- orchagent/intfsorch.h | 10 +- orchagent/orch.cpp | 2 + orchagent/orch.h | 5 + orchagent/orchdaemon.cpp | 17 +- orchagent/orchdaemon.h | 1 + orchagent/port.h | 1 + orchagent/request_parser.cpp | 39 ++- orchagent/request_parser.h | 33 +++ orchagent/vnetorch.cpp | 512 +++++++++++++++++++++++++++++++++++ orchagent/vnetorch.h | 223 +++++++++++++++ orchagent/vrforch.h | 14 +- tests/request_parser_ut.cpp | 115 +++++++- tests/test_vrf.py | 40 +-- 15 files changed, 1054 insertions(+), 49 deletions(-) create mode 100644 orchagent/vnetorch.cpp create mode 100644 orchagent/vnetorch.h diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index 97d98cd692ca..3df5760938b8 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -43,6 +43,7 @@ orchagent_SOURCES = \ vrforch.cpp \ countercheckorch.cpp \ vxlanorch.cpp \ + vnetorch.cpp \ dtelorch.cpp \ flexcounterorch.cpp \ acltable.h \ @@ -74,6 +75,7 @@ orchagent_SOURCES = \ dtelorch.h \ countercheckorch.h \ vxlanorch.h \ + vnetorch.h \ flexcounterorch.h \ $(top_srcdir)/warmrestart/warm_restart.cpp \ $(top_srcdir)/warmrestart/warm_restart.h diff --git a/orchagent/intfsorch.cpp b/orchagent/intfsorch.cpp index cab07f62ae06..3111bccf899f 100644 --- a/orchagent/intfsorch.cpp +++ b/orchagent/intfsorch.cpp @@ -12,8 +12,11 @@ #include "routeorch.h" #include "crmorch.h" #include "bufferorch.h" +#include "directory.h" +#include "vnetorch.h" extern sai_object_id_t gVirtualRouterId; +extern Directory gDirectory; extern sai_router_interface_api_t* sai_router_intfs_api; extern sai_route_api_t* sai_route_api; @@ -27,8 +30,8 @@ extern BufferOrch *gBufferOrch; const int intfsorch_pri = 35; -IntfsOrch::IntfsOrch(DBConnector *db, string tableName) : - Orch(db, tableName, intfsorch_pri) +IntfsOrch::IntfsOrch(DBConnector *db, string tableName, VRFOrch *vrf_orch) : + Orch(db, tableName, intfsorch_pri), m_vrfOrch(vrf_orch) { SWSS_LOG_ENTER(); } @@ -113,7 +116,31 @@ void IntfsOrch::doTask(Consumer &consumer) vector keys = tokenize(kfvKey(t), ':'); string alias(keys[0]); - IpPrefix ip_prefix(kfvKey(t).substr(kfvKey(t).find(':')+1)); + IpPrefix ip_prefix; + bool ip_prefix_in_key = false; + + if (keys.size() > 1) + { + ip_prefix = kfvKey(t).substr(kfvKey(t).find(':')+1); + ip_prefix_in_key = true; + } + + const vector& data = kfvFieldsValues(t); + string vrf_name = "", vnet_name = ""; + + for (auto idx : data) + { + const auto &field = fvField(idx); + const auto &value = fvValue(idx); + if (field == "vrf_name") + { + vrf_name = value; + } + else if (field == "vnet_name") + { + vnet_name = value; + } + } if (alias == "eth0" || alias == "docker0") { @@ -121,12 +148,33 @@ void IntfsOrch::doTask(Consumer &consumer) continue; } + sai_object_id_t vrf_id = gVirtualRouterId; + if (!vnet_name.empty()) + { + VNetOrch* vnet_orch = gDirectory.get(); + if (!vnet_orch->isVnetExists(vnet_name)) + { + it++; + continue; + } + vrf_id = vnet_orch->getVRid(vnet_name); + } + else if (!vrf_name.empty()) + { + if (m_vrfOrch->isVRFexists(vrf_name)) + { + it++; + continue; + } + vrf_id = m_vrfOrch->getVRFid(vrf_name); + } + string op = kfvOp(t); if (op == SET_COMMAND) { if (alias == "lo") { - addIp2MeRoute(ip_prefix); + addIp2MeRoute(vrf_id, ip_prefix); it = consumer.m_toSync.erase(it); continue; } @@ -149,7 +197,7 @@ void IntfsOrch::doTask(Consumer &consumer) auto it_intfs = m_syncdIntfses.find(alias); if (it_intfs == m_syncdIntfses.end()) { - if (addRouterIntfs(port)) + if (addRouterIntfs(vrf_id, port)) { IntfsEntry intfs_entry; intfs_entry.ref_count = 0; @@ -162,9 +210,10 @@ void IntfsOrch::doTask(Consumer &consumer) } } - if (m_syncdIntfses[alias].ip_addresses.count(ip_prefix)) + vrf_id = port.m_vr_id; + if (!ip_prefix_in_key || m_syncdIntfses[alias].ip_addresses.count(ip_prefix)) { - /* Duplicate entry */ + /* Request to create router interface, no prefix present or Duplicate entry */ it = consumer.m_toSync.erase(it); continue; } @@ -198,7 +247,7 @@ void IntfsOrch::doTask(Consumer &consumer) } addSubnetRoute(port, ip_prefix); - addIp2MeRoute(ip_prefix); + addIp2MeRoute(vrf_id, ip_prefix); if (port.m_type == Port::VLAN && ip_prefix.isV4()) { @@ -212,7 +261,7 @@ void IntfsOrch::doTask(Consumer &consumer) { if (alias == "lo") { - removeIp2MeRoute(ip_prefix); + removeIp2MeRoute(vrf_id, ip_prefix); it = consumer.m_toSync.erase(it); continue; } @@ -225,12 +274,13 @@ void IntfsOrch::doTask(Consumer &consumer) continue; } + vrf_id = port.m_vr_id; if (m_syncdIntfses.find(alias) != m_syncdIntfses.end()) { if (m_syncdIntfses[alias].ip_addresses.count(ip_prefix)) { removeSubnetRoute(port, ip_prefix); - removeIp2MeRoute(ip_prefix); + removeIp2MeRoute(vrf_id, ip_prefix); if(port.m_type == Port::VLAN && ip_prefix.isV4()) { removeDirectedBroadcast(port, ip_prefix.getBroadcastIp()); @@ -262,7 +312,7 @@ void IntfsOrch::doTask(Consumer &consumer) } } -bool IntfsOrch::addRouterIntfs(Port &port) +bool IntfsOrch::addRouterIntfs(sai_object_id_t vrf_id, Port &port) { SWSS_LOG_ENTER(); @@ -279,7 +329,7 @@ bool IntfsOrch::addRouterIntfs(Port &port) vector attrs; attr.id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; - attr.value.oid = gVirtualRouterId; + attr.value.oid = vrf_id; attrs.push_back(attr); attr.id = SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS; @@ -334,6 +384,8 @@ bool IntfsOrch::addRouterIntfs(Port &port) throw runtime_error("Failed to create router interface."); } + port.m_vr_id = vrf_id; + gPortsOrch->setPort(port.m_alias, port); SWSS_LOG_NOTICE("Create router interface %s MTU %u", port.m_alias.c_str(), port.m_mtu); @@ -359,6 +411,7 @@ bool IntfsOrch::removeRouterIntfs(Port &port) } port.m_rif_id = 0; + port.m_vr_id = 0; gPortsOrch->setPort(port.m_alias, port); SWSS_LOG_NOTICE("Remove router interface for port %s", port.m_alias.c_str()); @@ -370,7 +423,7 @@ void IntfsOrch::addSubnetRoute(const Port &port, const IpPrefix &ip_prefix) { sai_route_entry_t unicast_route_entry; unicast_route_entry.switch_id = gSwitchId; - unicast_route_entry.vr_id = gVirtualRouterId; + unicast_route_entry.vr_id = port.m_vr_id; copy(unicast_route_entry.destination, ip_prefix); subnet(unicast_route_entry.destination, unicast_route_entry.destination); @@ -413,7 +466,7 @@ void IntfsOrch::removeSubnetRoute(const Port &port, const IpPrefix &ip_prefix) { sai_route_entry_t unicast_route_entry; unicast_route_entry.switch_id = gSwitchId; - unicast_route_entry.vr_id = gVirtualRouterId; + unicast_route_entry.vr_id = port.m_vr_id; copy(unicast_route_entry.destination, ip_prefix); subnet(unicast_route_entry.destination, unicast_route_entry.destination); @@ -441,11 +494,11 @@ void IntfsOrch::removeSubnetRoute(const Port &port, const IpPrefix &ip_prefix) gRouteOrch->notifyNextHopChangeObservers(ip_prefix, IpAddresses(), false); } -void IntfsOrch::addIp2MeRoute(const IpPrefix &ip_prefix) +void IntfsOrch::addIp2MeRoute(sai_object_id_t vrf_id, const IpPrefix &ip_prefix) { sai_route_entry_t unicast_route_entry; unicast_route_entry.switch_id = gSwitchId; - unicast_route_entry.vr_id = gVirtualRouterId; + unicast_route_entry.vr_id = vrf_id; copy(unicast_route_entry.destination, ip_prefix.getIp()); sai_attribute_t attr; @@ -481,11 +534,11 @@ void IntfsOrch::addIp2MeRoute(const IpPrefix &ip_prefix) } } -void IntfsOrch::removeIp2MeRoute(const IpPrefix &ip_prefix) +void IntfsOrch::removeIp2MeRoute(sai_object_id_t vrf_id, const IpPrefix &ip_prefix) { sai_route_entry_t unicast_route_entry; unicast_route_entry.switch_id = gSwitchId; - unicast_route_entry.vr_id = gVirtualRouterId; + unicast_route_entry.vr_id = vrf_id; copy(unicast_route_entry.destination, ip_prefix.getIp()); sai_status_t status = sai_route_api->remove_route_entry(&unicast_route_entry); diff --git a/orchagent/intfsorch.h b/orchagent/intfsorch.h index 424cb62a7b55..6273a44c3a95 100644 --- a/orchagent/intfsorch.h +++ b/orchagent/intfsorch.h @@ -3,6 +3,7 @@ #include "orch.h" #include "portsorch.h" +#include "vrforch.h" #include "ipaddresses.h" #include "ipprefix.h" @@ -25,7 +26,7 @@ typedef map IntfsTable; class IntfsOrch : public Orch { public: - IntfsOrch(DBConnector *db, string tableName); + IntfsOrch(DBConnector *db, string tableName, VRFOrch *vrf_orch); sai_object_id_t getRouterIntfsId(const string&); @@ -35,19 +36,20 @@ class IntfsOrch : public Orch bool setRouterIntfsMtu(Port &port); std::set getSubnetRoutes(); private: + VRFOrch *m_vrfOrch; IntfsTable m_syncdIntfses; void doTask(Consumer &consumer); int getRouterIntfsRefCount(const string&); - bool addRouterIntfs(Port &port); + bool addRouterIntfs(sai_object_id_t vrf_id, Port &port); bool removeRouterIntfs(Port &port); void addSubnetRoute(const Port &port, const IpPrefix &ip_prefix); void removeSubnetRoute(const Port &port, const IpPrefix &ip_prefix); - void addIp2MeRoute(const IpPrefix &ip_prefix); - void removeIp2MeRoute(const IpPrefix &ip_prefix); + void addIp2MeRoute(sai_object_id_t vrf_id, const IpPrefix &ip_prefix); + void removeIp2MeRoute(sai_object_id_t vrf_id, const IpPrefix &ip_prefix); void addDirectedBroadcast(const Port &port, const IpAddress &ip_addr); void removeDirectedBroadcast(const Port &port, const IpAddress &ip_addr); diff --git a/orchagent/orch.cpp b/orchagent/orch.cpp index 4825d82d6cb0..fb8a8eec5db6 100644 --- a/orchagent/orch.cpp +++ b/orchagent/orch.cpp @@ -552,6 +552,8 @@ void Orch2::doTask(Consumer &consumer) try { request_.parse(it->second); + auto table_name = consumer.getTableName(); + request_.setTableName(table_name); auto op = request_.getOperation(); if (op == SET_COMMAND) diff --git a/orchagent/orch.h b/orchagent/orch.h index 03f18f4f8d4c..b623b662b968 100644 --- a/orchagent/orch.h +++ b/orchagent/orch.h @@ -220,6 +220,11 @@ class Orch2 : public Orch { } + Orch2(DBConnector *db, const vector &tableNames, Request& request) + : Orch(db, tableNames), request_(request) + { + } + protected: virtual void doTask(Consumer& consumer); diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index db1de0a00b0d..ad4ce3f9e163 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -69,12 +69,22 @@ bool OrchDaemon::init() gCrmOrch = new CrmOrch(m_configDb, CFG_CRM_TABLE_NAME); gPortsOrch = new PortsOrch(m_applDb, ports_tables); - TableConnector applDbFdb(m_applDb, APP_FDB_TABLE_NAME); TableConnector stateDbFdb(m_stateDb, STATE_FDB_TABLE_NAME); gFdbOrch = new FdbOrch(applDbFdb, stateDbFdb, gPortsOrch); - gIntfsOrch = new IntfsOrch(m_applDb, APP_INTF_TABLE_NAME); + vector vnet_tables = { + APP_VNET_RT_TABLE_NAME, + APP_VNET_RT_TUNNEL_TABLE_NAME + }; + VNetOrch *vnet_orch = new VNetOrch(m_applDb, APP_VNET_TABLE_NAME); + gDirectory.set(vnet_orch); + VNetRouteOrch *vnet_rt_orch = new VNetRouteOrch(m_applDb, vnet_tables, vnet_orch); + gDirectory.set(vnet_rt_orch); + VRFOrch *vrf_orch = new VRFOrch(m_applDb, APP_VRF_TABLE_NAME); + gDirectory.set(vrf_orch); + + gIntfsOrch = new IntfsOrch(m_applDb, APP_INTF_TABLE_NAME, vrf_orch); gNeighOrch = new NeighOrch(m_applDb, APP_NEIGH_TABLE_NAME, gIntfsOrch); gRouteOrch = new RouteOrch(m_applDb, APP_ROUTE_TABLE_NAME, gNeighOrch); CoppOrch *copp_orch = new CoppOrch(m_applDb, APP_COPP_TABLE_NAME); @@ -111,7 +121,6 @@ bool OrchDaemon::init() TableConnector stateDbMirrorSession(m_stateDb, APP_MIRROR_SESSION_TABLE_NAME); TableConnector confDbMirrorSession(m_configDb, CFG_MIRROR_SESSION_TABLE_NAME); MirrorOrch *mirror_orch = new MirrorOrch(stateDbMirrorSession, confDbMirrorSession, gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch); - VRFOrch *vrf_orch = new VRFOrch(m_configDb, CFG_VRF_TABLE_NAME); TableConnector confDbAclTable(m_configDb, CFG_ACL_TABLE_NAME); TableConnector confDbAclRuleTable(m_configDb, CFG_ACL_RULE_TABLE_NAME); @@ -178,6 +187,8 @@ bool OrchDaemon::init() m_orchList.push_back(gFdbOrch); m_orchList.push_back(mirror_orch); m_orchList.push_back(gAclOrch); + m_orchList.push_back(vnet_orch); + m_orchList.push_back(vnet_rt_orch); m_orchList.push_back(vrf_orch); m_orchList.push_back(vxlan_tunnel_orch); m_orchList.push_back(vxlan_tunnel_map_orch); diff --git a/orchagent/orchdaemon.h b/orchagent/orchdaemon.h index d9a8b07da931..b398dba05833 100644 --- a/orchagent/orchdaemon.h +++ b/orchagent/orchdaemon.h @@ -22,6 +22,7 @@ #include "crmorch.h" #include "vrforch.h" #include "vxlanorch.h" +#include "vnetorch.h" #include "countercheckorch.h" #include "flexcounterorch.h" #include "directory.h" diff --git a/orchagent/port.h b/orchagent/port.h index 16936f4c0bc2..0b46457986e1 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -73,6 +73,7 @@ class Port sai_object_id_t m_bridge_port_id = 0; // TODO: port could have multiple bridge port IDs sai_vlan_id_t m_port_vlan_id = DEFAULT_PORT_VLAN_ID; // Port VLAN ID sai_object_id_t m_rif_id = 0; + sai_object_id_t m_vr_id = 0; sai_object_id_t m_hif_id = 0; sai_object_id_t m_lag_id = 0; sai_object_id_t m_lag_member_id = 0; diff --git a/orchagent/request_parser.cpp b/orchagent/request_parser.cpp index a7be4daf3c5c..610b19145419 100644 --- a/orchagent/request_parser.cpp +++ b/orchagent/request_parser.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "sai.h" @@ -91,6 +90,9 @@ void Request::parseKey(const KeyOpFieldsValuesTuple& request) case REQ_T_IP: key_item_ip_addresses_[i] = parseIpAddress(key_items[i]); break; + case REQ_T_IP_PREFIX: + key_item_ip_prefix_[i] = parseIpPrefix(key_items[i]); + break; case REQ_T_UINT: key_item_uint_[i] = parseUint(key_items[i]); break; @@ -145,6 +147,9 @@ void Request::parseAttrs(const KeyOpFieldsValuesTuple& request) case REQ_T_UINT: attr_item_uint_[fvField(*i)] = parseUint(fvValue(*i)); break; + case REQ_T_SET: + attr_item_set_[fvField(*i)] = parseSet(fvValue(*i)); + break; default: throw std::logic_error(std::string("Not implemented attribute type parser for attribute:") + fvField(*i)); } @@ -207,6 +212,38 @@ IpAddress Request::parseIpAddress(const std::string& str) } } +IpPrefix Request::parseIpPrefix(const std::string& str) +{ + try + { + IpPrefix pfx(str); + return pfx; + } + catch (std::invalid_argument& _) + { + throw std::invalid_argument(std::string("Invalid ip prefix: ") + str); + } +} + +set Request::parseSet(const std::string& str) +{ + try + { + set str_set; + string substr; + std::istringstream iss(str); + while (getline(iss, substr, ',')) + { + str_set.insert(substr); + } + return str_set; + } + catch (std::invalid_argument& _) + { + throw std::invalid_argument(std::string("Invalid string set")); + } +} + uint64_t Request::parseUint(const std::string& str) { try diff --git a/orchagent/request_parser.h b/orchagent/request_parser.h index 1be08f39c91a..442e1a8f127e 100644 --- a/orchagent/request_parser.h +++ b/orchagent/request_parser.h @@ -2,6 +2,9 @@ #define __REQUEST_PARSER_H #include "ipaddress.h" +#include "ipprefix.h" +#include +#include typedef enum _request_types_t { @@ -11,8 +14,10 @@ typedef enum _request_types_t REQ_T_MAC_ADDRESS, REQ_T_PACKET_ACTION, REQ_T_IP, + REQ_T_IP_PREFIX, REQ_T_VLAN, REQ_T_UINT, + REQ_T_SET, } request_types_t; typedef struct _request_description @@ -58,6 +63,12 @@ class Request return key_item_ip_addresses_.at(position); } + const IpPrefix& getKeyIpPrefix(int position) const + { + assert(is_parsed_); + return key_item_ip_prefix_.at(position); + } + const uint64_t& getKeyUint(int position) const { assert(is_parsed_); @@ -112,6 +123,23 @@ class Request return attr_item_uint_.at(attr_name); } + const set& getAttrSet(const std::string& attr_name) const + { + assert(is_parsed_); + return attr_item_set_.at(attr_name); + } + + void setTableName(std::string& table_name) + { + table_name_ = table_name; + } + + const std::string& getTableName() const + { + assert(is_parsed_); + return table_name_; + } + protected: Request(const request_description_t& request_description, const char key_separator) : request_description_(request_description), @@ -129,8 +157,10 @@ class Request bool parseBool(const std::string& str); MacAddress parseMacAddress(const std::string& str); IpAddress parseIpAddress(const std::string& str); + IpPrefix parseIpPrefix(const std::string& str); uint64_t parseUint(const std::string& str); uint16_t parseVlan(const std::string& str); + set parseSet(const std::string& str); sai_packet_action_t parsePacketAction(const std::string& str); @@ -139,11 +169,13 @@ class Request bool is_parsed_; size_t number_of_key_items_; + std::string table_name_; std::string operation_; std::string full_key_; std::unordered_map key_item_strings_; std::unordered_map key_item_mac_addresses_; std::unordered_map key_item_ip_addresses_; + std::unordered_map key_item_ip_prefix_; std::unordered_map key_item_uint_; std::unordered_set attr_names_; // FIXME: Make one union with all the values, except string @@ -154,6 +186,7 @@ class Request std::unordered_map attr_item_vlan_; std::unordered_map attr_item_ip_; std::unordered_map attr_item_uint_; + std::unordered_map> attr_item_set_; }; #endif // __REQUEST_PARSER_H diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp new file mode 100644 index 000000000000..6988aeedbb35 --- /dev/null +++ b/orchagent/vnetorch.cpp @@ -0,0 +1,512 @@ +#include +#include +#include +#include +#include +#include + +#include "sai.h" +#include "macaddress.h" +#include "orch.h" +#include "portsorch.h" +#include "request_parser.h" +#include "vnetorch.h" +#include "swssnet.h" + +extern sai_virtual_router_api_t* sai_virtual_router_api; +extern sai_route_api_t* sai_route_api; +extern sai_object_id_t gSwitchId; +extern PortsOrch *gPortsOrch; + +/* + * VRF Modeling and VNetVrf class definitions + */ +std::vector vr_cntxt; + +VNetVrfObject::VNetVrfObject(const std::string& name, set& p_list, vector& attrs) + : VNetObject(p_list) +{ + vnet_name_ = name; + createObj(attrs); +} + +sai_object_id_t VNetVrfObject::getVRidIngress() const +{ + if (vr_ids_.find(VR_TYPE::ING_VR_VALID) != vr_ids_.end()) + { + return vr_ids_.at(VR_TYPE::ING_VR_VALID); + } + return SAI_NULL_OBJECT_ID; +} + +sai_object_id_t VNetVrfObject::getVRidEgress() const +{ + if (vr_ids_.find(VR_TYPE::EGR_VR_VALID) != vr_ids_.end()) + { + return vr_ids_.at(VR_TYPE::EGR_VR_VALID); + } + return SAI_NULL_OBJECT_ID; +} + +set VNetVrfObject::getVRids() const +{ + set ids; + + for_each (vr_ids_.begin(), vr_ids_.end(), [&](std::pair element) + { + ids.insert(element.second); + }); + + return ids; +} + +bool VNetVrfObject::createObj(vector& attrs) +{ + auto l_fn = [&] (sai_object_id_t& router_id) { + + sai_status_t status = sai_virtual_router_api->create_virtual_router(&router_id, + gSwitchId, + static_cast(attrs.size()), + attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create virtual router name: %s, rv: %d", + vnet_name_.c_str(), status); + throw std::runtime_error("Failed to create VR object"); + } + return true; + }; + + /* + * Create ingress and egress VRF based on VR_VALID + */ + + for (auto vr_type : vr_cntxt) + { + sai_object_id_t router_id; + if (vr_type != VR_TYPE::VR_INVALID && l_fn(router_id)) + { + SWSS_LOG_DEBUG("VNET vr_type %d router id %lx ", vr_type, router_id); + vr_ids_.insert(std::pair(vr_type, router_id)); + } + } + + SWSS_LOG_INFO("VNET '%s' router object created ", vnet_name_.c_str()); + return true; +} + +bool VNetVrfObject::updateObj(vector& attrs) +{ + set vr_ent = getVRids(); + + for (const auto& attr: attrs) + { + for (auto it : vr_ent) + { + sai_status_t status = sai_virtual_router_api->set_virtual_router_attribute(it, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to update virtual router attribute. VNET name: %s, rv: %d", + vnet_name_.c_str(), status); + return false; + } + } + } + + SWSS_LOG_INFO("VNET '%s' was updated", vnet_name_.c_str()); + return true; +} + +VNetVrfObject::~VNetVrfObject() +{ + set vr_ent = getVRids(); + for (auto it : vr_ent) + { + sai_status_t status = sai_virtual_router_api->remove_virtual_router(it); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove virtual router name: %s, rv:%d", + vnet_name_.c_str(), status); + } + } + + SWSS_LOG_INFO("VNET '%s' deleted ", vnet_name_.c_str()); +} + +/* + * VNet Orch class definitions + */ + +template +std::unique_ptr VNetOrch::createObject(const string& vnet_name, set& plist, + vector& attrs) +{ + std::unique_ptr vnet_obj(new T(vnet_name, plist, attrs)); + return vnet_obj; +} + +VNetOrch::VNetOrch(DBConnector *db, const std::string& tableName, VNET_EXEC op) + : Orch2(db, tableName, request_) +{ + vnet_exec_ = op; + + if (op == VNET_EXEC::VNET_EXEC_VRF) + { + vr_cntxt = { VR_TYPE::ING_VR_VALID, VR_TYPE::EGR_VR_VALID }; + } + else + { + // BRIDGE Handling + } +} + +bool VNetOrch::addOperation(const Request& request) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t attr; + vector attrs; + set peer_list = {}; + bool peer = false, create = false; + + for (const auto& name: request.getAttrFieldNames()) + { + if (name == "src_mac") + { + const auto& mac = request.getAttrMacAddress("src_mac"); + attr.id = SAI_VIRTUAL_ROUTER_ATTR_SRC_MAC_ADDRESS; + memcpy(attr.value.mac, mac.getMac(), sizeof(sai_mac_t)); + attrs.push_back(attr); + } + else if (name == "peer_list") + { + peer_list = request.getAttrSet("peer_list"); + peer = true; + } + else + { + SWSS_LOG_WARN("Logic error: Unknown attribute: %s", name.c_str()); + continue; + } + } + + const std::string& vnet_name = request.getKeyString(0); + SWSS_LOG_INFO("VNET '%s' add request", vnet_name.c_str()); + + try + { + VNetObject_T obj; + auto it = vnet_table_.find(vnet_name); + if (isVnetExecVrf()) + { + if (it == std::end(vnet_table_)) + { + obj = createObject(vnet_name, peer_list, attrs); + create = true; + } + SWSS_LOG_INFO("VNET '%s' was added ", vnet_name.c_str()); + } + else + { + // BRIDGE Handling + } + + if (create) + { + vnet_table_[vnet_name] = std::move(obj); + } + else if (peer) + { + it->second->setPeerList(peer_list); + } + else if (!attrs.empty()) + { + if(!it->second->updateObj(attrs)) + { + return true; + } + } + + } + catch(std::runtime_error& _) + { + SWSS_LOG_ERROR("VNET add operation error for %s: error %s ", vnet_name.c_str(), _.what()); + return false; + } + + SWSS_LOG_INFO("VNET '%s' added/updated ", vnet_name.c_str()); + return true; +} + +bool VNetOrch::delOperation(const Request& request) +{ + SWSS_LOG_ENTER(); + + const std::string& vnet_name = request.getKeyString(0); + + if (vnet_table_.find(vnet_name) == std::end(vnet_table_)) + { + SWSS_LOG_WARN("VNET '%s' doesn't exist", vnet_name.c_str()); + return true; + } + + vnet_table_.erase(vnet_name); + + SWSS_LOG_INFO("VNET '%s' del request", vnet_name.c_str()); + return true; +} + +/* + * Vnet Route Handling + */ + +static bool add_route(sai_object_id_t vr_id, sai_ip_prefix_t& ip_pfx, sai_object_id_t nh_id) +{ + sai_route_entry_t route_entry; + route_entry.vr_id = vr_id; + route_entry.switch_id = gSwitchId; + route_entry.destination = ip_pfx; + + sai_attribute_t route_attr; + + route_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + route_attr.value.oid = nh_id; + + sai_status_t status = sai_route_api->create_route_entry(&route_entry, 1, &route_attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("SAI failed to create route"); + return false; + } + + return true; +} + +VNetRouteOrch::VNetRouteOrch(DBConnector *db, vector &tableNames, VNetOrch *vnetOrch) + : Orch2(db, tableNames, request_), vnet_orch_(vnetOrch) +{ + SWSS_LOG_ENTER(); + + handler_map_.insert(handler_pair(APP_VNET_RT_TABLE_NAME, &VNetRouteOrch::handleRoutes)); + handler_map_.insert(handler_pair(APP_VNET_RT_TUNNEL_TABLE_NAME, &VNetRouteOrch::handleTunnel)); +} + +sai_object_id_t VNetRouteOrch::getNextHop(const string& vnet, IpAddress& ipAddr) +{ + auto it = nh_tunnels_.find(vnet); + if (it != nh_tunnels_.end()) + { + if (it->second.find(ipAddr) != it->second.end()) + { + return it->second.at(ipAddr); + } + } + + sai_object_id_t nh_id = SAI_NULL_OBJECT_ID; + + /* + * @FIXEME createNextHopTunnel(vnet, ipAddr, nh_id) , throw if failed + */ + + nh_tunnels_[vnet].insert({ipAddr, nh_id}); + return nh_id; +} + +template<> +bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipPrefix, IpAddress& endIp) +{ + SWSS_LOG_ENTER(); + + if (!vnet_orch_->isVnetExists(vnet)) + { + SWSS_LOG_WARN("VNET %s doesn't exist", vnet.c_str()); + return false; + } + + set vr_set; + auto& peer_list = vnet_orch_->getPeerList(vnet); + + auto l_fn = [&] (const string& vnet) { + auto *vnet_obj = vnet_orch_->getTypePtr(vnet); + sai_object_id_t vr_id = vnet_obj->getVRidIngress(); + vr_set.insert(vr_id); + }; + + l_fn(vnet); + for (auto peer : peer_list) + { + if (!vnet_orch_->isVnetExists(peer)) + { + SWSS_LOG_INFO("Peer VNET %s not yet created", peer.c_str()); + return false; + } + l_fn(peer); + } + + sai_ip_prefix_t pfx; + copy(pfx, ipPrefix); + sai_object_id_t nh_id = getNextHop(vnet, endIp); + + for (auto vr_id : vr_set) + { + if(!add_route(vr_id, pfx, nh_id)) + { + SWSS_LOG_ERROR("Route add failed for %s", ipPrefix.to_string().c_str()); + break; + } + } + return true; +} + +template<> +bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipPrefix, string& ifname) +{ + SWSS_LOG_ENTER(); + + if (!vnet_orch_->isVnetExists(vnet)) + { + SWSS_LOG_WARN("VNET %s doesn't exist", vnet.c_str()); + return false; + } + + Port p; + if (!gPortsOrch->getPort(ifname, p) || (p.m_rif_id == SAI_NULL_OBJECT_ID)) + { + SWSS_LOG_WARN("Port/RIF %s doesn't exist", ifname.c_str()); + return false; + } + + set vr_set; + auto& peer_list = vnet_orch_->getPeerList(vnet); + auto *vnet_obj = vnet_orch_->getTypePtr(vnet); + vr_set.insert(vnet_obj->getVRidEgress()); + + auto l_fn = [&] (const string& vnet) { + auto *vnet_obj = vnet_orch_->getTypePtr(vnet); + sai_object_id_t vr_id = vnet_obj->getVRidIngress(); + vr_set.insert(vr_id); + }; + + for (auto peer : peer_list) + { + if (!vnet_orch_->isVnetExists(peer)) + { + SWSS_LOG_INFO("Peer VNET %s not yet created", peer.c_str()); + return false; + } + l_fn(peer); + } + + sai_ip_prefix_t pfx; + copy(pfx, ipPrefix); + + for (auto vr_id : vr_set) + { + if(!add_route(vr_id, pfx, p.m_rif_id )) + { + SWSS_LOG_ERROR("Route add failed for %s", ipPrefix.to_string().c_str()); + break; + } + } + + return true; +} + +void VNetRouteOrch::handleRoutes(const Request& request) +{ + SWSS_LOG_ENTER(); + + string ifname = ""; + + for (const auto& name: request.getAttrFieldNames()) + { + if (name == "ifname") + { + ifname = request.getAttrString(name); + } + else + { + SWSS_LOG_WARN("Logic error: Unknown attribute: %s", name.c_str()); + return; + } + } + + const std::string& vnet_name = request.getKeyString(0); + auto ip_pfx = request.getKeyIpPrefix(1); + + SWSS_LOG_INFO("VNET-RT '%s' add for ip %s", vnet_name.c_str(), ip_pfx.to_string().c_str()); + + if (vnet_orch_->isVnetExecVrf()) + { + if (!doRouteTask(vnet_name, ip_pfx, ifname)) + { + throw std::runtime_error("Route add failed"); + } + } +} + +void VNetRouteOrch::handleTunnel(const Request& request) +{ + SWSS_LOG_ENTER(); + + IpAddress ip; + + for (const auto& name: request.getAttrFieldNames()) + { + if (name == "endpoint") + { + ip = request.getAttrIP(name); + } + else + { + SWSS_LOG_WARN("Logic error: Unknown attribute: %s", name.c_str()); + return; + } + } + + const std::string& vnet_name = request.getKeyString(0); + auto ip_pfx = request.getKeyIpPrefix(1); + + SWSS_LOG_INFO("VNET-RT '%s' add for endpoint %s", vnet_name.c_str(), ip_pfx.to_string().c_str()); + + if (vnet_orch_->isVnetExecVrf()) + { + if (!doRouteTask(vnet_name, ip_pfx, ip)) + { + throw std::runtime_error("Route add failed"); + } + } +} + +bool VNetRouteOrch::addOperation(const Request& request) +{ + SWSS_LOG_ENTER(); + + try + { + auto& tn = request.getTableName(); + if (handler_map_.find(tn) == handler_map_.end()) + { + SWSS_LOG_ERROR(" %s handler is not initialized", tn.c_str()); + return true; + } + + (this->*(handler_map_[tn]))(request); + } + catch(std::runtime_error& _) + { + SWSS_LOG_ERROR("VNET add operation error %s ", _.what()); + return false; + } + + return true; +} + +bool VNetRouteOrch::delOperation(const Request& request) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_ERROR("DEL operation is not implemented"); + + return true; +} diff --git a/orchagent/vnetorch.h b/orchagent/vnetorch.h new file mode 100644 index 000000000000..f3911d0b79cf --- /dev/null +++ b/orchagent/vnetorch.h @@ -0,0 +1,223 @@ +#ifndef __VNETORCH_H +#define __VNETORCH_H + +#include +#include +#include +#include + +#include "request_parser.h" + +extern sai_object_id_t gVirtualRouterId; + +const request_description_t vnet_request_description = { + { REQ_T_STRING }, + { + { "src_mac", REQ_T_MAC_ADDRESS }, + { "vnet_name", REQ_T_STRING }, + { "peer_list", REQ_T_SET }, + }, + { } // no mandatory attributes +}; + +enum class VNET_EXEC +{ + VNET_EXEC_VRF, + VNET_EXEC_BRIDGE, + VNET_EXEC_INVALID +}; + +enum class VR_TYPE +{ + ING_VR_VALID, + EGR_VR_VALID, + VR_INVALID +}; + +using vrid_list_t = map; +extern std::vector vr_cntxt; + +class VNetRequest : public Request +{ +public: + VNetRequest() : Request(vnet_request_description, ':') { } +}; + +class VNetObject +{ +public: + VNetObject(set& p_list) + { + peer_list_ = p_list; + } + + virtual sai_object_id_t getEncapMapId() const = 0; + + virtual sai_object_id_t getDecapMapId() const = 0; + + virtual bool updateObj(vector&) = 0; + + void setPeerList(set& p_list) + { + peer_list_ = p_list; + } + + virtual sai_object_id_t getVRid() const = 0; + + const set& getPeerList() const + { + return peer_list_; + } + + virtual ~VNetObject() {}; + +private: + set peer_list_ = {}; +}; + +class VNetVrfObject : public VNetObject +{ +public: + VNetVrfObject(const std::string& name, set& p_list, vector& attrs); + + sai_object_id_t getVRidIngress() const; + + sai_object_id_t getVRidEgress() const; + + set getVRids() const; + + virtual sai_object_id_t getEncapMapId() const + { + return getVRidIngress(); + } + + virtual sai_object_id_t getDecapMapId() const + { + return getVRidEgress(); + } + + virtual sai_object_id_t getVRid() const + { + return getVRidIngress(); + } + + bool createObj(vector&); + + bool updateObj(vector&); + + ~VNetVrfObject(); + +private: + string vnet_name_; + vrid_list_t vr_ids_; +}; + +using VNetObject_T = std::unique_ptr; +typedef std::unordered_map VNetTable; + +class VNetOrch : public Orch2 +{ +public: + VNetOrch(DBConnector *db, const std::string&, VNET_EXEC op = VNET_EXEC::VNET_EXEC_VRF); + + bool isVnetExists(const std::string& name) const + { + return vnet_table_.find(name) != std::end(vnet_table_); + } + + template + T* getTypePtr(const std::string& name) const + { + return static_cast(vnet_table_.at(name).get()); + } + + sai_object_id_t getEncapMapId(const std::string& name) const + { + return vnet_table_.at(name)->getEncapMapId(); + } + + sai_object_id_t getDecapMapId(const std::string& name) const + { + return vnet_table_.at(name)->getDecapMapId(); + } + + const set& getPeerList(const std::string& name) const + { + return vnet_table_.at(name)->getPeerList(); + } + + sai_object_id_t getVRid(const std::string& name) const + { + return vnet_table_.at(name)->getVRid(); + } + + bool isVnetExecVrf() const + { + return (vnet_exec_ == VNET_EXEC::VNET_EXEC_VRF); + } + + bool isVnetExecBridge() const + { + return (vnet_exec_ == VNET_EXEC::VNET_EXEC_BRIDGE); + } + +private: + virtual bool addOperation(const Request& request); + virtual bool delOperation(const Request& request); + + template + std::unique_ptr createObject(const string&, set&, vector&); + + VNetTable vnet_table_; + VNetRequest request_; + VNET_EXEC vnet_exec_; + +}; + +const request_description_t vnet_route_description = { + { REQ_T_STRING, REQ_T_IP_PREFIX }, + { + { "endpoint", REQ_T_IP }, + { "ifname", REQ_T_STRING }, + }, + { } +}; + +class VNetRouteRequest : public Request +{ +public: + VNetRouteRequest() : Request(vnet_route_description, ':') { } +}; + +using NextHopMap = map; +using NextHopTunnels = map; + +class VNetRouteOrch : public Orch2 +{ +public: + VNetRouteOrch(DBConnector *db, vector &tableNames, VNetOrch *); + using handler_pair = pair; + using handler_map = map; + +private: + virtual bool addOperation(const Request& request); + virtual bool delOperation(const Request& request); + + void handleRoutes(const Request&); + void handleTunnel(const Request&); + + template + bool doRouteTask(const string& vnet, IpPrefix& ipPrefix, IpAddress& ipAddr); + + template + bool doRouteTask(const string& vnet, IpPrefix& ipPrefix, string& ifname); + + sai_object_id_t getNextHop(const string& vnet, IpAddress& ipAddr); + + VNetOrch *vnet_orch_; + VNetRouteRequest request_; + handler_map handler_map_; + NextHopTunnels nh_tunnels_; +}; + +#endif // __VNETORCH_H diff --git a/orchagent/vrforch.h b/orchagent/vrforch.h index 49df85492ea4..22f5c6430724 100644 --- a/orchagent/vrforch.h +++ b/orchagent/vrforch.h @@ -3,6 +3,7 @@ #include "request_parser.h" +extern sai_object_id_t gVirtualRouterId; typedef std::unordered_map VRFTable; const request_description_t request_description = { @@ -14,6 +15,7 @@ const request_description_t request_description = { { "ttl_action", REQ_T_PACKET_ACTION }, { "ip_opt_action", REQ_T_PACKET_ACTION }, { "l3_mc_action", REQ_T_PACKET_ACTION }, + { "fallback", REQ_T_BOOL }, }, { } // no mandatory attributes }; @@ -21,7 +23,7 @@ const request_description_t request_description = { class VRFRequest : public Request { public: - VRFRequest() : Request(request_description, '|') { } + VRFRequest() : Request(request_description, ':') { } }; @@ -39,8 +41,16 @@ class VRFOrch : public Orch2 sai_object_id_t getVRFid(const std::string& name) const { - return vrf_table_.at(name); + if (vrf_table_.find(name) != std::end(vrf_table_)) + { + return vrf_table_.at(name); + } + else + { + return gVirtualRouterId; + } } + private: virtual bool addOperation(const Request& request); virtual bool delOperation(const Request& request); diff --git a/tests/request_parser_ut.cpp b/tests/request_parser_ut.cpp index c68cb6bf6c50..ba8a504578c4 100644 --- a/tests/request_parser_ut.cpp +++ b/tests/request_parser_ut.cpp @@ -18,6 +18,7 @@ const request_description_t request_description1 = { { "ttl_action", REQ_T_PACKET_ACTION }, { "ip_opt_action", REQ_T_PACKET_ACTION }, { "l3_mc_action", REQ_T_PACKET_ACTION }, + { "nlist", REQ_T_SET }, }, { } // no mandatory attributes }; @@ -54,6 +55,7 @@ const request_description_t request_description3 = { { { "v4", REQ_T_BOOL }, { "v6", REQ_T_BOOL }, + { "nlist", REQ_T_SET }, }, { } // no mandatory attributes }; @@ -73,7 +75,8 @@ TEST(request_parser, simpleKey) { "src_mac", "02:03:04:05:06:07" }, { "ttl_action", "copy" }, { "ip_opt_action", "drop" }, - { "l3_mc_action", "log" } + { "l3_mc_action", "log" }, + { "nlist", "name1" }, } }; @@ -86,13 +89,15 @@ TEST(request_parser, simpleKey) EXPECT_STREQ(request.getOperation().c_str(), "SET"); EXPECT_STREQ(request.getFullKey().c_str(), "key1"); EXPECT_STREQ(request.getKeyString(0).c_str(), "key1"); - EXPECT_TRUE(request.getAttrFieldNames() == (std::unordered_set{"v4", "v6", "src_mac", "ttl_action", "ip_opt_action", "l3_mc_action"})); + EXPECT_TRUE(request.getAttrFieldNames() == (std::unordered_set{"v4", "v6", "src_mac", "ttl_action", "ip_opt_action", "l3_mc_action", "nlist"})); EXPECT_TRUE(request.getAttrBool("v4")); EXPECT_TRUE(request.getAttrBool("v6")); EXPECT_STREQ(request.getAttrMacAddress("src_mac").to_string().c_str(), "02:03:04:05:06:07"); EXPECT_EQ(request.getAttrPacketAction("ttl_action"), SAI_PACKET_ACTION_COPY); EXPECT_EQ(request.getAttrPacketAction("ip_opt_action"), SAI_PACKET_ACTION_DROP); EXPECT_EQ(request.getAttrPacketAction("l3_mc_action"), SAI_PACKET_ACTION_LOG); + EXPECT_TRUE(request.getAttrSet("nlist") == (std::set{"name1"})); + } catch (const std::exception& e) { @@ -746,6 +751,32 @@ TEST(request_parser, correctAttrTypePacketAction2) } } +TEST(request_parser, emptyAttrValue1) +{ + KeyOpFieldsValuesTuple t {"key1", "SET", + { + { "nlist", "" }, + } + }; + + try + { + TestRequest1 request; + + EXPECT_NO_THROW(request.parse(t)); + + EXPECT_TRUE(request.getAttrSet("nlist") == (std::set{})); + } + catch (const std::exception& e) + { + FAIL() << "Got unexpected exception " << e.what(); + } + catch (...) + { + FAIL() << "Got unexpected exception"; + } +} + TEST(request_parser, correctAttrTypePacketAction3) { KeyOpFieldsValuesTuple t {"key1", "SET", @@ -942,6 +973,7 @@ TEST(request_parser, anotherKeySeparator) { { "v4", "false" }, { "v6", "false" }, + { "nlist", "name1,name2" }, } }; @@ -955,9 +987,11 @@ TEST(request_parser, anotherKeySeparator) EXPECT_STREQ(request.getFullKey().c_str(), "key1:key2"); EXPECT_STREQ(request.getKeyString(0).c_str(), "key1"); EXPECT_STREQ(request.getKeyString(1).c_str(), "key2"); - EXPECT_TRUE(request.getAttrFieldNames() == (std::unordered_set{"v4", "v6"})); + EXPECT_TRUE(request.getAttrFieldNames() == (std::unordered_set{"v4", "v6", "nlist"})); EXPECT_FALSE(request.getAttrBool("v4")); EXPECT_FALSE(request.getAttrBool("v6")); + EXPECT_TRUE(request.getAttrSet("nlist") == (std::set{"name1", "name2"})); + } catch (const std::exception& e) { @@ -1188,3 +1222,78 @@ TEST(request_parser, wrong_uint_key_2) FAIL() << "Expected std::logic_error, not other exception"; } } + +const request_description_t request_description7 = { + { REQ_T_STRING, REQ_T_IP_PREFIX }, + { + { "ip", REQ_T_IP }, + }, + { } // no mandatory attributes +}; + +class TestRequest7 : public Request +{ +public: + TestRequest7() : Request(request_description7, ':') { } +}; + +TEST(request_parser, prefix_key1) +{ + KeyOpFieldsValuesTuple t {"Ethernet1:10.1.1.1/24", "SET", + { + { "ip", "20.1.1.1" }, + } + }; + + try + { + TestRequest7 request; + + EXPECT_NO_THROW(request.parse(t)); + + EXPECT_STREQ(request.getOperation().c_str(), "SET"); + EXPECT_STREQ(request.getFullKey().c_str(), "Ethernet1:10.1.1.1/24"); + EXPECT_STREQ(request.getKeyString(0).c_str(), "Ethernet1"); + EXPECT_EQ(request.getKeyIpPrefix(1), IpPrefix("10.1.1.1/24")); + EXPECT_TRUE(request.getAttrFieldNames() == (std::unordered_set{"ip"})); + EXPECT_EQ(request.getAttrIP("ip"), IpAddress("20.1.1.1")); + } + catch (const std::exception& e) + { + FAIL() << "Got unexpected exception " << e.what(); + } + catch (...) + { + FAIL() << "Expected std::logic_error, not other exception"; + } +} + +TEST(request_parser, wrong_key_ip_prefix) +{ + KeyOpFieldsValuesTuple t {"Ethernet1:10.1.1.1.1/24", "SET", + { + { "empty" , "empty" }, + } + }; + + try + { + TestRequest7 request; + + request.parse(t); + + FAIL() << "Expected std::invalid_argument error"; + } + catch (const std::invalid_argument& e) + { + EXPECT_STREQ(e.what(),"Invalid ip prefix: 10.1.1.1.1/24"); + } + catch (const std::exception& e) + { + FAIL() << "Got unexpected exception " << e.what(); + } + catch (...) + { + FAIL() << "Expected std::logic_error, not other exception"; + } +} diff --git a/tests/test_vrf.py b/tests/test_vrf.py index 9f3431ee6a83..9307d9d584e9 100644 --- a/tests/test_vrf.py +++ b/tests/test_vrf.py @@ -29,6 +29,10 @@ def delete_entry_tbl(db, table, key): 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) @@ -59,7 +63,7 @@ def is_vrf_attributes_correct(db, table, key, expected_attributes): (value, name, expected_attributes[name]) -def vrf_create(asic_db, conf_db, vrf_name, attributes, expected_attributes): +def vrf_create(asic_db, appl_db, vrf_name, attributes, expected_attributes): # check that the vrf wasn't exist before assert how_many_entries_exist(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER") == 1, "The initial state is incorrect" @@ -71,7 +75,7 @@ def vrf_create(asic_db, conf_db, vrf_name, attributes, expected_attributes): attributes = [('empty', 'empty')] # create the VRF entry in Config DB - create_entry_tbl(conf_db, "VRF", vrf_name, attributes) + create_entry_pst(appl_db, "VRF_TABLE", vrf_name, attributes) # check that the vrf entry was created assert how_many_entries_exist(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER") == 2, "The vrf wasn't created" @@ -95,9 +99,9 @@ def vrf_create(asic_db, conf_db, vrf_name, attributes, expected_attributes): return state -def vrf_remove(asic_db, conf_db, vrf_name, state): +def vrf_remove(asic_db, appl_db, vrf_name, state): # delete the created vrf entry - delete_entry_tbl(conf_db, "VRF", vrf_name) + delete_entry_pst(appl_db, "VRF_TABLE", vrf_name) # check that the vrf entry was removed assert how_many_entries_exist(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER") == 1, "The vrf wasn't removed" @@ -106,9 +110,9 @@ def vrf_remove(asic_db, conf_db, vrf_name, state): assert state['initial_entries'] == entries(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER"), "The incorrect entry was removed" -def vrf_update(asic_db, conf_db, vrf_name, attributes, expected_attributes, state): +def vrf_update(asic_db, appl_db, vrf_name, attributes, expected_attributes, state): # update the VRF entry in Config DB - create_entry_tbl(conf_db, "VRF", vrf_name, attributes) + create_entry_pst(appl_db, "VRF_TABLE", vrf_name, attributes) # check correctness of the created attributes is_vrf_attributes_correct( @@ -149,7 +153,7 @@ def packet_action_gen(): def test_VRFOrch_Comprehensive(dvs): asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + appl_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) attributes = [ ('v4', 'SAI_VIRTUAL_ROUTER_ATTR_ADMIN_V4_STATE', boolean_gen), @@ -174,22 +178,22 @@ def test_VRFOrch_Comprehensive(dvs): req_attr.append((attributes[an][0], req_res)) exp_attr[attributes[an][1]] = exp_res bmask <<= 1 - state = vrf_create(asic_db, conf_db, vrf_name, req_attr, exp_attr) - vrf_remove(asic_db, conf_db, vrf_name, state) + state = vrf_create(asic_db, appl_db, vrf_name, req_attr, exp_attr) + vrf_remove(asic_db, appl_db, vrf_name, state) def test_VRFOrch(dvs): asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - state = vrf_create(asic_db, conf_db, "vrf0", + appl_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + state = vrf_create(asic_db, appl_db, "vrf0", [ ], { } ) - vrf_remove(asic_db, conf_db, "vrf0", state) + vrf_remove(asic_db, appl_db, "vrf0", state) - state = vrf_create(asic_db, conf_db, "vrf1", + state = vrf_create(asic_db, appl_db, "vrf1", [ ('v4', 'true'), ('src_mac', '02:04:06:07:08:09'), @@ -199,11 +203,11 @@ def test_VRFOrch(dvs): 'SAI_VIRTUAL_ROUTER_ATTR_SRC_MAC_ADDRESS': '02:04:06:07:08:09', } ) - vrf_remove(asic_db, conf_db, "vrf1", state) + vrf_remove(asic_db, appl_db, "vrf1", state) def test_VRFOrch_Update(dvs): asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + appl_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) attributes = [ ('v4', 'SAI_VIRTUAL_ROUTER_ATTR_ADMIN_V4_STATE', boolean_gen), @@ -216,7 +220,7 @@ def test_VRFOrch_Update(dvs): random.seed(int(time.clock())) - state = vrf_create(asic_db, conf_db, "vrf_a", + state = vrf_create(asic_db, appl_db, "vrf_a", [ ], { @@ -230,6 +234,6 @@ def test_VRFOrch_Update(dvs): req_res, exp_res = attr[2]() req_attr.append((attr[0], req_res)) exp_attr[attr[1]] = exp_res - vrf_update(asic_db, conf_db, "vrf_a", req_attr, exp_attr, state) + vrf_update(asic_db, appl_db, "vrf_a", req_attr, exp_attr, state) - vrf_remove(asic_db, conf_db, "vrf_a", state) + vrf_remove(asic_db, appl_db, "vrf_a", state)