Skip to content

Commit

Permalink
[autoneg] add support for capability checker and remote speed adverti…
Browse files Browse the repository at this point in the history
…sement

HLD: sonic-net/SONiC#924

- What I did
Add support for remote speed advertisement
Add support for capability checker

- How I did it
Implementation is done according to the AutoNeg HLD

Signed-off-by: Dante Su <dante.su@broadcom.com>
  • Loading branch information
ds952811 committed Apr 1, 2022
1 parent f4ec565 commit 891bc82
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 1 deletion.
1 change: 1 addition & 0 deletions orchagent/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class Port

bool m_fec_cfg = false;
bool m_an_cfg = false;
bool m_port_cap_an = false; /* Port Capability - AutoNeg */
};

}
Expand Down
148 changes: 147 additions & 1 deletion orchagent/portsorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ extern string gMyAsicName;
#define DEFAULT_VLAN_ID 1
#define MAX_VALID_VLAN_ID 4094

#define PORT_STAT_POLLING_SEC 1
#define PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 1000
#define PORT_BUFFER_DROP_STAT_POLLING_INTERVAL_MS 60000
#define QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 10000
Expand Down Expand Up @@ -298,7 +299,8 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector<table_name_wi
m_portStateTable(stateDb, STATE_PORT_TABLE_NAME),
port_stat_manager(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, false),
port_buffer_drop_stat_manager(PORT_BUFFER_DROP_STAT_FLEX_COUNTER_GROUP, StatsMode::READ, PORT_BUFFER_DROP_STAT_POLLING_INTERVAL_MS, false),
queue_stat_manager(QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, false)
queue_stat_manager(QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, false),
m_timer(new SelectableTimer(timespec { .tv_sec = PORT_STAT_POLLING_SEC, .tv_nsec = 0 }))
{
SWSS_LOG_ENTER();

Expand Down Expand Up @@ -563,6 +565,10 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector<table_name_wi

m_lagIdAllocator = unique_ptr<LagIdAllocator> (new LagIdAllocator(chassisAppDb));
}

auto executor = new ExecutableTimer(m_timer, this, "PORT_STATE_POLL");
Orch::addExecutor(executor);
m_timer->start();
}

void PortsOrch::removeDefaultVlanMembers()
Expand Down Expand Up @@ -1860,6 +1866,24 @@ void PortsOrch::initPortSupportedSpeeds(const std::string& alias, sai_object_id_
m_portStateTable.set(alias, v);
}

void PortsOrch::initPortCapAutoNeg(Port &port)
{
sai_status_t status;
sai_attribute_t attr;

attr.id = SAI_PORT_ATTR_SUPPORTED_AUTO_NEG_MODE;
status = sai_port_api->set_port_attribute(port.m_port_id, &attr);
if (status == SAI_STATUS_SUCCESS)
{
port.m_port_cap_an = attr.value.booldata;
}
else
{
port.m_port_cap_an = false;
SWSS_LOG_NOTICE("Unable to get %s AN capability", port.m_alias.c_str());
}
}

/*
* If Gearbox is enabled and this is a Gearbox port then set the attributes accordingly.
*/
Expand Down Expand Up @@ -2014,6 +2038,61 @@ bool PortsOrch::getPortSpeed(sai_object_id_t id, sai_uint32_t &speed)
return true;
}

bool PortsOrch::getPortAdvSpeeds(const Port& port, bool remote, std::vector<sai_uint32_t>& speed_list)
{
sai_object_id_t port_id = port.m_port_id;
sai_object_id_t line_port_id;
sai_attribute_t attr;
sai_status_t status;
const auto size_guess = 16; // Guess the size which could be enough
std::vector<sai_uint32_t> speeds(size_guess);

attr.id = remote ? SAI_PORT_ATTR_REMOTE_ADVERTISED_SPEED : SAI_PORT_ATTR_ADVERTISED_SPEED;
attr.value.u32list.count = static_cast<uint32_t>(speeds.size());
attr.value.u32list.list = speeds.data();

if (getDestPortId(port_id, LINE_PORT_TYPE, line_port_id))
{
status = sai_port_api->get_port_attribute(line_port_id, 1, &attr);
}
else
{
status = sai_port_api->get_port_attribute(port_id, 1, &attr);
}
if (status != SAI_STATUS_SUCCESS)
{
return false;
}
speeds.resize(attr.value.u32list.count);

speed_list.clear();
for (auto it = speeds.begin(); it != speeds.end(); ++it)
{
speed_list.push_back(*it);
}
return true;
}

bool PortsOrch::getPortAdvSpeeds(const Port& port, bool remote, string& adv_speeds)
{
std::vector<sai_uint32_t> speed_list;
bool rc = getPortAdvSpeeds(port, remote, speed_list);

adv_speeds = "";
if (rc)
{
for (auto it = speed_list.begin(); it != speed_list.end(); ++it)
{
adv_speeds += std::to_string(*it);
if (it + 1 != speed_list.end())
{
adv_speeds += ",";
}
}
}
return rc;
}

task_process_status PortsOrch::setPortAdvSpeeds(sai_object_id_t port_id, std::vector<sai_uint32_t>& speed_list)
{
SWSS_LOG_ENTER();
Expand Down Expand Up @@ -2351,6 +2430,9 @@ bool PortsOrch::initPort(const string &alias, const string &role, const int inde
/* Create associated Gearbox lane mapping */
initGearboxPort(p);

/* Initialize port capabilities */
initPortCapAutoNeg(p);

/* Add port to port list */
m_portList[alias] = p;
saiOidToAlias[id] = alias;
Expand Down Expand Up @@ -2858,6 +2940,13 @@ void PortsOrch::doPortTask(Consumer &consumer)
{
if (!an_str.empty())
{
if (!p.m_port_cap_an)
{
SWSS_LOG_ERROR("%s: autoneg is not supported", p.m_alias.c_str());
// Invalid auto negotiation mode configured, don't retry
it = consumer.m_toSync.erase(it);
continue;
}
if (autoneg_mode_map.find(an_str) == autoneg_mode_map.end())
{
SWSS_LOG_ERROR("Failed to parse autoneg value: %s", an_str.c_str());
Expand Down Expand Up @@ -2900,6 +2989,15 @@ void PortsOrch::doPortTask(Consumer &consumer)
SWSS_LOG_NOTICE("Set port %s AutoNeg from %d to %d", alias.c_str(), p.m_autoneg, an);
p.m_autoneg = an;
m_portList[alias] = p;
m_portStateTable.hdel(p.m_alias, "rmt_adv_speeds");
if (an > 0)
{
m_port_state_poll[p.m_alias] |= PORT_STATE_POLL_AN;
}
else
{
m_port_state_poll[p.m_alias] &= ~PORT_STATE_POLL_AN;
}
}
}

Expand Down Expand Up @@ -5666,6 +5764,20 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status)
if (port.m_type == Port::PHY)
{
updateDbPortOperStatus(port, status);
if (port.m_autoneg > 0)
{
if (status == SAI_PORT_OPER_STATUS_UP)
{
updatePortStateAutoNeg(port);
m_port_state_poll[port.m_alias] &= ~PORT_STATE_POLL_AN;
}
else
{
/* Restart autoneg state polling upon link down event */
m_portStateTable.hdel(port.m_alias, "rmt_adv_speeds");
m_port_state_poll[port.m_alias] |= PORT_STATE_POLL_AN;
}
}
}
port.m_oper_status = status;

Expand Down Expand Up @@ -6792,3 +6904,37 @@ std::unordered_set<std::string> PortsOrch::generateCounterStats(const string& ty
}
return counter_stats;
}

void PortsOrch::updatePortStateAutoNeg(const Port &port)
{
SWSS_LOG_ENTER();

if (port.m_type != Port::Type::PHY)
{
return;
}

string adv_speeds;

if (getPortAdvSpeeds(port, true, adv_speeds))
{
m_portStateTable.hset(port.m_alias, "rmt_adv_speeds", adv_speeds);
}
else
{
m_port_state_poll[port.m_alias] &= ~PORT_STATE_POLL_AN;
}
}

void PortsOrch::doTask(swss::SelectableTimer &timer)
{
SWSS_LOG_ENTER();

for (auto it = m_portList.begin(); it != m_portList.end(); ++it)
{
if (m_port_state_poll[it->second.m_alias] & PORT_STATE_POLL_AN)
{
updatePortStateAutoNeg(it->second);
}
}
}
16 changes: 16 additions & 0 deletions orchagent/portsorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ class PortsOrch : public Orch, public Subject
LINE_PORT_TYPE,
} dest_port_type_t;

typedef enum {
PORT_STATE_POLL_NONE = 0,
PORT_STATE_POLL_AN = 0x00000001, /* Auto Negotiation */
PORT_STATE_POLL_LT = 0x00000002 /* Link Trainig */
} port_state_poll_t;

bool m_gearboxEnabled = false;
map<int, gearbox_phy_t> m_gearboxPhyMap;
map<int, gearbox_interface_t> m_gearboxInterfaceMap;
Expand Down Expand Up @@ -245,6 +251,8 @@ class PortsOrch : public Orch, public Subject

NotificationConsumer* m_portStatusNotificationConsumer;

swss::SelectableTimer *m_timer = nullptr;

void doTask() override;
void doTask(Consumer &consumer);
void doPortTask(Consumer &consumer);
Expand All @@ -254,6 +262,7 @@ class PortsOrch : public Orch, public Subject
void doLagMemberTask(Consumer &consumer);

void doTask(NotificationConsumer &consumer);
void doTask(swss::SelectableTimer &timer);

void removePortFromLanesMap(string alias);
void removePortFromPortListMap(sai_object_id_t port_id);
Expand Down Expand Up @@ -286,6 +295,8 @@ class PortsOrch : public Orch, public Subject
bool initPort(const string &alias, const string &role, const int index, const set<int> &lane_set);
void deInitPort(string alias, sai_object_id_t port_id);

void initPortCapAutoNeg(Port &port);

bool setPortAdminStatus(Port &port, bool up);
bool getPortAdminStatus(sai_object_id_t id, bool& up);
bool setPortMtu(sai_object_id_t id, sai_uint32_t mtu);
Expand All @@ -306,6 +317,8 @@ class PortsOrch : public Orch, public Subject
bool setGearboxPortsAttr(Port &port, sai_port_attr_t id, void *value);
bool setGearboxPortAttr(Port &port, dest_port_type_t port_type, sai_port_attr_t id, void *value);

bool getPortAdvSpeeds(const Port& port, bool remote, std::vector<sai_uint32_t>& speed_list);
bool getPortAdvSpeeds(const Port& port, bool remote, string& adv_speeds);
task_process_status setPortAdvSpeeds(sai_object_id_t port_id, std::vector<sai_uint32_t>& speed_list);

bool getQueueTypeAndIndex(sai_object_id_t queue_id, string &type, uint8_t &index);
Expand All @@ -329,6 +342,9 @@ class PortsOrch : public Orch, public Subject
bool getPortOperSpeed(const Port& port, sai_uint32_t& speed) const;
void updateDbPortOperSpeed(Port &port, sai_uint32_t speed);

map<string, uint32_t> m_port_state_poll;
void updatePortStateAutoNeg(const Port &port);

void getPortSerdesVal(const std::string& s, std::vector<uint32_t> &lane_values);
bool getPortAdvSpeedsVal(const std::string &s, std::vector<uint32_t> &speed_values);
bool getPortInterfaceTypeVal(const std::string &s, sai_port_interface_type_t &interface_type);
Expand Down

0 comments on commit 891bc82

Please sign in to comment.