diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index 2aa0337448..83b280f13d 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -35,6 +35,7 @@ orchagent_SOURCES = \ neighorch.cpp \ intfsorch.cpp \ portsorch.cpp \ + fabricportsorch.cpp \ fgnhgorch.cpp \ copporch.cpp \ tunneldecaporch.cpp \ diff --git a/orchagent/fabricportsorch.cpp b/orchagent/fabricportsorch.cpp new file mode 100644 index 0000000000..ae983d253e --- /dev/null +++ b/orchagent/fabricportsorch.cpp @@ -0,0 +1,338 @@ +#include "fabricportsorch.h" + +#include +#include +#include +#include + +#include "logger.h" +#include "schema.h" +#include "sai_serialize.h" +#include "timer.h" + +#define FABRIC_POLLING_INTERVAL_DEFAULT (30) +#define FABRIC_PORT_ERROR 0 +#define FABRIC_PORT_SUCCESS 1 +#define FABRIC_PORT_STAT_COUNTER_FLEX_COUNTER_GROUP "FABRIC_PORT_STAT_COUNTER" +#define FABRIC_PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 10000 +#define FABRIC_QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP "FABRIC_QUEUE_STAT_COUNTER" +#define FABRIC_QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 100000 +#define FABRIC_PORT_TABLE_NAME "FABRIC_PORT_TABLE_NAME" +#define FABRIC_COUNTERS_QUEUE_NAME_MAP "FABRIC_COUNTERS_QUEUE_NAME_MAP" +#define FABRIC_COUNTERS_QUEUE_PORT_MAP "FABRIC_COUNTERS_QUEUE_PORT_MAP" +#define FABRIC_COUNTERS_QUEUE_INDEX_MAP "FABRIC_COUNTERS_QUEUE_INDEX_MAP" +#define FABRIC_COUNTERS_QUEUE_TYPE_MAP "FABRIC_COUNTERS_QUEUE_TYPE_MAP" +#define FABRIC_COUNTERS_PORT_NAME_MAP "FABRIC_COUNTERS_PORT_NAME_MAP" + +extern sai_object_id_t gSwitchId; +extern sai_switch_api_t *sai_switch_api; +extern sai_port_api_t *sai_port_api; +extern sai_queue_api_t *sai_queue_api; + +const vector port_stat_ids = +{ + SAI_PORT_STAT_IF_IN_OCTETS, + SAI_PORT_STAT_IF_IN_ERRORS, + SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS, + SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES, + SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES, + SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS, + SAI_PORT_STAT_IF_OUT_OCTETS, + SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS, +}; + +static const vector queue_stat_ids = +{ + SAI_QUEUE_STAT_WATERMARK_LEVEL, + SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES, + SAI_QUEUE_STAT_CURR_OCCUPANCY_LEVEL, +}; + +FabricPortsOrch::FabricPortsOrch(DBConnector *appl_db, vector &tableNames) : + Orch(appl_db, tableNames), + port_stat_manager(FABRIC_PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, + FABRIC_PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, true), + queue_stat_manager(FABRIC_QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, + FABRIC_QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, true), + m_timer(new SelectableTimer(timespec { .tv_sec = FABRIC_POLLING_INTERVAL_DEFAULT, .tv_nsec = 0 })) +{ + SWSS_LOG_ENTER(); + SWSS_LOG_NOTICE( "FabricPortsOrch constructor" ); + + m_state_db = shared_ptr(new DBConnector("STATE_DB", 0)); + m_stateTable = unique_ptr(new Table(m_state_db.get(), FABRIC_PORT_TABLE_NAME)); + + m_counter_db = shared_ptr(new DBConnector("COUNTERS_DB", 0)); + m_portNameQueueCounterTable = unique_ptr
(new Table(m_counter_db.get(), FABRIC_COUNTERS_QUEUE_NAME_MAP)); + m_queuePortCounterTable = unique_ptr
(new Table(m_counter_db.get(), FABRIC_COUNTERS_QUEUE_PORT_MAP)); + m_queueIndexCounterTable = unique_ptr
(new Table(m_counter_db.get(), FABRIC_COUNTERS_QUEUE_INDEX_MAP)); + m_queueTypeCounterTable = unique_ptr
(new Table(m_counter_db.get(), FABRIC_COUNTERS_QUEUE_TYPE_MAP)); + m_portNamePortCounterTable = unique_ptr
(new Table(m_counter_db.get(), FABRIC_COUNTERS_PORT_NAME_MAP)); + + m_flex_db = shared_ptr(new DBConnector("FLEX_COUNTER_DB", 0)); + m_flexCounterTable = unique_ptr(new ProducerTable(m_flex_db.get(), FABRIC_PORT_TABLE_NAME)); + + getFabricPortList(); + + auto executor = new ExecutableTimer(m_timer, this, "FABRIC_POLL"); + Orch::addExecutor(executor); + m_timer->start(); +} + +int FabricPortsOrch::getFabricPortList() +{ + SWSS_LOG_ENTER(); + SWSS_LOG_NOTICE("Get fabric port list done %d", m_getFabricPortListDone == true ? 1 : 0 ); + + if (m_getFabricPortListDone) { + return FABRIC_PORT_SUCCESS; + } + + uint32_t i; + sai_status_t status; + sai_attribute_t attr; + + attr.id = SAI_SWITCH_ATTR_NUMBER_OF_FABRIC_PORTS; + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get fabric port number, rv:%d", status); + return FABRIC_PORT_ERROR; + } + m_fabricPortCount = attr.value.u32; + SWSS_LOG_NOTICE("Get %d fabric ports", m_fabricPortCount); + + vector fabric_port_list; + fabric_port_list.resize(m_fabricPortCount); + attr.id = SAI_SWITCH_ATTR_FABRIC_PORT_LIST; + attr.value.objlist.count = (uint32_t)fabric_port_list.size(); + attr.value.objlist.list = fabric_port_list.data(); + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + throw runtime_error("FabricPortsOrch get port list failure"); + } + + for (i = 0; i < m_fabricPortCount; i++) + { + sai_uint32_t lanes[1] = { 0 }; + attr.id = SAI_PORT_ATTR_HW_LANE_LIST; + attr.value.u32list.count = 1; + attr.value.u32list.list = lanes; + status = sai_port_api->get_port_attribute(fabric_port_list[i], 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + throw runtime_error("FabricPortsOrch get port lane failure"); + } + int lane = attr.value.u32list.list[0]; + m_fabricLanePortMap[lane] = fabric_port_list[i]; + SWSS_LOG_NOTICE("Get fabric port pid: %" PRIx64 " lanes: %d", fabric_port_list[i], lane); + } + + generatePortStats(); + + m_getFabricPortListDone = true; + + return FABRIC_PORT_SUCCESS; +} + +bool FabricPortsOrch::allPortsReady() +{ + return m_getFabricPortListDone; +} + +void FabricPortsOrch::generatePortStats() +{ + SWSS_LOG_NOTICE("Generate fabric port stats"); + + vector portNamePortCounterMap; + for (auto p : m_fabricLanePortMap) + { + int lane = p.first; + sai_object_id_t port = p.second; + + std::ostringstream portName; + portName << "FabricPort" << lane; + portNamePortCounterMap.emplace_back(portName.str(), sai_serialize_object_id(port)); + + // Install flex counters for port stats + std::unordered_set counter_stats; + for (const auto& it: port_stat_ids) + { + counter_stats.emplace(sai_serialize_port_stat(it)); + } + port_stat_manager.setCounterIdList(port, CounterType::PORT, counter_stats); + } + m_portNamePortCounterTable->set("", portNamePortCounterMap); +} + +void FabricPortsOrch::generateQueueStats() +{ + if (m_isQueueStatsGenerated) return; + if (!m_getFabricPortListDone) return; + + SWSS_LOG_NOTICE("Generate queue map for fabric ports"); + + sai_status_t status; + sai_attribute_t attr; + sai_attribute_t queue_attrs[2]; + + for (auto p : m_fabricLanePortMap) + { + int lane = p.first; + sai_object_id_t port = p.second; + + attr.id = SAI_PORT_ATTR_QOS_NUMBER_OF_QUEUES; + status = sai_port_api->get_port_attribute(port, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + throw runtime_error("FabricPortsOrch get port queue number failure"); + } + int num_queues = attr.value.u32; + + if (num_queues > 0) + { + vector m_queue_ids; + m_queue_ids.resize(num_queues); + + attr.id = SAI_PORT_ATTR_QOS_QUEUE_LIST; + attr.value.objlist.count = (uint32_t) num_queues; + attr.value.objlist.list = m_queue_ids.data(); + + status = sai_port_api->get_port_attribute(port, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + throw runtime_error("FabricPortsOrch get port queue list failure"); + } + + // Maintain queue map and install flex counters for queue stats + vector portNameQueueMap; + vector queuePortMap; + vector queueTypeMap; + vector queueIndexMap; + + for (size_t q = 0; q < m_queue_ids.size(); q ++) + { + std::ostringstream portName; + portName << "FabricPort" << lane << ":" << q; + const auto queue = sai_serialize_object_id(m_queue_ids[q]); + + portNameQueueMap.emplace_back(portName.str(), queue); + queuePortMap.emplace_back(queue, sai_serialize_object_id(port)); + + queue_attrs[0].id = SAI_QUEUE_ATTR_TYPE; + queue_attrs[1].id = SAI_QUEUE_ATTR_INDEX; + status = sai_queue_api->get_queue_attribute(m_queue_ids[q], 2, queue_attrs); + if (status == SAI_STATUS_SUCCESS) + { + string queueType; + string queueIndex; + switch (queue_attrs[0].value.s32) + { + case SAI_QUEUE_TYPE_ALL: + queueType = "SAI_QUEUE_TYPE_ALL"; + break; + case SAI_QUEUE_TYPE_UNICAST: + queueType = "SAI_QUEUE_TYPE_UNICAST"; + break; + case SAI_QUEUE_TYPE_MULTICAST: + queueType = "SAI_QUEUE_TYPE_MULTICAST"; + break; + default: + throw runtime_error("Got unsupported queue type"); + } + queueTypeMap.emplace_back(queue, queueType); + queueIndex = to_string(queue_attrs[1].value.u8); + queueIndexMap.emplace_back(queue, queueIndex); + } + else + { + SWSS_LOG_NOTICE("FabricPortsOrch cannot get fabric port queue type and index"); + } + + std::unordered_set counter_stats; + for (const auto& it: queue_stat_ids) + { + counter_stats.emplace(sai_serialize_queue_stat(it)); + } + queue_stat_manager.setCounterIdList(m_queue_ids[q], CounterType::QUEUE, counter_stats); + } + + m_portNameQueueCounterTable->set("", portNameQueueMap); + m_queuePortCounterTable->set("", queuePortMap); + m_queueTypeCounterTable->set("", queueTypeMap); + m_queueIndexCounterTable->set("", queueIndexMap); + } + } + + m_isQueueStatsGenerated = true; +} + +void FabricPortsOrch::updateFabricPortState() +{ + if (!m_getFabricPortListDone) return; + + sai_status_t status; + sai_attribute_t attr; + + for (auto p : m_fabricLanePortMap) + { + int lane = p.first; + sai_object_id_t port = p.second; + + string key = "PORT" + to_string(lane); + std::vector values; + + attr.id = SAI_PORT_ATTR_FABRIC_ATTACHED; + status = sai_port_api->get_port_attribute(port, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + throw runtime_error("FabricPortsOrch get port status failure"); + } + FieldValueTuple s("STATUS", attr.value.booldata ? "up" : "down"); + values.push_back(s); + + if (attr.value.booldata) + { + attr.id = SAI_PORT_ATTR_FABRIC_ATTACHED_SWITCH_ID; + status = sai_port_api->get_port_attribute(port, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + throw runtime_error("FabricPortsOrch get remote id failure"); + } + FieldValueTuple rm("REMOTE_MOD", to_string(attr.value.u32)); + values.push_back(rm); + + attr.id = SAI_PORT_ATTR_FABRIC_ATTACHED_PORT_INDEX; + status = sai_port_api->get_port_attribute(port, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + throw runtime_error("FabricPortsOrch get remote port index failure"); + } + FieldValueTuple rp("REMOTE_PORT", to_string(attr.value.u32)); + values.push_back(rp); + } + m_stateTable->set(key, values); + } +} + +void FabricPortsOrch::doTask() +{ +} + +void FabricPortsOrch::doTask(Consumer &consumer) +{ +} + +void FabricPortsOrch::doTask(swss::SelectableTimer &timer) +{ + if (!m_getFabricPortListDone) + { + getFabricPortList(); + } + + if (m_getFabricPortListDone) + { + updateFabricPortState(); + } +} diff --git a/orchagent/fabricportsorch.h b/orchagent/fabricportsorch.h new file mode 100644 index 0000000000..aff275abb1 --- /dev/null +++ b/orchagent/fabricportsorch.h @@ -0,0 +1,51 @@ +#ifndef SWSS_FABRICPORTSORCH_H +#define SWSS_FABRICPORTSORCH_H + +#include + +#include "orch.h" +#include "observer.h" +#include "observer.h" +#include "producertable.h" +#include "flex_counter_manager.h" + +class FabricPortsOrch : public Orch, public Subject +{ +public: + FabricPortsOrch(DBConnector *appl_db, vector &tableNames); + bool allPortsReady(); + void generateQueueStats(); + +private: + shared_ptr m_state_db; + shared_ptr m_counter_db; + shared_ptr m_flex_db; + + unique_ptr
m_stateTable; + unique_ptr
m_portNameQueueCounterTable; + unique_ptr
m_queuePortCounterTable; + unique_ptr
m_queueIndexCounterTable; + unique_ptr
m_queueTypeCounterTable; + unique_ptr
m_portNamePortCounterTable; + unique_ptr m_flexCounterTable; + + swss::SelectableTimer *m_timer = nullptr; + + FlexCounterManager port_stat_manager; + FlexCounterManager queue_stat_manager; + + sai_uint32_t m_fabricPortCount; + map m_fabricLanePortMap; + + bool m_getFabricPortListDone = false; + bool m_isQueueStatsGenerated = false; + int getFabricPortList(); + void generatePortStats(); + void updateFabricPortState(); + + void doTask() override; + void doTask(Consumer &consumer); + void doTask(swss::SelectableTimer &timer); +}; + +#endif /* SWSS_FABRICPORTSORCH_H */ diff --git a/orchagent/flexcounterorch.cpp b/orchagent/flexcounterorch.cpp index 549db87c93..2994881d39 100644 --- a/orchagent/flexcounterorch.cpp +++ b/orchagent/flexcounterorch.cpp @@ -1,6 +1,7 @@ #include #include "flexcounterorch.h" #include "portsorch.h" +#include "fabricportsorch.h" #include "select.h" #include "notifier.h" #include "redisclient.h" @@ -13,6 +14,7 @@ extern sai_port_api_t *sai_port_api; extern PortsOrch *gPortsOrch; +extern FabricPortsOrch *gFabricPortsOrch; extern IntfsOrch *gIntfsOrch; extern BufferOrch *gBufferOrch; @@ -51,7 +53,12 @@ void FlexCounterOrch::doTask(Consumer &consumer) { SWSS_LOG_ENTER(); - if (!gPortsOrch->allPortsReady()) + if (gPortsOrch && !gPortsOrch->allPortsReady()) + { + return; + } + + if (gFabricPortsOrch && !gFabricPortsOrch->allPortsReady()) { return; } @@ -101,15 +108,24 @@ void FlexCounterOrch::doTask(Consumer &consumer) // This can be because generateQueueMap() installs a fundamental list of queue stats // that need to be polled. So my doubt here is if queue watermark stats shall be piggybacked // into the same function as they may not be counted as fundamental - gPortsOrch->generateQueueMap(); - gPortsOrch->generatePriorityGroupMap(); - gIntfsOrch->generateInterfaceMap(); + if (gPortsOrch) + { + gPortsOrch->generateQueueMap(); + gPortsOrch->generatePriorityGroupMap(); + } + if (gIntfsOrch) + { + gIntfsOrch->generateInterfaceMap(); + } // Install COUNTER_ID_LIST/ATTR_ID_LIST only when hearing buffer pool watermark enable event - if ((key == BUFFER_POOL_WATERMARK_KEY) && (value == "enable")) + if (gBufferOrch && (key == BUFFER_POOL_WATERMARK_KEY) && (value == "enable")) { gBufferOrch->generateBufferPoolWatermarkCounterIdList(); } - + if (gFabricPortsOrch) + { + gFabricPortsOrch->generateQueueStats(); + } vector fieldValues; fieldValues.emplace_back(FLEX_COUNTER_STATUS_FIELD, value); m_flexCounterGroupTable->set(flexCounterGroupMap[key], fieldValues); diff --git a/orchagent/main.cpp b/orchagent/main.cpp index 9da230bfb6..ee5c7e061b 100644 --- a/orchagent/main.cpp +++ b/orchagent/main.cpp @@ -255,6 +255,16 @@ int main(int argc, char **argv) attr.value.ptr = (void *)on_switch_shutdown_request; attrs.push_back(attr); + /* + Asic managed by this swss will be known at this point as fabric asic, + or NPU with fabric ports enabled. We are waiting for this pull request + https://github.com/Azure/sonic-swss/pull/1431/ to merge up, and adding + code to create FabricOrchDaemon for fabric asic, or enable fabric port + management for NPU with fabric ports enabled. Also, some code below + (e.g., set mac addr, create host interface) will be skipped if the asic + is fabric. + */ + if (gMacAddress) { attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS; diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 1682e4a23c..1f0d40d9e9 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -26,6 +26,7 @@ extern void syncd_apply_view(); * Global orch daemon variables */ PortsOrch *gPortsOrch; +FabricPortsOrch *gFabricPortsOrch; FdbOrch *gFdbOrch; IntfsOrch *gIntfsOrch; NeighOrch *gNeighOrch; @@ -46,6 +47,7 @@ OrchDaemon::OrchDaemon(DBConnector *applDb, DBConnector *configDb, DBConnector * m_stateDb(stateDb) { SWSS_LOG_ENTER(); + m_select = new Select(); } OrchDaemon::~OrchDaemon() @@ -65,6 +67,7 @@ OrchDaemon::~OrchDaemon() for(; it != m_orchList.rend(); ++it) { delete(*it); } + delete m_select; } bool OrchDaemon::init() @@ -294,7 +297,14 @@ bool OrchDaemon::init() m_orchList.push_back(gNatOrch); m_orchList.push_back(gFgNhgOrch); - m_select = new Select(); + if (m_fabricEnabled) + { + vector fabric_port_tables = { + // empty for now + }; + gFabricPortsOrch = new FabricPortsOrch(m_applDb, fabric_port_tables); + m_orchList.push_back(gFabricPortsOrch); + } vector flex_counter_tables = { CFG_FLEX_COUNTER_TABLE_NAME @@ -497,7 +507,7 @@ void OrchDaemon::start() * Not doing this under Select::TIMEOUT condition because of * the existence of finer granularity ExecutableTimer with select */ - if (gSwitchOrch->checkRestartReady()) + if (gSwitchOrch && gSwitchOrch->checkRestartReady()) { bool ret = warmRestartCheck(); if (ret) @@ -510,10 +520,13 @@ void OrchDaemon::start() gSwitchOrch->setAgingFDB(0); // Disable FDB learning on all bridge ports - for (auto& pair: gPortsOrch->getAllPorts()) + if (gPortsOrch) { - auto& port = pair.second; - gPortsOrch->setBridgePortLearningFDB(port, SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE); + for (auto& pair: gPortsOrch->getAllPorts()) + { + auto& port = pair.second; + gPortsOrch->setBridgePortLearningFDB(port, SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE); + } } // Flush sairedis's redis pipeline @@ -665,3 +678,36 @@ bool OrchDaemon::warmRestartCheck() gSwitchOrch->restartCheckReply(op, data, values); return ret; } + +void OrchDaemon::addOrchList(Orch *o) +{ + m_orchList.push_back(o); +} + +FabricOrchDaemon::FabricOrchDaemon(DBConnector *applDb, DBConnector *configDb, DBConnector *stateDb) : + OrchDaemon(applDb, configDb, stateDb), + m_applDb(applDb), + m_configDb(configDb) +{ + SWSS_LOG_ENTER(); + SWSS_LOG_NOTICE("FabricOrchDaemon starting..."); +} + +bool FabricOrchDaemon::init() +{ + SWSS_LOG_ENTER(); + SWSS_LOG_NOTICE("FabricOrchDaemon init"); + + vector fabric_port_tables = { + // empty for now, I don't consume anything yet + }; + gFabricPortsOrch = new FabricPortsOrch(m_applDb, fabric_port_tables); + addOrchList(gFabricPortsOrch); + + vector flex_counter_tables = { + CFG_FLEX_COUNTER_TABLE_NAME + }; + addOrchList(new FlexCounterOrch(m_configDb, flex_counter_tables)); + + return true; +} diff --git a/orchagent/orchdaemon.h b/orchagent/orchdaemon.h index 3094692df6..7c9a7aedf1 100644 --- a/orchagent/orchdaemon.h +++ b/orchagent/orchdaemon.h @@ -7,6 +7,7 @@ #include "select.h" #include "portsorch.h" +#include "fabricportsorch.h" #include "intfsorch.h" #include "neighorch.h" #include "routeorch.h" @@ -40,17 +41,24 @@ class OrchDaemon OrchDaemon(DBConnector *, DBConnector *, DBConnector *); ~OrchDaemon(); - bool init(); + virtual bool init(); void start(); bool warmRestoreAndSyncUp(); void getTaskToSync(vector &ts); bool warmRestoreValidation(); bool warmRestartCheck(); + + void addOrchList(Orch* o); + void setFabricEnabled(bool enabled) + { + m_fabricEnabled = enabled; + } private: DBConnector *m_applDb; DBConnector *m_configDb; DBConnector *m_stateDb; + bool m_fabricEnabled = false; std::vector m_orchList; Select *m_select; @@ -58,4 +66,14 @@ class OrchDaemon void flush(); }; +class FabricOrchDaemon : public OrchDaemon +{ +public: + FabricOrchDaemon(DBConnector *, DBConnector *, DBConnector *); + bool init() override; +private: + DBConnector *m_applDb; + DBConnector *m_configDb; +}; + #endif /* SWSS_ORCHDAEMON_H */ diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index 108cab6beb..401af9f0f5 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -40,6 +40,7 @@ tests_SOURCES = aclorch_ut.cpp \ $(top_srcdir)/orchagent/neighorch.cpp \ $(top_srcdir)/orchagent/intfsorch.cpp \ $(top_srcdir)/orchagent/portsorch.cpp \ + $(top_srcdir)/orchagent/fabricportsorch.cpp \ $(top_srcdir)/orchagent/copporch.cpp \ $(top_srcdir)/orchagent/tunneldecaporch.cpp \ $(top_srcdir)/orchagent/qosorch.cpp \