diff --git a/cfgmgr/portmgr.cpp b/cfgmgr/portmgr.cpp index 5134b31861..19ba41dc90 100644 --- a/cfgmgr/portmgr.cpp +++ b/cfgmgr/portmgr.cpp @@ -14,8 +14,10 @@ using namespace swss; PortMgr::PortMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector &tableNames) : Orch(cfgDb, tableNames), m_cfgPortTable(cfgDb, CFG_PORT_TABLE_NAME), + m_cfgSendToIngressPortTable(cfgDb, CFG_SEND_TO_INGRESS_PORT_TABLE_NAME), m_cfgLagMemberTable(cfgDb, CFG_LAG_MEMBER_TABLE_NAME), m_statePortTable(stateDb, STATE_PORT_TABLE_NAME), + m_appSendToIngressPortTable(appDb, APP_SEND_TO_INGRESS_PORT_TABLE_NAME), m_appPortTable(appDb, APP_PORT_TABLE_NAME) { } @@ -93,11 +95,49 @@ bool PortMgr::isPortStateOk(const string &alias) return false; } +void PortMgr::doSendToIngressPortTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + + string alias = kfvKey(t); + string op = kfvOp(t); + auto fvs = kfvFieldsValues(t); + + if (op == SET_COMMAND) + { + SWSS_LOG_NOTICE("Add SendToIngress Port: %s", + alias.c_str()); + m_appSendToIngressPortTable.set(alias, fvs); + } + else if (op == DEL_COMMAND) + { + SWSS_LOG_NOTICE("Removing SendToIngress Port: %s", + alias.c_str()); + m_appSendToIngressPortTable.del(alias); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); + } + it = consumer.m_toSync.erase(it); + } + +} + void PortMgr::doTask(Consumer &consumer) { SWSS_LOG_ENTER(); auto table = consumer.getTableName(); + if (table == CFG_SEND_TO_INGRESS_PORT_TABLE_NAME) + { + doSendToIngressPortTask(consumer); + return; + } auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) @@ -146,7 +186,7 @@ void PortMgr::doTask(Consumer &consumer) { admin_status = fvValue(i); } - else + else { field_values.emplace_back(i); } diff --git a/cfgmgr/portmgr.h b/cfgmgr/portmgr.h index 683aacc488..3d6f0365bf 100644 --- a/cfgmgr/portmgr.h +++ b/cfgmgr/portmgr.h @@ -22,13 +22,16 @@ class PortMgr : public Orch using Orch::doTask; private: Table m_cfgPortTable; + Table m_cfgSendToIngressPortTable; Table m_cfgLagMemberTable; Table m_statePortTable; ProducerStateTable m_appPortTable; + ProducerStateTable m_appSendToIngressPortTable; std::set m_portList; void doTask(Consumer &consumer); + void doSendToIngressPortTask(Consumer &consumer); bool writeConfigToAppDb(const std::string &alias, const std::string &field, const std::string &value); bool writeConfigToAppDb(const std::string &alias, std::vector &field_values); bool setPortMtu(const std::string &alias, const std::string &mtu); diff --git a/cfgmgr/portmgrd.cpp b/cfgmgr/portmgrd.cpp index 99c7974559..4d04b42d38 100644 --- a/cfgmgr/portmgrd.cpp +++ b/cfgmgr/portmgrd.cpp @@ -26,6 +26,7 @@ int main(int argc, char **argv) { vector cfg_port_tables = { CFG_PORT_TABLE_NAME, + CFG_SEND_TO_INGRESS_PORT_TABLE_NAME, }; DBConnector cfgDb("CONFIG_DB", 0); diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 6787fdf846..c19836989d 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -128,6 +128,7 @@ bool OrchDaemon::init() vector ports_tables = { { APP_PORT_TABLE_NAME, portsorch_base_pri + 5 }, + { APP_SEND_TO_INGRESS_PORT_TABLE_NAME, portsorch_base_pri + 5 }, { APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 }, { APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri }, { APP_LAG_TABLE_NAME, portsorch_base_pri + 4 }, @@ -173,7 +174,7 @@ bool OrchDaemon::init() gDirectory.set(vnet_rt_orch); VRFOrch *vrf_orch = new VRFOrch(m_applDb, APP_VRF_TABLE_NAME, m_stateDb, STATE_VRF_OBJECT_TABLE_NAME); gDirectory.set(vrf_orch); - gMonitorOrch = new MonitorOrch(m_stateDb, STATE_VNET_MONITOR_TABLE_NAME); + gMonitorOrch = new MonitorOrch(m_stateDb, STATE_VNET_MONITOR_TABLE_NAME); gDirectory.set(gMonitorOrch); const vector chassis_frontend_tables = { diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 9fad001d77..b345d1e709 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -384,6 +384,7 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector(new Table(db, APP_PORT_TABLE_NAME)); + m_sendToIngressPortTable = unique_ptr(new Table(db, APP_SEND_TO_INGRESS_PORT_TABLE_NAME)); /* Initialize gearbox */ m_gearboxTable = unique_ptr
(new Table(db, "_GEARBOX_TABLE")); @@ -3250,6 +3251,68 @@ void PortsOrch::removePortFromPortListMap(sai_object_id_t port_id) } } +void PortsOrch::doSendToIngressPortTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + auto &t = it->second; + + string alias = kfvKey(t); + string op = kfvOp(t); + ReturnCode rc; + std::vector app_state_db_attrs; + + if (op == SET_COMMAND) + { + if (m_isSendToIngressPortConfigured) + { + rc = ReturnCode(StatusCode::SWSS_RC_UNIMPLEMENTED) + << "Update operation on SendToIngress port with alias=" + << alias << " is not suported"; + SWSS_LOG_ERROR("%s", rc.message().c_str()); + m_publisher.publish(consumer.getTableName(), kfvKey(t), + kfvFieldsValues(t), rc); + it = consumer.m_toSync.erase(it); + continue; + } + rc = addSendToIngressHostIf(alias); + if (!rc.ok()) + { + SWSS_LOG_ERROR("%s", rc.message().c_str()); + } + else + { + m_isSendToIngressPortConfigured = true; + } + } + else if (op == DEL_COMMAND) + { + // For SendToIngress port, delete the host interface and unbind from the CPU port + rc = removeSendToIngressHostIf(); + if (!rc.ok()) + { + SWSS_LOG_ERROR("Failed to remove SendToIngress port rc=%s", + rc.message().c_str()); + } + else + { + m_isSendToIngressPortConfigured = false; + } + } + else + { + rc = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << + "Unknown operation type " << op; + SWSS_LOG_ERROR("%s", rc.message().c_str()); + } + m_publisher.publish(consumer.getTableName(), kfvKey(t), + kfvFieldsValues(t), rc); + it = consumer.m_toSync.erase(it); + } +} void PortsOrch::doPortTask(Consumer &consumer) { @@ -4765,6 +4828,10 @@ void PortsOrch::doTask(Consumer &consumer) { doPortTask(consumer); } + else if (table_name == APP_SEND_TO_INGRESS_PORT_TABLE_NAME) + { + doSendToIngressPortTask(consumer); + } else { /* Wait for all ports to be initialized */ @@ -5138,6 +5205,64 @@ bool PortsOrch::addHostIntfs(Port &port, string alias, sai_object_id_t &host_int return true; } +ReturnCode PortsOrch::addSendToIngressHostIf(const std::string &send_to_ingress_name) +{ + SWSS_LOG_ENTER(); + + // For SendToIngress port, add the host interface and bind to the CPU port + vector ingress_attribs; + sai_attribute_t attr; + + attr.id = SAI_HOSTIF_ATTR_TYPE; + attr.value.s32 = SAI_HOSTIF_TYPE_NETDEV; + ingress_attribs.push_back(attr); + + attr.id = SAI_HOSTIF_ATTR_NAME; + auto size = sizeof(attr.value.chardata); + strncpy(attr.value.chardata, send_to_ingress_name.c_str(), + size - 1); + attr.value.chardata[size - 1] = '\0'; + ingress_attribs.push_back(attr); + + // If this isn't passed as true, the false setting makes + // the device unready for later attempts to set UP/RUNNING + attr.id = SAI_HOSTIF_ATTR_OPER_STATUS; + attr.value.booldata = true; + ingress_attribs.push_back(attr); + + // Get CPU port object id to signal send to ingress + attr.id = SAI_HOSTIF_ATTR_OBJ_ID; + attr.value.oid = m_cpuPort.m_port_id; + ingress_attribs.push_back(attr); + + LOG_AND_RETURN_IF_ERROR(sai_hostif_api->create_hostif(&m_cpuPort.m_hif_id, + gSwitchId, + (uint32_t)ingress_attribs.size(), + ingress_attribs.data())); + + return ReturnCode(); +} + +ReturnCode PortsOrch::removeSendToIngressHostIf() +{ + SWSS_LOG_ENTER(); + + if (SAI_NULL_OBJECT_ID == m_cpuPort.m_hif_id) + { + ReturnCode rc = ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Can't delete invalid SendToIngress hostif with SAI_NULL_OBJECT_ID oid"; + SWSS_LOG_ERROR("%s", rc.message().c_str()); + return rc; + } + + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_hostif_api->remove_hostif(m_cpuPort.m_hif_id), + "Failed to delete SendToIngress hostif:0x" + << std::hex << m_cpuPort.m_hif_id); + + return ReturnCode(); +} + bool PortsOrch::setBridgePortLearningFDB(Port &port, sai_bridge_port_fdb_learning_mode_t mode) { // TODO: how to support 1D bridge? diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index 40f63dad0d..20e599f8cb 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -239,6 +239,7 @@ class PortsOrch : public Orch, public Subject unique_ptr
m_counterSysPortTable; unique_ptr
m_counterLagTable; unique_ptr
m_portTable; + unique_ptr
m_sendToIngressPortTable; unique_ptr
m_gearboxTable; unique_ptr
m_queueTable; unique_ptr
m_voqTable; @@ -276,6 +277,7 @@ class PortsOrch : public Orch, public Subject std::map m_portSupportedFecModes; bool m_initDone = false; + bool m_isSendToIngressPortConfigured = false; Port m_cpuPort; // TODO: Add Bridge/Vlan class sai_object_id_t m_default1QBridge; @@ -331,6 +333,7 @@ class PortsOrch : public Orch, public Subject void doTask() override; void doTask(Consumer &consumer); void doPortTask(Consumer &consumer); + void doSendToIngressPortTask(Consumer &consumer); void doVlanTask(Consumer &consumer); void doVlanMemberTask(Consumer &consumer); void doLagTask(Consumer &consumer); @@ -464,6 +467,9 @@ class PortsOrch : public Orch, public Subject bool getSaiAclBindPointType(Port::Type type, sai_acl_bind_point_type_t &sai_acl_bind_type); + + ReturnCode addSendToIngressHostIf(const std::string &send_to_ingress_name); + ReturnCode removeSendToIngressHostIf(); void initGearbox(); bool initGearboxPort(Port &port); bool getPortOperFec(const Port& port, sai_port_fec_mode_t &fec_mode) const; diff --git a/tests/mock_tests/portsorch_ut.cpp b/tests/mock_tests/portsorch_ut.cpp index c338b9fbeb..d304901c90 100644 --- a/tests/mock_tests/portsorch_ut.cpp +++ b/tests/mock_tests/portsorch_ut.cpp @@ -314,6 +314,7 @@ namespace portsorch_test vector ports_tables = { { APP_PORT_TABLE_NAME, portsorch_base_pri + 5 }, + { APP_SEND_TO_INGRESS_PORT_TABLE_NAME, portsorch_base_pri + 5 }, { APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 }, { APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri }, { APP_LAG_TABLE_NAME, portsorch_base_pri + 4 }, @@ -1236,6 +1237,7 @@ namespace portsorch_test TEST_F(PortsOrchTest, PortReadinessColdBoot) { Table portTable = Table(m_app_db.get(), APP_PORT_TABLE_NAME); + Table sendToIngressPortTable = Table(m_app_db.get(), APP_SEND_TO_INGRESS_PORT_TABLE_NAME); Table pgTable = Table(m_app_db.get(), APP_BUFFER_PG_TABLE_NAME); Table pgTableCfg = Table(m_config_db.get(), CFG_BUFFER_PG_TABLE_NAME); Table profileTable = Table(m_app_db.get(), APP_BUFFER_PROFILE_TABLE_NAME); @@ -1289,6 +1291,8 @@ namespace portsorch_test // Set PortConfigDone portTable.set("PortConfigDone", { { "count", to_string(ports.size()) } }); + // Populate send to ingresss port table + sendToIngressPortTable.set("SEND_TO_INGRESS", {{"NULL", "NULL"}}); // refill consumer gPortsOrch->addExistingData(&portTable);