Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[portsorch]: Add support of cable breakout feature #320

Merged
merged 1 commit into from
Oct 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 153 additions & 33 deletions orchagent/portsorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
#include <sstream>
#include <set>
#include <algorithm>
#include <tuple>

#include <netinet/if_ether.h>
#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;
Expand Down Expand Up @@ -470,6 +472,107 @@ void PortsOrch::updateDbPortOperStatus(sai_object_id_t id, sai_port_oper_status_
}
}

bool PortsOrch::addPort(const set<int> &lane_set, uint32_t speed)
{
SWSS_LOG_ENTER();

vector<uint32_t> lanes(lane_set.begin(), lane_set.end());

sai_attribute_t attr;
vector<sai_attribute_t> 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<uint32_t>(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<uint32_t>(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<int> &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<int32_t>(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 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create router interface [](start = 39, length = 23)

this comment here is actualy incorrect, the initializePort no longer crate router interface.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct. let me modify it.

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<FieldValueTuple> 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();
Expand All @@ -482,21 +585,34 @@ 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<uint32_t>(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.
*/
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);
Expand All @@ -523,7 +639,6 @@ void PortsOrch::doPortTask(Consumer &consumer)
int lane = stoi(lane_str);
lane_set.insert(lane);
}

}

/* Set port admin status */
Expand All @@ -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<FieldValueTuple> 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;
Expand Down
6 changes: 6 additions & 0 deletions orchagent/portsorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<set<int>, sai_object_id_t> m_portListLaneMap;
map<set<int>, tuple<string, uint32_t>> m_lanesAliasSpeedMap;
map<string, Port> m_portList;

void doTask(Consumer &consumer);
Expand Down Expand Up @@ -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<int> &lane_set, uint32_t speed);
bool removePort(sai_object_id_t port_id);
bool initPort(const string &alias, const set<int> &lane_set);

bool setPortAdminStatus(sai_object_id_t id, bool up);
bool setPortMtu(sai_object_id_t id, sai_uint32_t mtu);

Expand Down
57 changes: 47 additions & 10 deletions portsyncd/portsyncd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <vector>
#include <set>
#include <map>
#include <list>
#include "dbconnector.h"
#include "select.h"
#include "netdispatcher.h"
Expand All @@ -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<string> g_portSet;
Expand Down Expand Up @@ -107,7 +108,7 @@ int main(int argc, char **argv)
*/
FieldValueTuple finish_notice("lanes", "0");
vector<FieldValueTuple> attrs = { finish_notice };
p.set("ConfigDone", attrs);
p.set("PortInitDone", attrs);

g_init = true;
}
Expand All @@ -134,34 +135,70 @@ void handlePortConfigFile(ProducerStateTable &p, string file)
throw "Port configuration file not found!";
}

list<string> 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<string, string> 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<FieldValueTuple> 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<FieldValueTuple> attrs = { finish_notice };
p.set("PortConfigDone", attrs);
}