diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index e446bb76ac..40f9a8219c 100644 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -5,12 +5,14 @@ #include #include #include +#include #include #include "net/if.h" #include "logger.h" #include "schema.h" +#include "converter.h" extern sai_switch_api_t *sai_switch_api; extern sai_bridge_api_t *sai_bridge_api; @@ -470,6 +472,107 @@ void PortsOrch::updateDbPortOperStatus(sai_object_id_t id, sai_port_oper_status_ } } +bool PortsOrch::addPort(const set &lane_set, uint32_t speed) +{ + SWSS_LOG_ENTER(); + + vector lanes(lane_set.begin(), lane_set.end()); + + sai_attribute_t attr; + vector attrs; + + attr.id = SAI_PORT_ATTR_SPEED; + attr.value.u32 = speed; + attrs.push_back(attr); + + attr.id = SAI_PORT_ATTR_HW_LANE_LIST; + attr.value.u32list.list = lanes.data(); + attr.value.u32list.count = static_cast(lanes.size()); + attrs.push_back(attr); + + sai_object_id_t port_id; + sai_status_t status = sai_port_api->create_port(&port_id, gSwitchId, static_cast(attrs.size()), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create port with the speed %u, rv:%d", speed, status); + return false; + } + + m_portListLaneMap[lane_set] = port_id; + + SWSS_LOG_NOTICE("Create port %lx with the speed %u", port_id, speed); + + return true; +} + +bool PortsOrch::removePort(sai_object_id_t port_id) +{ + SWSS_LOG_ENTER(); + + sai_status_t status = sai_port_api->remove_port(port_id); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove port %lx, rv:%d", port_id, status); + return false; + } + + SWSS_LOG_NOTICE("Remove port %lx", port_id); + + return true; +} + +bool PortsOrch::initPort(const string &alias, const set &lane_set) +{ + SWSS_LOG_ENTER(); + + /* Determine if the lane combination exists in switch */ + if (m_portListLaneMap.find(lane_set) != m_portListLaneMap.end()) + { + sai_object_id_t id = m_portListLaneMap[lane_set]; + + /* Determine if the port has already been initialized before */ + if (m_portList.find(alias) != m_portList.end() && m_portList[alias].m_port_id == id) + { + SWSS_LOG_INFO("Port has already been initialized before alias:%s", alias.c_str()); + } + else + { + Port p(alias, Port::PHY); + + p.m_index = static_cast(m_portList.size()); // TODO: Assume no deletion of physical port + p.m_port_id = id; + + /* Initialize the port and create router interface and host interface */ + if (initializePort(p)) + { + /* Add port to port list */ + m_portList[alias] = p; + /* Add port name map to counter table */ + std::stringstream ss; + ss << hex << p.m_port_id; + FieldValueTuple tuple(p.m_alias, ss.str()); + vector vector; + vector.push_back(tuple); + m_counterTable->set("", vector); + + SWSS_LOG_NOTICE("Initialized port %s", alias.c_str()); + } + else + { + SWSS_LOG_ERROR("Failed to initialize port %s", alias.c_str()); + return false; + } + } + } + else + { + SWSS_LOG_ERROR("Failed to locate port lane combination alias:%s", alias.c_str()); + return false; + } + + return true; +} + void PortsOrch::doPortTask(Consumer &consumer) { SWSS_LOG_ENTER(); @@ -482,13 +585,26 @@ void PortsOrch::doPortTask(Consumer &consumer) string alias = kfvKey(t); string op = kfvOp(t); + if (alias == "PortConfigDone") + { + m_portConfigDone = true; + + for (auto i : kfvFieldsValues(t)) + { + if (fvField(i) == "count") + { + m_portCount = to_uint(fvValue(i)); + } + } + } + /* Get notification from application */ /* portsyncd application: - * When portsorch receives 'ConfigDone' message, it indicates port initialization + * When portsorch receives 'PortInitDone' message, it indicates port initialization * procedure is done. Before port initialization procedure, none of other tasks * are executed. */ - if (alias == "ConfigDone") + if (alias == "PortInitDone") { /* portsyncd restarting case: * When portsyncd restarts, duplicate notifications may be received. @@ -496,7 +612,7 @@ void PortsOrch::doPortTask(Consumer &consumer) if (!m_initDone) { m_initDone = true; - SWSS_LOG_INFO("Get ConfigDone notification from portsyncd."); + SWSS_LOG_INFO("Get PortInitDone notification from portsyncd."); } it = consumer.m_toSync.erase(it); @@ -523,7 +639,6 @@ void PortsOrch::doPortTask(Consumer &consumer) int lane = stoi(lane_str); lane_set.insert(lane); } - } /* Set port admin status */ @@ -539,47 +654,52 @@ void PortsOrch::doPortTask(Consumer &consumer) speed = (uint32_t)stoul(fvValue(i)); } + /* Collect information about all received ports */ if (lane_set.size()) { - /* Determine if the lane combination exists in switch */ - if (m_portListLaneMap.find(lane_set) != - m_portListLaneMap.end()) - { - sai_object_id_t id = m_portListLaneMap[lane_set]; + m_lanesAliasSpeedMap[lane_set] = make_tuple(alias, speed); + } - /* Determin if the port has already been initialized before */ - if (m_portList.find(alias) != m_portList.end() && m_portList[alias].m_port_id == id) + /* Once all ports received, go through the each port and perform appropriate actions: + * 1. Remove ports which don't exist anymore + * 2. Create new ports + * 3. Initialize all ports + */ + if (m_portConfigDone && (m_lanesAliasSpeedMap.size() == m_portCount)) + { + for (auto it = m_portListLaneMap.begin(); it != m_portListLaneMap.end();) + { + if (m_lanesAliasSpeedMap.find(it->first) == m_lanesAliasSpeedMap.end()) { - SWSS_LOG_INFO("Port has already been initialized before alias:%s", alias.c_str()); + if (!removePort(it->second)) + { + throw runtime_error("PortsOrch initialization failure."); + } + it = m_portListLaneMap.erase(it); } else { - Port p(alias, Port::PHY); - - p.m_index = (uint32_t)m_portList.size(); // TODO: Assume no deletion of physical port - p.m_port_id = id; + ++it; + } + } - /* Initialize the port and create router interface and host interface */ - if (initializePort(p)) + for (auto it = m_lanesAliasSpeedMap.begin(); it != m_lanesAliasSpeedMap.end();) + { + if (m_portListLaneMap.find(it->first) == m_portListLaneMap.end()) + { + if (!addPort(it->first, get<1>(it->second))) { - /* Add port to port list */ - m_portList[alias] = p; - /* Add port name map to counter table */ - std::stringstream ss; - ss << hex << p.m_port_id; - FieldValueTuple tuple(p.m_alias, ss.str()); - vector vector; - vector.push_back(tuple); - m_counterTable->set("", vector); - - SWSS_LOG_NOTICE("Initialized port %s", alias.c_str()); + throw runtime_error("PortsOrch initialization failure."); } - else - SWSS_LOG_ERROR("Failed to initialize port %s", alias.c_str()); } + + if (!initPort(get<0>(it->second), it->first)) + { + throw runtime_error("PortsOrch initialization failure."); + } + + it = m_lanesAliasSpeedMap.erase(it); } - else - SWSS_LOG_ERROR("Failed to locate port lane combination alias:%s", alias.c_str()); } Port p; diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index b5e78297e2..959f9bf77c 100644 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -67,8 +67,10 @@ class PortsOrch : public Orch, public Subject sai_object_id_t m_default1QBridge; sai_object_id_t m_defaultVlan; + bool m_portConfigDone = false; sai_uint32_t m_portCount; map, sai_object_id_t> m_portListLaneMap; + map, tuple> m_lanesAliasSpeedMap; map m_portList; void doTask(Consumer &consumer); @@ -100,6 +102,10 @@ class PortsOrch : public Orch, public Subject bool addLagMember(Port lag, Port port); bool removeLagMember(Port lag, Port port); + bool addPort(const set &lane_set, uint32_t speed); + bool removePort(sai_object_id_t port_id); + bool initPort(const string &alias, const set &lane_set); + bool setPortAdminStatus(sai_object_id_t id, bool up); bool setPortMtu(sai_object_id_t id, sai_uint32_t mtu); diff --git a/portsyncd/portsyncd.cpp b/portsyncd/portsyncd.cpp index f10c03ba6b..c62550fd7f 100644 --- a/portsyncd/portsyncd.cpp +++ b/portsyncd/portsyncd.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "dbconnector.h" #include "select.h" #include "netdispatcher.h" @@ -24,7 +25,7 @@ using namespace swss; * interfaces are already created and remove them from this set. We will * remove the rest of the ports in the set when receiving the first netlink * message indicating that the host interfaces are created. After the set - * is empty, we send out the signal ConfigDone. g_init is used to limit the + * is empty, we send out the signal PortInitDone. g_init is used to limit the * command to be run only once. */ set g_portSet; @@ -107,7 +108,7 @@ int main(int argc, char **argv) */ FieldValueTuple finish_notice("lanes", "0"); vector attrs = { finish_notice }; - p.set("ConfigDone", attrs); + p.set("PortInitDone", attrs); g_init = true; } @@ -134,34 +135,70 @@ void handlePortConfigFile(ProducerStateTable &p, string file) throw "Port configuration file not found!"; } + list header = {"name", "lanes", "alias", "speed"}; string line; while (getline(infile, line)) { if (line.at(0) == '#') { + /* Find out what info is specified in the configuration file */ + for (auto it = header.begin(); it != header.end();) + { + if (line.find(*it) == string::npos) + { + it = header.erase(it); + } + else + { + ++it; + } + } + continue; } istringstream iss(line); - string name, lanes, alias; - iss >> name >> lanes >> alias; + map entry; - /* If port has no alias, then use its' name as alias */ - if (alias == "") + /* Read port configuration entry */ + for (auto column : header) { - alias = name; + iss >> entry[column]; } - FieldValueTuple lanes_attr("lanes", lanes); + + /* If port has no alias, then use its name as alias */ + string alias; + if ((entry.find("alias") != entry.end()) && (entry["alias"] != "")) + { + alias = entry["alias"]; + } + else + { + alias = entry["name"]; + } + + FieldValueTuple lanes_attr("lanes", entry["lanes"]); FieldValueTuple alias_attr("alias", alias); vector attrs; attrs.push_back(lanes_attr); attrs.push_back(alias_attr); - p.set(name, attrs); + if ((entry.find("speed") != entry.end()) && (entry["speed"] != "")) + { + FieldValueTuple speed_attr("speed", entry["speed"]); + attrs.push_back(speed_attr); + } - g_portSet.insert(name); + p.set(entry["name"], attrs); + + g_portSet.insert(entry["name"]); } infile.close(); + + /* Notify that all ports added */ + FieldValueTuple finish_notice("count", to_string(g_portSet.size())); + vector attrs = { finish_notice }; + p.set("PortConfigDone", attrs); }