Skip to content

Commit 53d6a1d

Browse files
Volodymyr SamotiyShuotian Cheng
authored andcommitted
[portsorch]: Add support of cable breakout feature (sonic-net#320)
Signed-off-by: Volodymyr Samotiy <[email protected]>
1 parent bcdea13 commit 53d6a1d

3 files changed

Lines changed: 206 additions & 43 deletions

File tree

orchagent/portsorch.cpp

Lines changed: 153 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
#include <sstream>
66
#include <set>
77
#include <algorithm>
8+
#include <tuple>
89

910
#include <netinet/if_ether.h>
1011
#include "net/if.h"
1112

1213
#include "logger.h"
1314
#include "schema.h"
15+
#include "converter.h"
1416

1517
extern sai_switch_api_t *sai_switch_api;
1618
extern sai_bridge_api_t *sai_bridge_api;
@@ -470,6 +472,107 @@ void PortsOrch::updateDbPortOperStatus(sai_object_id_t id, sai_port_oper_status_
470472
}
471473
}
472474

475+
bool PortsOrch::addPort(const set<int> &lane_set, uint32_t speed)
476+
{
477+
SWSS_LOG_ENTER();
478+
479+
vector<uint32_t> lanes(lane_set.begin(), lane_set.end());
480+
481+
sai_attribute_t attr;
482+
vector<sai_attribute_t> attrs;
483+
484+
attr.id = SAI_PORT_ATTR_SPEED;
485+
attr.value.u32 = speed;
486+
attrs.push_back(attr);
487+
488+
attr.id = SAI_PORT_ATTR_HW_LANE_LIST;
489+
attr.value.u32list.list = lanes.data();
490+
attr.value.u32list.count = static_cast<uint32_t>(lanes.size());
491+
attrs.push_back(attr);
492+
493+
sai_object_id_t port_id;
494+
sai_status_t status = sai_port_api->create_port(&port_id, gSwitchId, static_cast<uint32_t>(attrs.size()), attrs.data());
495+
if (status != SAI_STATUS_SUCCESS)
496+
{
497+
SWSS_LOG_ERROR("Failed to create port with the speed %u, rv:%d", speed, status);
498+
return false;
499+
}
500+
501+
m_portListLaneMap[lane_set] = port_id;
502+
503+
SWSS_LOG_NOTICE("Create port %lx with the speed %u", port_id, speed);
504+
505+
return true;
506+
}
507+
508+
bool PortsOrch::removePort(sai_object_id_t port_id)
509+
{
510+
SWSS_LOG_ENTER();
511+
512+
sai_status_t status = sai_port_api->remove_port(port_id);
513+
if (status != SAI_STATUS_SUCCESS)
514+
{
515+
SWSS_LOG_ERROR("Failed to remove port %lx, rv:%d", port_id, status);
516+
return false;
517+
}
518+
519+
SWSS_LOG_NOTICE("Remove port %lx", port_id);
520+
521+
return true;
522+
}
523+
524+
bool PortsOrch::initPort(const string &alias, const set<int> &lane_set)
525+
{
526+
SWSS_LOG_ENTER();
527+
528+
/* Determine if the lane combination exists in switch */
529+
if (m_portListLaneMap.find(lane_set) != m_portListLaneMap.end())
530+
{
531+
sai_object_id_t id = m_portListLaneMap[lane_set];
532+
533+
/* Determine if the port has already been initialized before */
534+
if (m_portList.find(alias) != m_portList.end() && m_portList[alias].m_port_id == id)
535+
{
536+
SWSS_LOG_INFO("Port has already been initialized before alias:%s", alias.c_str());
537+
}
538+
else
539+
{
540+
Port p(alias, Port::PHY);
541+
542+
p.m_index = static_cast<int32_t>(m_portList.size()); // TODO: Assume no deletion of physical port
543+
p.m_port_id = id;
544+
545+
/* Initialize the port and create router interface and host interface */
546+
if (initializePort(p))
547+
{
548+
/* Add port to port list */
549+
m_portList[alias] = p;
550+
/* Add port name map to counter table */
551+
std::stringstream ss;
552+
ss << hex << p.m_port_id;
553+
FieldValueTuple tuple(p.m_alias, ss.str());
554+
vector<FieldValueTuple> vector;
555+
vector.push_back(tuple);
556+
m_counterTable->set("", vector);
557+
558+
SWSS_LOG_NOTICE("Initialized port %s", alias.c_str());
559+
}
560+
else
561+
{
562+
SWSS_LOG_ERROR("Failed to initialize port %s", alias.c_str());
563+
return false;
564+
}
565+
}
566+
}
567+
else
568+
{
569+
SWSS_LOG_ERROR("Failed to locate port lane combination alias:%s", alias.c_str());
570+
return false;
571+
}
572+
573+
return true;
574+
}
575+
473576
void PortsOrch::doPortTask(Consumer &consumer)
474577
{
475578
SWSS_LOG_ENTER();
@@ -482,21 +585,34 @@ void PortsOrch::doPortTask(Consumer &consumer)
482585
string alias = kfvKey(t);
483586
string op = kfvOp(t);
484587

588+
if (alias == "PortConfigDone")
589+
{
590+
m_portConfigDone = true;
591+
592+
for (auto i : kfvFieldsValues(t))
593+
{
594+
if (fvField(i) == "count")
595+
{
596+
m_portCount = to_uint<uint32_t>(fvValue(i));
597+
}
598+
}
599+
}
600+
485601
/* Get notification from application */
486602
/* portsyncd application:
487-
* When portsorch receives 'ConfigDone' message, it indicates port initialization
603+
* When portsorch receives 'PortInitDone' message, it indicates port initialization
488604
* procedure is done. Before port initialization procedure, none of other tasks
489605
* are executed.
490606
*/
491-
if (alias == "ConfigDone")
607+
if (alias == "PortInitDone")
492608
{
493609
/* portsyncd restarting case:
494610
* When portsyncd restarts, duplicate notifications may be received.
495611
*/
496612
if (!m_initDone)
497613
{
498614
m_initDone = true;
499-
SWSS_LOG_INFO("Get ConfigDone notification from portsyncd.");
615+
SWSS_LOG_INFO("Get PortInitDone notification from portsyncd.");
500616
}
501617

502618
it = consumer.m_toSync.erase(it);
@@ -523,7 +639,6 @@ void PortsOrch::doPortTask(Consumer &consumer)
523639
int lane = stoi(lane_str);
524640
lane_set.insert(lane);
525641
}
526-
527642
}
528643

529644
/* Set port admin status */
@@ -539,47 +654,52 @@ void PortsOrch::doPortTask(Consumer &consumer)
539654
speed = (uint32_t)stoul(fvValue(i));
540655
}
541656

657+
/* Collect information about all received ports */
542658
if (lane_set.size())
543659
{
544-
/* Determine if the lane combination exists in switch */
545-
if (m_portListLaneMap.find(lane_set) !=
546-
m_portListLaneMap.end())
547-
{
548-
sai_object_id_t id = m_portListLaneMap[lane_set];
660+
m_lanesAliasSpeedMap[lane_set] = make_tuple(alias, speed);
661+
}
549662

550-
/* Determin if the port has already been initialized before */
551-
if (m_portList.find(alias) != m_portList.end() && m_portList[alias].m_port_id == id)
663+
/* Once all ports received, go through the each port and perform appropriate actions:
664+
* 1. Remove ports which don't exist anymore
665+
* 2. Create new ports
666+
* 3. Initialize all ports
667+
*/
668+
if (m_portConfigDone && (m_lanesAliasSpeedMap.size() == m_portCount))
669+
{
670+
for (auto it = m_portListLaneMap.begin(); it != m_portListLaneMap.end();)
671+
{
672+
if (m_lanesAliasSpeedMap.find(it->first) == m_lanesAliasSpeedMap.end())
552673
{
553-
SWSS_LOG_INFO("Port has already been initialized before alias:%s", alias.c_str());
674+
if (!removePort(it->second))
675+
{
676+
throw runtime_error("PortsOrch initialization failure.");
677+
}
678+
it = m_portListLaneMap.erase(it);
554679
}
555680
else
556681
{
557-
Port p(alias, Port::PHY);
558-
559-
p.m_index = (uint32_t)m_portList.size(); // TODO: Assume no deletion of physical port
560-
p.m_port_id = id;
682+
++it;
683+
}
684+
}
561685

562-
/* Initialize the port and create router interface and host interface */
563-
if (initializePort(p))
686+
for (auto it = m_lanesAliasSpeedMap.begin(); it != m_lanesAliasSpeedMap.end();)
687+
{
688+
if (m_portListLaneMap.find(it->first) == m_portListLaneMap.end())
689+
{
690+
if (!addPort(it->first, get<1>(it->second)))
564691
{
565-
/* Add port to port list */
566-
m_portList[alias] = p;
567-
/* Add port name map to counter table */
568-
std::stringstream ss;
569-
ss << hex << p.m_port_id;
570-
FieldValueTuple tuple(p.m_alias, ss.str());
571-
vector<FieldValueTuple> vector;
572-
vector.push_back(tuple);
573-
m_counterTable->set("", vector);
574-
575-
SWSS_LOG_NOTICE("Initialized port %s", alias.c_str());
692+
throw runtime_error("PortsOrch initialization failure.");
576693
}
577-
else
578-
SWSS_LOG_ERROR("Failed to initialize port %s", alias.c_str());
579694
}
695+
696+
if (!initPort(get<0>(it->second), it->first))
697+
{
698+
throw runtime_error("PortsOrch initialization failure.");
699+
}
700+
701+
it = m_lanesAliasSpeedMap.erase(it);
580702
}
581-
else
582-
SWSS_LOG_ERROR("Failed to locate port lane combination alias:%s", alias.c_str());
583703
}
584704

585705
Port p;

orchagent/portsorch.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@ class PortsOrch : public Orch, public Subject
6767
sai_object_id_t m_default1QBridge;
6868
sai_object_id_t m_defaultVlan;
6969

70+
bool m_portConfigDone = false;
7071
sai_uint32_t m_portCount;
7172
map<set<int>, sai_object_id_t> m_portListLaneMap;
73+
map<set<int>, tuple<string, uint32_t>> m_lanesAliasSpeedMap;
7274
map<string, Port> m_portList;
7375

7476
void doTask(Consumer &consumer);
@@ -100,6 +102,10 @@ class PortsOrch : public Orch, public Subject
100102
bool addLagMember(Port lag, Port port);
101103
bool removeLagMember(Port lag, Port port);
102104

105+
bool addPort(const set<int> &lane_set, uint32_t speed);
106+
bool removePort(sai_object_id_t port_id);
107+
bool initPort(const string &alias, const set<int> &lane_set);
108+
103109
bool setPortAdminStatus(sai_object_id_t id, bool up);
104110
bool setPortMtu(sai_object_id_t id, sai_uint32_t mtu);
105111

portsyncd/portsyncd.cpp

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <vector>
66
#include <set>
77
#include <map>
8+
#include <list>
89
#include "dbconnector.h"
910
#include "select.h"
1011
#include "netdispatcher.h"
@@ -24,7 +25,7 @@ using namespace swss;
2425
* interfaces are already created and remove them from this set. We will
2526
* remove the rest of the ports in the set when receiving the first netlink
2627
* message indicating that the host interfaces are created. After the set
27-
* is empty, we send out the signal ConfigDone. g_init is used to limit the
28+
* is empty, we send out the signal PortInitDone. g_init is used to limit the
2829
* command to be run only once.
2930
*/
3031
set<string> g_portSet;
@@ -107,7 +108,7 @@ int main(int argc, char **argv)
107108
*/
108109
FieldValueTuple finish_notice("lanes", "0");
109110
vector<FieldValueTuple> attrs = { finish_notice };
110-
p.set("ConfigDone", attrs);
111+
p.set("PortInitDone", attrs);
111112

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

138+
list<string> header = {"name", "lanes", "alias", "speed"};
137139
string line;
138140
while (getline(infile, line))
139141
{
140142
if (line.at(0) == '#')
141143
{
144+
/* Find out what info is specified in the configuration file */
145+
for (auto it = header.begin(); it != header.end();)
146+
{
147+
if (line.find(*it) == string::npos)
148+
{
149+
it = header.erase(it);
150+
}
151+
else
152+
{
153+
++it;
154+
}
155+
}
156+
142157
continue;
143158
}
144159

145160
istringstream iss(line);
146-
string name, lanes, alias;
147-
iss >> name >> lanes >> alias;
161+
map<string, string> entry;
148162

149-
/* If port has no alias, then use its' name as alias */
150-
if (alias == "")
163+
/* Read port configuration entry */
164+
for (auto column : header)
151165
{
152-
alias = name;
166+
iss >> entry[column];
153167
}
154-
FieldValueTuple lanes_attr("lanes", lanes);
168+
169+
/* If port has no alias, then use its name as alias */
170+
string alias;
171+
if ((entry.find("alias") != entry.end()) && (entry["alias"] != ""))
172+
{
173+
alias = entry["alias"];
174+
}
175+
else
176+
{
177+
alias = entry["name"];
178+
}
179+
180+
FieldValueTuple lanes_attr("lanes", entry["lanes"]);
155181
FieldValueTuple alias_attr("alias", alias);
156182

157183
vector<FieldValueTuple> attrs;
158184
attrs.push_back(lanes_attr);
159185
attrs.push_back(alias_attr);
160186

161-
p.set(name, attrs);
187+
if ((entry.find("speed") != entry.end()) && (entry["speed"] != ""))
188+
{
189+
FieldValueTuple speed_attr("speed", entry["speed"]);
190+
attrs.push_back(speed_attr);
191+
}
162192

163-
g_portSet.insert(name);
193+
p.set(entry["name"], attrs);
194+
195+
g_portSet.insert(entry["name"]);
164196
}
165197

166198
infile.close();
199+
200+
/* Notify that all ports added */
201+
FieldValueTuple finish_notice("count", to_string(g_portSet.size()));
202+
vector<FieldValueTuple> attrs = { finish_notice };
203+
p.set("PortConfigDone", attrs);
167204
}

0 commit comments

Comments
 (0)