From dd6bdd936273dff94214d876e6dfa1e7b2f57941 Mon Sep 17 00:00:00 2001 From: Marian Pritsak Date: Thu, 21 Feb 2019 20:20:31 +0200 Subject: [PATCH] [vnetorch]: Bitmap VNet implementation (#773) * [vnetorch]: Bitmap VNet implementation * Adress review comments Signed-off-by: Marian Pritsak --- orchagent/intfsorch.cpp | 10 + orchagent/intfsorch.h | 13 +- orchagent/main.cpp | 1 + orchagent/orchdaemon.cpp | 10 +- orchagent/saihelper.cpp | 4 + orchagent/switchorch.cpp | 2 + orchagent/vnetorch.cpp | 604 ++++++++++++++++++++++++++++++++++++++- orchagent/vnetorch.h | 67 ++++- 8 files changed, 693 insertions(+), 18 deletions(-) diff --git a/orchagent/intfsorch.cpp b/orchagent/intfsorch.cpp index ffc572b9bbbc..1617dbde15ca 100644 --- a/orchagent/intfsorch.cpp +++ b/orchagent/intfsorch.cpp @@ -314,6 +314,11 @@ void IntfsOrch::doTask(Consumer &consumer) continue; } + if (m_vnetInfses.find(alias) != m_vnetInfses.end()) + { + vnet_name = m_vnetInfses.at(alias); + } + if (!vnet_name.empty()) { VNetOrch* vnet_orch = gDirectory.get(); @@ -327,6 +332,11 @@ void IntfsOrch::doTask(Consumer &consumer) it++; continue; } + + if (m_vnetInfses.find(alias) == m_vnetInfses.end()) + { + m_vnetInfses.emplace(alias, vnet_name); + } } else { diff --git a/orchagent/intfsorch.h b/orchagent/intfsorch.h index fbfb478444b2..b9db02e1d080 100644 --- a/orchagent/intfsorch.h +++ b/orchagent/intfsorch.h @@ -44,6 +44,15 @@ class IntfsOrch : public Orch void removeRifFromFlexCounter(const string&, const string&); bool setIntf(const string& alias, sai_object_id_t vrf_id = gVirtualRouterId, const IpPrefix *ip_prefix = nullptr); + + void addIp2MeRoute(sai_object_id_t vrf_id, const IpPrefix &ip_prefix); + void removeIp2MeRoute(sai_object_id_t vrf_id, const IpPrefix &ip_prefix); + + const IntfsTable& getSyncdIntfses(void) + { + return m_syncdIntfses; + } + private: SelectableTimer* m_updateMapsTimer = nullptr; @@ -51,6 +60,7 @@ class IntfsOrch : public Orch VRFOrch *m_vrfOrch; IntfsTable m_syncdIntfses; + map m_vnetInfses; void doTask(Consumer &consumer); void doTask(SelectableTimer &timer); @@ -73,9 +83,6 @@ class IntfsOrch : public Orch void addSubnetRoute(const Port &port, const IpPrefix &ip_prefix); void removeSubnetRoute(const Port &port, 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 IpPrefix &ip_prefix); void removeDirectedBroadcast(const Port &port, const IpPrefix &ip_prefix); }; diff --git a/orchagent/main.cpp b/orchagent/main.cpp index f70ec670b37f..649d43344535 100644 --- a/orchagent/main.cpp +++ b/orchagent/main.cpp @@ -38,6 +38,7 @@ sai_object_id_t gVirtualRouterId; sai_object_id_t gUnderlayIfId; sai_object_id_t gSwitchId = SAI_NULL_OBJECT_ID; MacAddress gMacAddress; +MacAddress gVxlanMacAddress; #define DEFAULT_BATCH_SIZE 128 int gBatchSize = DEFAULT_BATCH_SIZE; diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 063b0bb8d777..6f09bca96786 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -77,7 +77,15 @@ bool OrchDaemon::init() APP_VNET_RT_TABLE_NAME, APP_VNET_RT_TUNNEL_TABLE_NAME }; - VNetOrch *vnet_orch = new VNetOrch(m_applDb, APP_VNET_TABLE_NAME); + VNetOrch *vnet_orch; + if (platform == MLNX_PLATFORM_SUBSTRING) + { + vnet_orch = new VNetOrch(m_applDb, APP_VNET_TABLE_NAME, VNET_EXEC::VNET_EXEC_BRIDGE); + } + else + { + 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); diff --git a/orchagent/saihelper.cpp b/orchagent/saihelper.cpp index 7381e7443098..4b01ddeb39f8 100644 --- a/orchagent/saihelper.cpp +++ b/orchagent/saihelper.cpp @@ -2,6 +2,7 @@ extern "C" { #include "sai.h" #include "saistatus.h" +#include "saiextensions.h" } #include @@ -39,6 +40,7 @@ sai_acl_api_t* sai_acl_api; sai_mirror_api_t* sai_mirror_api; sai_fdb_api_t* sai_fdb_api; sai_dtel_api_t* sai_dtel_api; +sai_bmtor_api_t* sai_bmtor_api; extern sai_object_id_t gSwitchId; extern bool gSairedisRecord; @@ -127,6 +129,7 @@ void initSaiApi() sai_api_query(SAI_API_SCHEDULER_GROUP, (void **)&sai_scheduler_group_api); sai_api_query(SAI_API_ACL, (void **)&sai_acl_api); sai_api_query(SAI_API_DTEL, (void **)&sai_dtel_api); + sai_api_query((sai_api_t)SAI_API_BMTOR, (void **)&sai_bmtor_api); sai_log_set(SAI_API_SWITCH, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_BRIDGE, SAI_LOG_LEVEL_NOTICE); @@ -152,6 +155,7 @@ void initSaiApi() sai_log_set(SAI_API_SCHEDULER_GROUP, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_ACL, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_DTEL, SAI_LOG_LEVEL_NOTICE); + sai_log_set((sai_api_t)SAI_API_BMTOR, SAI_LOG_LEVEL_NOTICE); } void initSaiRedis(const string &record_location) diff --git a/orchagent/switchorch.cpp b/orchagent/switchorch.cpp index 6c93556cfbcb..4664b49bdb4b 100644 --- a/orchagent/switchorch.cpp +++ b/orchagent/switchorch.cpp @@ -11,6 +11,7 @@ using namespace swss; extern sai_object_id_t gSwitchId; extern sai_switch_api_t *sai_switch_api; +extern MacAddress gVxlanMacAddress; const map switch_attribute_map = { @@ -100,6 +101,7 @@ void SwitchOrch::doTask(Consumer &consumer) case SAI_SWITCH_ATTR_VXLAN_DEFAULT_ROUTER_MAC: mac_addr = value; + gVxlanMacAddress = mac_addr; memcpy(attr.value.mac, mac_addr.getMac(), sizeof(sai_mac_t)); break; diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index 417cce7ff530..62f806ebf8d8 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -6,6 +6,7 @@ #include #include "sai.h" +#include "saiextensions.h" #include "macaddress.h" #include "orch.h" #include "portsorch.h" @@ -20,12 +21,19 @@ extern sai_virtual_router_api_t* sai_virtual_router_api; extern sai_route_api_t* sai_route_api; +extern sai_bridge_api_t* sai_bridge_api; +extern sai_router_interface_api_t* sai_router_intfs_api; +extern sai_fdb_api_t* sai_fdb_api; +extern sai_neighbor_api_t* sai_neighbor_api; +extern sai_next_hop_api_t* sai_next_hop_api; +extern sai_bmtor_api_t* sai_bmtor_api; extern sai_object_id_t gSwitchId; extern Directory gDirectory; extern PortsOrch *gPortsOrch; extern IntfsOrch *gIntfsOrch; extern NeighOrch *gNeighOrch; extern CrmOrch *gCrmOrch; +extern MacAddress gVxlanMacAddress; /* * VRF Modeling and VNetVrf class definitions @@ -249,6 +257,545 @@ VNetVrfObject::~VNetVrfObject() SWSS_LOG_INFO("VNET '%s' deleted ", vnet_name_.c_str()); } +/* + * Bitmap based VNET class definition + */ +std::bitset VNetBitmapObject::vnetBitmap_; +std::bitset VNetBitmapObject::tunnelOffsets_; +map VNetBitmapObject::vnetIds_; +map VNetBitmapObject::bridgeInfoMap_; +map, sai_fdb_entry_t> VNetBitmapObject::fdbMap_; +map, sai_neighbor_entry_t> VNetBitmapObject::neighMap_; + +VNetBitmapObject::VNetBitmapObject(const std::string& vnet, const VNetInfo& vnetInfo, + vector& attrs) : VNetObject(vnetInfo) +{ + SWSS_LOG_ENTER(); + + setVniInfo(vnetInfo.vni); + + vnet_id_ = getFreeBitmapId(vnet); +} + +bool VNetBitmapObject::updateObj(vector&) +{ + SWSS_LOG_ENTER(); + + return false; +} + +uint32_t VNetBitmapObject::getFreeBitmapId(const string& vnet) +{ + SWSS_LOG_ENTER(); + + for (uint32_t i = 0; i < vnetBitmap_.size(); i++) + { + uint32_t id = 1 << i; + if (vnetBitmap_[i] == false) + { + vnetBitmap_[i] = true; + vnetIds_.emplace(vnet, id); + return id; + } + } + + return 0; +} + +uint32_t VNetBitmapObject::getBitmapId(const string& vnet) +{ + SWSS_LOG_ENTER(); + + if (vnetIds_.find(vnet) == vnetIds_.end()) + { + return 0; + } + + return vnetIds_[vnet]; +} + +void VNetBitmapObject::recycleBitmapId(uint32_t id) +{ + SWSS_LOG_ENTER(); + + vnetBitmap_ &= ~id; +} + +uint32_t VNetBitmapObject::getFreeTunnelRouteTableOffset() +{ + SWSS_LOG_ENTER(); + + for (uint32_t i = 0; i < tunnelOffsets_.size(); i++) + { + if (tunnelOffsets_[i] == false) + { + tunnelOffsets_[i] = true; + return i; + } + } + + return -1; +} + +void VNetBitmapObject::recycleTunnelRouteTableOffset(uint32_t offset) +{ + SWSS_LOG_ENTER(); + + tunnelOffsets_[offset] = false; +} + +VnetBridgeInfo VNetBitmapObject::getBridgeInfoByVni(uint32_t vni, string tunnelName) +{ + SWSS_LOG_ENTER(); + + if (bridgeInfoMap_.find(vni) != bridgeInfoMap_.end()) + { + return std::move(bridgeInfoMap_.at(vni)); + } + + sai_status_t status; + VnetBridgeInfo info; + sai_attribute_t attr; + vector bridge_attrs; + attr.id = SAI_BRIDGE_ATTR_TYPE; + attr.value.s32 = SAI_BRIDGE_TYPE_1D; + bridge_attrs.push_back(attr); + + status = sai_bridge_api->create_bridge( + &info.bridge_id, + gSwitchId, + (uint32_t)bridge_attrs.size(), + bridge_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create bridge for vni %u", vni); + throw std::runtime_error("vni creation failed"); + } + + vector rif_attrs; + + attr.id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; + attr.value.oid = gVirtualRouterId; + rif_attrs.push_back(attr); + + attr.id = SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS; + memcpy(attr.value.mac, gMacAddress.getMac(), sizeof(sai_mac_t)); + rif_attrs.push_back(attr); + + attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; + attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_BRIDGE; + rif_attrs.push_back(attr); + + attr.id = SAI_ROUTER_INTERFACE_ATTR_BRIDGE_ID; + attr.value.oid = info.bridge_id; + rif_attrs.push_back(attr); + + status = sai_router_intfs_api->create_router_interface( + &info.rif_id, + gSwitchId, + (uint32_t)rif_attrs.size(), + rif_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create rif for vni %u", vni); + throw std::runtime_error("vni creation failed"); + } + + vector bpr_attrs; + + attr.id = SAI_BRIDGE_PORT_ATTR_TYPE; + attr.value.s32 = SAI_BRIDGE_PORT_TYPE_1D_ROUTER; + bpr_attrs.push_back(attr); + + attr.id = SAI_BRIDGE_PORT_ATTR_RIF_ID; + attr.value.oid = info.rif_id; + bpr_attrs.push_back(attr); + + attr.id = SAI_BRIDGE_PORT_ATTR_BRIDGE_ID; + attr.value.oid = info.bridge_id; + bpr_attrs.push_back(attr); + + attr.id = SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE; + attr.value.s32 = SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE; + bpr_attrs.push_back(attr); + + status = sai_bridge_api->create_bridge_port( + &info.bridge_port_rif_id, + gSwitchId, + (uint32_t)bpr_attrs.size(), + bpr_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create rif bridge port for vni %u", vni); + throw std::runtime_error("vni creation failed"); + } + + vector bpt_attrs; + auto* vxlan_orch = gDirectory.get(); + auto *tunnel = vxlan_orch->getVxlanTunnel(tunnelName); + if (!tunnel->isActive()) + { + tunnel->createTunnel(MAP_T::BRIDGE_TO_VNI, MAP_T::VNI_TO_BRIDGE); + } + + attr.id = SAI_BRIDGE_PORT_ATTR_TYPE; + attr.value.s32 = SAI_BRIDGE_PORT_TYPE_TUNNEL; + bpt_attrs.push_back(attr); + + attr.id = SAI_BRIDGE_PORT_ATTR_BRIDGE_ID; + attr.value.oid = info.bridge_id; + bpt_attrs.push_back(attr); + + attr.id = SAI_BRIDGE_PORT_ATTR_ADMIN_STATE; + attr.value.booldata = true; + bpt_attrs.push_back(attr); + + attr.id = SAI_BRIDGE_PORT_ATTR_TUNNEL_ID; + attr.value.oid = tunnel->getTunnelId(); + bpt_attrs.push_back(attr); + + attr.id = SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE; + attr.value.s32 = SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE; + bpt_attrs.push_back(attr); + + status = sai_bridge_api->create_bridge_port( + &info.bridge_port_tunnel_id, + gSwitchId, + (uint32_t)bpt_attrs.size(), + bpt_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create tunnel bridge port for vni %u", vni); + throw std::runtime_error("vni creation failed"); + } + + tunnel->addEncapMapperEntry(info.bridge_id, vni); + + bridgeInfoMap_.emplace(vni, info); + + return std::move(info); +} + +void VNetBitmapObject::setVniInfo(uint32_t vni) +{ + sai_attribute_t attr; + vector vnet_attrs; + sai_object_id_t vnetTableEntryId; + auto info = getBridgeInfoByVni(getVni(), getTunnelName()); + + attr.id = SAI_TABLE_BITMAP_CLASSIFICATION_ENTRY_ATTR_ACTION; + attr.value.s32 = SAI_TABLE_BITMAP_CLASSIFICATION_ENTRY_ACTION_SET_METADATA; + vnet_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_CLASSIFICATION_ENTRY_ATTR_ROUTER_INTERFACE_KEY; + attr.value.oid = info.rif_id; + vnet_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_CLASSIFICATION_ENTRY_ATTR_IN_RIF_METADATA; + attr.value.u32 = vnet_id_; + vnet_attrs.push_back(attr); + + sai_status_t status = sai_bmtor_api->create_table_bitmap_classification_entry( + &vnetTableEntryId, + gSwitchId, + (uint32_t)vnet_attrs.size(), + vnet_attrs.data()); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create VNET table entry, SAI rc: %d", status); + throw std::runtime_error("VNet interface creation failed"); + } +} + +bool VNetBitmapObject::addIntf(const string& alias, const IpPrefix *prefix) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t attr; + vector vnet_attrs; + vector route_attrs; + sai_status_t status; + uint32_t peerBitmap = vnet_id_; + + if (prefix && !prefix->isV4()) + { + return false; + } + + for (const auto& vnet : getPeerList()) + { + uint32_t id = getBitmapId(vnet); + if (id == 0) + { + SWSS_LOG_WARN("Peer vnet %s not ready", vnet.c_str()); + return false; + } + peerBitmap |= id; + } + + if (gIntfsOrch->getSyncdIntfses().find(alias) == gIntfsOrch->getSyncdIntfses().end()) + { + if (!gIntfsOrch->setIntf(alias, gVirtualRouterId, nullptr)) + { + return false; + } + + sai_object_id_t vnetTableEntryId; + + attr.id = SAI_TABLE_BITMAP_CLASSIFICATION_ENTRY_ATTR_ACTION; + attr.value.s32 = SAI_TABLE_BITMAP_CLASSIFICATION_ENTRY_ACTION_SET_METADATA; + vnet_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_CLASSIFICATION_ENTRY_ATTR_ROUTER_INTERFACE_KEY; + attr.value.oid = gIntfsOrch->getRouterIntfsId(alias); + vnet_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_CLASSIFICATION_ENTRY_ATTR_IN_RIF_METADATA; + attr.value.u32 = vnet_id_; + vnet_attrs.push_back(attr); + + status = sai_bmtor_api->create_table_bitmap_classification_entry( + &vnetTableEntryId, + gSwitchId, + (uint32_t)vnet_attrs.size(), + vnet_attrs.data()); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create VNET table entry, SAI rc: %d", status); + throw std::runtime_error("VNet interface creation failed"); + } + } + + if (prefix) + { + sai_object_id_t tunnelRouteTableEntryId; + sai_ip_prefix_t saiPrefix; + copy(saiPrefix, *prefix); + + gIntfsOrch->addIp2MeRoute(gVirtualRouterId, *prefix); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_ACTION; + attr.value.s32 = SAI_TABLE_BITMAP_ROUTER_ENTRY_ACTION_TO_LOCAL; + route_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_PRIORITY; + attr.value.u32 = getFreeTunnelRouteTableOffset(); + route_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_IN_RIF_METADATA_KEY; + attr.value.u64 = 0; + route_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_IN_RIF_METADATA_MASK; + attr.value.u64 = ~peerBitmap; + route_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_DST_IP_KEY; + attr.value.ipprefix = saiPrefix; + route_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_ROUTER_INTERFACE; + attr.value.oid = gIntfsOrch->getRouterIntfsId(alias); + route_attrs.push_back(attr); + + status = sai_bmtor_api->create_table_bitmap_router_entry( + &tunnelRouteTableEntryId, + gSwitchId, + (uint32_t)route_attrs.size(), + route_attrs.data()); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create local VNET route entry, SAI rc: %d", status); + throw std::runtime_error("VNet interface creation failed"); + } + } + + return true; +} + +uint32_t VNetBitmapObject::getFreeNeighbor(void) +{ + static set neighbors; + + for (uint32_t i = 0; i < VNET_NEIGHBOR_MAX; i++) + { + if (neighbors.count(i) == 0) + { + neighbors.insert(i); + return i; + } + } + + SWSS_LOG_ERROR("No neighbors left"); + throw std::runtime_error("VNet route creation failed"); +} + +bool VNetBitmapObject::addTunnelRoute(IpPrefix& ipPrefix, tunnelEndpoint& endp) +{ + SWSS_LOG_ENTER(); + + sai_status_t status; + sai_attribute_t attr; + sai_object_id_t tunnelRouteTableEntryId; + auto& peer_list = getPeerList(); + auto bInfo = getBridgeInfoByVni(endp.vni == 0 ? getVni() : endp.vni, getTunnelName()); + uint32_t peerBitmap = vnet_id_; + MacAddress mac = endp.mac ? endp.mac : gVxlanMacAddress; + + VNetOrch* vnet_orch = gDirectory.get(); + for (auto peer : peer_list) + { + if (!vnet_orch->isVnetExists(peer)) + { + SWSS_LOG_INFO("Peer VNET %s not yet created", peer.c_str()); + return false; + } + peerBitmap |= getBitmapId(peer); + } + + auto macBridge = make_tuple(mac, bInfo.bridge_id); + + if (fdbMap_.find(macBridge) == fdbMap_.end()) + { + /* FDB entry to the tunnel */ + vector fdb_attrs; + sai_ip_address_t underlayAddr; + copy(underlayAddr, endp.ip); + sai_fdb_entry_t fdbEntry; + fdbEntry.switch_id = gSwitchId; + mac.getMac(fdbEntry.mac_address); + fdbEntry.bv_id = bInfo.bridge_id; + + attr.id = SAI_FDB_ENTRY_ATTR_TYPE; + attr.value.s32 = SAI_FDB_ENTRY_TYPE_STATIC; + fdb_attrs.push_back(attr); + + attr.id = SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID; + attr.value.oid = bInfo.bridge_port_tunnel_id; + fdb_attrs.push_back(attr); + + attr.id = SAI_FDB_ENTRY_ATTR_ENDPOINT_IP; + attr.value.ipaddr = underlayAddr; + fdb_attrs.push_back(attr); + + status = sai_fdb_api->create_fdb_entry( + &fdbEntry, + (uint32_t)fdb_attrs.size(), + fdb_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create fdb entry for tunnel, SAI rc: %d", status); + throw std::runtime_error("VNet route creation failed"); + } + + fdbMap_.emplace(macBridge, fdbEntry); + } + + /* Fake neighbor */ + sai_neighbor_entry_t neigh; + if (neighMap_.find(macBridge) == neighMap_.end()) + { + vector n_attrs; + neigh.switch_id = gSwitchId; + neigh.rif_id = bInfo.rif_id; + neigh.ip_address.addr_family = SAI_IP_ADDR_FAMILY_IPV4; + neigh.ip_address.addr.ip4 = htonl(getFreeNeighbor()); + + attr.id = SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS; + mac.getMac(attr.value.mac); + n_attrs.push_back(attr); + + status = sai_neighbor_api->create_neighbor_entry( + &neigh, + (uint32_t)n_attrs.size(), + n_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create neighbor entry for tunnel, SAI rc: %d", status); + throw std::runtime_error("VNet route creation failed"); + } + + neighMap_.emplace(macBridge, neigh); + } + else + { + neigh = neighMap_.at(macBridge); + } + + /* Nexthop */ + vector nh_attrs; + sai_object_id_t nexthopId; + + attr.id = SAI_NEXT_HOP_ATTR_TYPE; + attr.value.s32 = SAI_NEXT_HOP_TYPE_IP; + nh_attrs.push_back(attr); + + attr.id = SAI_NEXT_HOP_ATTR_IP; + attr.value.ipaddr = neigh.ip_address; + nh_attrs.push_back(attr); + + attr.id = SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID; + attr.value.oid = bInfo.rif_id; + nh_attrs.push_back(attr); + + status = sai_next_hop_api->create_next_hop( + &nexthopId, + gSwitchId, + (uint32_t)nh_attrs.size(), + nh_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create nexthop for tunnel, SAI rc: %d", status); + throw std::runtime_error("VNet route creation failed"); + } + + /* Tunnel route */ + vector tr_attrs; + sai_ip_prefix_t pfx; + copy(pfx, ipPrefix); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_ACTION; + attr.value.s32 = SAI_TABLE_BITMAP_ROUTER_ENTRY_ACTION_TO_NEXTHOP; + tr_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_PRIORITY; + attr.value.u32 = getFreeTunnelRouteTableOffset(); + tr_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_IN_RIF_METADATA_KEY; + attr.value.u64 = 0; + tr_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_IN_RIF_METADATA_MASK; + attr.value.u64 = ~peerBitmap; + tr_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_DST_IP_KEY; + attr.value.ipprefix = pfx; + tr_attrs.push_back(attr); + + attr.id = SAI_TABLE_BITMAP_ROUTER_ENTRY_ATTR_NEXT_HOP; + attr.value.oid = nexthopId; + tr_attrs.push_back(attr); + + status = sai_bmtor_api->create_table_bitmap_router_entry( + &tunnelRouteTableEntryId, + gSwitchId, + (uint32_t)tr_attrs.size(), + tr_attrs.data()); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create local VNET route entry, SAI rc: %d", status); + throw std::runtime_error("VNet route creation failed"); + } + + return true; +} + /* * VNet Orch class definitions */ @@ -280,19 +827,24 @@ bool VNetOrch::setIntf(const string& alias, const string name, const IpPrefix *p { SWSS_LOG_ENTER(); - if (isVnetExecVrf()) + if (!isVnetExists(name)) { - if (!isVnetExists(name)) - { - SWSS_LOG_WARN("VNET %s doesn't exist", name.c_str()); - return false; - } + SWSS_LOG_WARN("VNET %s doesn't exist", name.c_str()); + return false; + } + if (isVnetExecVrf()) + { auto *vnet_obj = getTypePtr(name); sai_object_id_t vrf_id = vnet_obj->getVRidIngress(); return gIntfsOrch->setIntf(alias, vrf_id, prefix); } + else + { + auto *vnet_obj = getTypePtr(name); + return vnet_obj->addIntf(alias, prefix); + } return false; } @@ -372,7 +924,20 @@ bool VNetOrch::addOperation(const Request& request) } else { - // BRIDGE Handling + VxlanTunnelOrch* vxlan_orch = gDirectory.get(); + + if (!vxlan_orch->isTunnelExists(tunnel)) + { + SWSS_LOG_WARN("Vxlan tunnel '%s' doesn't exist", tunnel.c_str()); + return false; + } + + if (it == std::end(vnet_table_)) + { + VNetInfo vnet_info = { tunnel, vni, peer_list }; + obj = createObject(vnet_name, vnet_info, attrs); + create = true; + } } if (create) @@ -706,6 +1271,27 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP return true; } +template<> +bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipPrefix, tunnelEndpoint& endp, string& op) +{ + SWSS_LOG_ENTER(); + + if (!vnet_orch_->isVnetExists(vnet)) + { + SWSS_LOG_WARN("VNET %s doesn't exist", vnet.c_str()); + return false; + } + + auto *vnet_obj = vnet_orch_->getTypePtr(vnet); + + if (op == SET_COMMAND) + { + return vnet_obj->addTunnelRoute(ipPrefix, endp); + } + + return true; +} + bool VNetRouteOrch::handleRoutes(const Request& request) { SWSS_LOG_ENTER(); @@ -789,6 +1375,10 @@ bool VNetRouteOrch::handleTunnel(const Request& request) { return doRouteTask(vnet_name, ip_pfx, endp, op); } + else + { + return doRouteTask(vnet_name, ip_pfx, endp, op); + } return true; } diff --git a/orchagent/vnetorch.h b/orchagent/vnetorch.h index 59e8317f45a2..0482ccc3dcb2 100644 --- a/orchagent/vnetorch.h +++ b/orchagent/vnetorch.h @@ -5,10 +5,15 @@ #include #include #include +#include #include "request_parser.h" #include "ipaddresses.h" +#define VNET_BITMAP_SIZE 32 +#define VNET_TUNNEL_SIZE 512 +#define VNET_NEIGHBOR_MAX 0xffff + extern sai_object_id_t gVirtualRouterId; const request_description_t vnet_request_description = { @@ -53,6 +58,13 @@ class VNetRequest : public Request VNetRequest() : Request(vnet_request_description, ':') { } }; +struct tunnelEndpoint +{ + IpAddress ip; + MacAddress mac; + uint32_t vni; +}; + class VNetObject { public: @@ -92,13 +104,6 @@ class VNetObject uint32_t vni_; }; -struct tunnelEndpoint -{ - IpAddress ip; - MacAddress mac; - uint32_t vni; -}; - struct nextHop { IpAddresses ips; @@ -159,6 +164,54 @@ class VNetVrfObject : public VNetObject RouteMap routes_; }; +struct VnetBridgeInfo +{ + sai_object_id_t bridge_id; + sai_object_id_t bridge_port_rif_id; + sai_object_id_t bridge_port_tunnel_id; + sai_object_id_t rif_id; +}; + +class VNetBitmapObject: public VNetObject +{ +public: + VNetBitmapObject(const string& vnet, const VNetInfo& vnetInfo, vector& attrs); + + virtual bool addIntf(const string& alias, const IpPrefix *prefix); + + virtual bool addTunnelRoute(IpPrefix& ipPrefix, tunnelEndpoint& endp); + + void setVniInfo(uint32_t vni); + + bool updateObj(vector&); + + virtual ~VNetBitmapObject() {} + +private: + static uint32_t getFreeBitmapId(const string& name); + + static uint32_t getBitmapId(const string& name); + + static void recycleBitmapId(uint32_t id); + + static uint32_t getFreeTunnelRouteTableOffset(); + + static void recycleTunnelRouteTableOffset(uint32_t offset); + + static VnetBridgeInfo getBridgeInfoByVni(uint32_t vni, string tunnelName); + + static uint32_t getFreeNeighbor(void); + + static std::bitset vnetBitmap_; + static map vnetIds_; + static std::bitset tunnelOffsets_; + static map bridgeInfoMap_; + static map, sai_fdb_entry_t> fdbMap_; + static map, sai_neighbor_entry_t> neighMap_; + + uint32_t vnet_id_; +}; + typedef std::unique_ptr VNetObject_T; typedef std::unordered_map VNetTable;