-
Notifications
You must be signed in to change notification settings - Fork 557
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
Port configuration incremental update support #2305
Changes from 12 commits
0273978
623b64a
400ee4b
24697b2
c104b77
1cca0aa
97fae06
9dce0ca
9c5990d
0b9b2e1
0b18221
bbaadc5
55a18d9
ebeb091
5b99253
25cb579
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,29 +31,9 @@ bool PortMgr::setPortMtu(const string &alias, const string &mtu) | |
|
||
// Set the port MTU in application database to update both | ||
// the port MTU and possibly the port based router interface MTU | ||
vector<FieldValueTuple> fvs; | ||
FieldValueTuple fv("mtu", mtu); | ||
fvs.push_back(fv); | ||
m_appPortTable.set(alias, fvs); | ||
|
||
return true; | ||
} | ||
|
||
bool PortMgr::setPortTpid(const string &alias, const string &tpid) | ||
{ | ||
stringstream cmd; | ||
string res; | ||
|
||
// Set the port TPID in application database to update port TPID | ||
vector<FieldValueTuple> fvs; | ||
FieldValueTuple fv("tpid", tpid); | ||
fvs.push_back(fv); | ||
m_appPortTable.set(alias, fvs); | ||
|
||
return true; | ||
return writeConfigToAppDb(alias, "mtu", mtu); | ||
} | ||
|
||
|
||
bool PortMgr::setPortAdminStatus(const string &alias, const bool up) | ||
{ | ||
stringstream cmd; | ||
|
@@ -63,23 +43,7 @@ bool PortMgr::setPortAdminStatus(const string &alias, const bool up) | |
cmd << IP_CMD << " link set dev " << shellquote(alias) << (up ? " up" : " down"); | ||
EXEC_WITH_ERROR_THROW(cmd.str(), res); | ||
|
||
vector<FieldValueTuple> fvs; | ||
FieldValueTuple fv("admin_status", (up ? "up" : "down")); | ||
fvs.push_back(fv); | ||
m_appPortTable.set(alias, fvs); | ||
|
||
return true; | ||
} | ||
|
||
bool PortMgr::setPortLearnMode(const string &alias, const string &learn_mode) | ||
{ | ||
// Set the port MAC learn mode in application database | ||
vector<FieldValueTuple> fvs; | ||
FieldValueTuple fv("learn_mode", learn_mode); | ||
fvs.push_back(fv); | ||
m_appPortTable.set(alias, fvs); | ||
|
||
return true; | ||
return writeConfigToAppDb(alias, "admin_status", (up ? "up" : "down")); | ||
} | ||
|
||
bool PortMgr::isPortStateOk(const string &alias) | ||
|
@@ -117,14 +81,14 @@ void PortMgr::doTask(Consumer &consumer) | |
|
||
if (op == SET_COMMAND) | ||
{ | ||
if (!isPortStateOk(alias)) | ||
{ | ||
SWSS_LOG_INFO("Port %s is not ready, pending...", alias.c_str()); | ||
it++; | ||
continue; | ||
} | ||
/* portOk=true indicates that the port has been created in kernel. | ||
* We should not call any ip command if portOk=false. However, it is | ||
* valid to put port configuration to APP DB which will trigger port creation in kernel. | ||
*/ | ||
bool portOk = isPortStateOk(alias); | ||
|
||
string admin_status, mtu, learn_mode, tpid; | ||
std::vector<FieldValueTuple> field_values; | ||
|
||
bool configured = (m_portList.find(alias) != m_portList.end()); | ||
|
||
|
@@ -157,31 +121,57 @@ void PortMgr::doTask(Consumer &consumer) | |
{ | ||
tpid = fvValue(i); | ||
} | ||
else | ||
{ | ||
field_values.emplace_back(i); | ||
} | ||
} | ||
|
||
if (!mtu.empty()) | ||
{ | ||
setPortMtu(alias, mtu); | ||
if (portOk) | ||
{ | ||
setPortMtu(alias, mtu); | ||
} | ||
else | ||
{ | ||
writeConfigToAppDb(alias, "mtu", mtu); | ||
m_retryFields.emplace_back("mtu", mtu); | ||
} | ||
SWSS_LOG_NOTICE("Configure %s MTU to %s", alias.c_str(), mtu.c_str()); | ||
} | ||
|
||
if (!admin_status.empty()) | ||
{ | ||
setPortAdminStatus(alias, admin_status == "up"); | ||
if (portOk) | ||
{ | ||
setPortAdminStatus(alias, admin_status == "up"); | ||
} | ||
else | ||
{ | ||
writeConfigToAppDb(alias, "admin_status", admin_status); | ||
m_retryFields.emplace_back("admin_status", admin_status); | ||
} | ||
SWSS_LOG_NOTICE("Configure %s admin status to %s", alias.c_str(), admin_status.c_str()); | ||
} | ||
|
||
if (!learn_mode.empty()) | ||
{ | ||
setPortLearnMode(alias, learn_mode); | ||
writeConfigToAppDb(alias, "learn_mode", learn_mode); | ||
SWSS_LOG_NOTICE("Configure %s MAC learn mode to %s", alias.c_str(), learn_mode.c_str()); | ||
} | ||
|
||
if (!tpid.empty()) | ||
{ | ||
setPortTpid(alias, tpid); | ||
writeConfigToAppDb(alias, "tpid", tpid); | ||
SWSS_LOG_NOTICE("Configure %s TPID to %s", alias.c_str(), tpid.c_str()); | ||
} | ||
|
||
for (auto &entry : field_values) | ||
{ | ||
writeConfigToAppDb(alias, fvField(entry), fvValue(entry)); | ||
SWSS_LOG_NOTICE("Configure %s %s to %s", alias.c_str(), fvField(entry).c_str(), fvValue(entry).c_str()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i'm confused by this. It seems like we are anyways writing all the fields to APP DB, so why individual writes above like mtu, tpid? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will fix this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Left a comment above to move this section to top. Also please have this as INFO logs as we don't want to keep logging during retries. |
||
} | ||
} | ||
else if (op == DEL_COMMAND) | ||
{ | ||
|
@@ -190,6 +180,30 @@ void PortMgr::doTask(Consumer &consumer) | |
m_portList.erase(alias); | ||
} | ||
|
||
it = consumer.m_toSync.erase(it); | ||
if (m_retryFields.empty()) // TODO: test delete & retry | ||
{ | ||
it = consumer.m_toSync.erase(it); | ||
} | ||
else | ||
{ | ||
/* There are some fields require retry due to set failure. This is usually because | ||
* port has not been created in kernel so that mtu and admin_status configuration | ||
* cannot be synced between kernel and ASIC for now. In this case, we put the retry fields | ||
* back to m_toSync and wait for re-visit later. | ||
*/ | ||
it->second = KeyOpFieldsValuesTuple{alias, SET_COMMAND, m_retryFields}; | ||
++it; | ||
m_retryFields.clear(); | ||
} | ||
} | ||
} | ||
|
||
bool PortMgr::writeConfigToAppDb(const std::string &alias, const std::string &field, const std::string &value) | ||
{ | ||
vector<FieldValueTuple> fvs; | ||
FieldValueTuple fv(field, value); | ||
fvs.push_back(fv); | ||
m_appPortTable.set(alias, fvs); | ||
|
||
return true; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#include <string> | ||
#include <vector> | ||
|
||
int mockCmdReturn = 0; | ||
std::string mockCmdStdcout = ""; | ||
std::vector<std::string> mockCallArgs; | ||
|
||
namespace swss { | ||
int exec(const std::string &cmd, std::string &stdout) | ||
{ | ||
mockCallArgs.push_back(cmd); | ||
stdout = mockCmdStdcout; | ||
return mockCmdReturn; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont think we need to change this? portsyncd does the
handlePortConfigFromConfigDB
. So portmgrd can still wait and keep the current flow.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @prsunny ,
handlePortConfigFromConfigDB
is only called once at init stage. It cannot handle case like dynamic port breakout. So, I suppose we need keep this change. What do you think?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok. so the logic here retries for some part of the configuration (kernel), but write to app_db in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My concern is, developer has to make sure kernel writes cannot be attempted if portOk is false which is different from the previous logic. Secondly, it keeps re-writing app_db during the wait period. We need to revisit this logic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about doing this in the
if case
and keep the original logic.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First let me confirm your solution:
This solution makes code much clear and simple. But It will repeatedly put the configuration to APP DB until the port state turns "ok".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But its the same with your current implementation as well, as you are looping through all retry attributes and writing to app_db, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, for the retry process there are 3 cases:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about this? You can use similar to 'configured' below. Apply it to APP_DB only first time in this
else
part. I would like to simplify the code. I dont think we need to worry the 2nd case (port is still not ok and mtu/admin_status changed). The new values get anyways applied once the port is ready.