-
Notifications
You must be signed in to change notification settings - Fork 537
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
[AclOrch] aclOrch enhancement to handle LAG port not configured case #494
Changes from 4 commits
3bf6269
bf93016
f2d3035
032e862
c6dcd31
de11d51
d32c1c1
c670c3b
3e56f49
de198bd
be203be
0499f41
879d7fe
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 |
---|---|---|
|
@@ -936,7 +936,7 @@ bool AclTable::validate() | |
{ | ||
// Control plane ACLs are handled by a separate process | ||
if (type == ACL_TABLE_UNKNOWN || type == ACL_TABLE_CTRLPLANE) return false; | ||
if (ports.empty()) return false; | ||
if (portSet.empty()) return false; | ||
return true; | ||
} | ||
|
||
|
@@ -1365,8 +1365,8 @@ bool AclRange::remove() | |
return true; | ||
} | ||
|
||
AclOrch::AclOrch(DBConnector *db, vector<string> tableNames, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch) : | ||
Orch(db, tableNames), | ||
AclOrch::AclOrch(vector<TableConnector>& connectors, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch) : | ||
Orch(connectors), | ||
m_mirrorOrch(mirrorOrch), | ||
m_neighOrch(neighOrch), | ||
m_routeOrch(routeOrch) | ||
|
@@ -1449,6 +1449,11 @@ void AclOrch::doTask(Consumer &consumer) | |
unique_lock<mutex> lock(m_countersMutex); | ||
doAclRuleTask(consumer); | ||
} | ||
else if (table_name == STATE_LAG_TABLE_NAME) | ||
{ | ||
unique_lock<mutex> lock(m_countersMutex); | ||
doAclTablePortUpdateTask(consumer); | ||
} | ||
else | ||
{ | ||
SWSS_LOG_ERROR("Invalid table %s", table_name.c_str()); | ||
|
@@ -1584,7 +1589,7 @@ void AclOrch::doAclTableTask(Consumer &consumer) | |
} | ||
else if (attr_name == TABLE_PORTS) | ||
{ | ||
bool suc = processPorts(attr_value, [&](sai_object_id_t portOid) { | ||
bool suc = processPorts(newTable, attr_value, [&](sai_object_id_t portOid) { | ||
newTable.link(portOid); | ||
}); | ||
|
||
|
@@ -1729,17 +1734,117 @@ void AclOrch::doAclRuleTask(Consumer &consumer) | |
} | ||
} | ||
|
||
bool AclOrch::processPorts(string portsList, std::function<void (sai_object_id_t)> inserter) | ||
void AclOrch::doAclTablePortUpdateTask(Consumer &consumer) | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
auto it = consumer.m_toSync.begin(); | ||
while (it != consumer.m_toSync.end()) | ||
{ | ||
KeyOpFieldsValuesTuple t = it->second; | ||
string key = kfvKey(t); | ||
size_t found = key.find('|'); | ||
string port_alias = key.substr(0, found); | ||
string op = kfvOp(t); | ||
|
||
SWSS_LOG_INFO("doAclTablePortUpdateTask: OP: %s, port_alias: %s", op.c_str(), port_alias.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.
this is debug level message. |
||
|
||
if (op == SET_COMMAND) | ||
{ | ||
for (auto itmap : m_AclTables) | ||
{ | ||
auto table = itmap.second; | ||
|
||
if (table.pendingPortSet.find(port_alias) != table.pendingPortSet.end()) | ||
{ | ||
SWSS_LOG_NOTICE("found the port: %s in ACL table: %s pending port list, bind it to ACL table.", port_alias.c_str(), table.description.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. You may want to put this as INFO instead of NOTICEs? 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. revised. |
||
|
||
bool suc = processPendingPort(table, port_alias, [&](sai_object_id_t portOid) { | ||
table.link(portOid); | ||
}); | ||
|
||
if (!suc) | ||
{ | ||
SWSS_LOG_ERROR("Failed to bind the ACL table: %s to port: %s", table.description.c_str(), port_alias.c_str()); | ||
} | ||
else | ||
{ | ||
table.pendingPortSet.erase(port_alias); | ||
SWSS_LOG_NOTICE("port: %s bound to ACL table table: %s, remove it from pending list", port_alias.c_str(), table.description.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. why is it message notice level, this debug level information. |
||
} | ||
} | ||
} | ||
} | ||
else if (op == DEL_COMMAND) | ||
{ | ||
for (auto itmap : m_AclTables) | ||
{ | ||
auto table = itmap.second; | ||
|
||
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. Can you remove the extra lines. There are few other redundant lines as well in the PR. 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. deleted. |
||
if (table.portSet.find(port_alias) != table.portSet.end()) | ||
{ | ||
table.pendingPortSet.emplace(port_alias); | ||
SWSS_LOG_WARN("Add deleted port: %s to the pending list of ACL table: %s", port_alias.c_str(), table.description.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. why is this warning level? |
||
} | ||
} | ||
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. what is the scenario here? when a port is removed, then to update the acl table? In this case, you need to unbind the port from acl table, and then put the port to pending list. You cannot simply put the port into the pending list. 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. for this one maybe need to marked as TODO here. if one port or LAG deleted, do will still have the chance to unbind it? I mean maybe some DB entries already destroyed and for SDK level all the configuration should already be cleared? |
||
} | ||
else | ||
{ | ||
SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); | ||
} | ||
|
||
it = consumer.m_toSync.erase(it); | ||
} | ||
} | ||
|
||
sai_object_id_t AclOrch::getValidPortId(string alias, Port port) | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
sai_object_id_t port_id; | ||
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. sai_object_id_t port_id == SAI_NULL_OBJECT_ID; do it here. then you do not need to assign later in the function. |
||
|
||
switch (port.m_type) | ||
{ | ||
case Port::PHY: | ||
if (port.m_lag_member_id != SAI_NULL_OBJECT_ID) | ||
{ | ||
SWSS_LOG_ERROR("Failed to process port. Bind table to LAG member %s is not allowed", alias.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.
this should be WARNING level, this is invalid configuration, we just ignore it. 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.
use "Invalid configuration" is more clear. |
||
port_id = SAI_NULL_OBJECT_ID; | ||
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.
remove this. |
||
} | ||
else | ||
{ | ||
port_id = port.m_port_id; | ||
} | ||
break; | ||
case Port::LAG: | ||
port_id = port.m_lag_id; | ||
break; | ||
case Port::VLAN: | ||
port_id = port.m_vlan_info.vlan_oid; | ||
break; | ||
default: | ||
SWSS_LOG_ERROR("Failed to process port. Incorrect port %s type %d", alias.c_str(), port.m_type); | ||
port_id = SAI_NULL_OBJECT_ID; | ||
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.
remove this |
||
break; | ||
} | ||
|
||
return port_id; | ||
} | ||
|
||
bool AclOrch::processPorts(AclTable &aclTable, string portsList, std::function<void (sai_object_id_t)> inserter) | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
sai_object_id_t port_id; | ||
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. since port_id is only used in the for loop, let's move the definition into the for loop. 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. the principle here is to define the variable when you use it. In reply to: 190211288 [](ancestors = 190211288) |
||
|
||
vector<string> strList; | ||
|
||
SWSS_LOG_INFO("Processing ACL table port list %s", portsList.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.
this is debug level message. |
||
|
||
split(portsList, strList, ','); | ||
|
||
set<string> strSet(strList.begin(), strList.end()); | ||
aclTable.portSet = strSet; | ||
|
||
if (strList.size() != strSet.size()) | ||
{ | ||
|
@@ -1758,30 +1863,51 @@ bool AclOrch::processPorts(string portsList, std::function<void (sai_object_id_t | |
Port port; | ||
if (!gPortsOrch->getPort(alias, port)) | ||
{ | ||
SWSS_LOG_ERROR("Failed to process port. Port %s doesn't exist", alias.c_str()); | ||
return false; | ||
SWSS_LOG_WARN("Port %s not configured yet, add it to ACL table %s pending list", alias.c_str(), aclTable.description.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.
why warning level? this should be info level since this is a common situation your code is handling, so this should not be warning level. |
||
aclTable.pendingPortSet.emplace(alias); | ||
continue; | ||
} | ||
|
||
switch (port.m_type) | ||
port_id = getValidPortId(alias, port); | ||
if (port_id != SAI_NULL_OBJECT_ID) | ||
{ | ||
case Port::PHY: | ||
if (port.m_lag_member_id != SAI_NULL_OBJECT_ID) | ||
{ | ||
SWSS_LOG_ERROR("Failed to process port. Bind table to LAG member %s is not allowed", alias.c_str()); | ||
return false; | ||
} | ||
inserter(port.m_port_id); | ||
break; | ||
case Port::LAG: | ||
inserter(port.m_lag_id); | ||
break; | ||
case Port::VLAN: | ||
inserter(port.m_vlan_info.vlan_oid); | ||
break; | ||
default: | ||
SWSS_LOG_ERROR("Failed to process port. Incorrect port %s type %d", alias.c_str(), port.m_type); | ||
return false; | ||
} | ||
inserter(port_id); | ||
} | ||
else | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
bool AclOrch::processPendingPort(AclTable &aclTable, string portAlias, std::function<void (sai_object_id_t)> inserter) | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
SWSS_LOG_INFO("Processing ACL table port %s", portAlias.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.
debug level. |
||
|
||
sai_object_id_t port_id; | ||
|
||
Port port; | ||
if (!gPortsOrch->getPort(portAlias, port)) | ||
{ | ||
SWSS_LOG_WARN("Port %s not configured yet, add it to ACL table %s pending list", portAlias.c_str(), aclTable.description.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.
info level. |
||
aclTable.pendingPortSet.insert(portAlias); | ||
return true; | ||
} | ||
|
||
port_id = getValidPortId(portAlias, port); | ||
|
||
if (port_id != SAI_NULL_OBJECT_ID) | ||
{ | ||
inserter(port_id); | ||
aclTable.bind(port_id); | ||
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.
move this out of processPendingPort() so that you can reuse this function. 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 have clarified with Qi before, my view is that these two functions do share some same code, but since processPorts is for "normal" flow and for processPendingPort is dedicated to receiving the notification and handle the pending port, to keep the code more straightforward, I feel like to have these two functions separated though will have some slight redundant code. |
||
} | ||
else | ||
{ | ||
return false; | ||
} | ||
|
||
return true; | ||
|
@@ -1898,18 +2024,17 @@ sai_status_t AclOrch::bindAclTable(sai_object_id_t table_oid, AclTable &aclTable | |
sai_status_t status = SAI_STATUS_SUCCESS; | ||
|
||
SWSS_LOG_INFO("%s table %s to ports", bind ? "Bind" : "Unbind", aclTable.id.c_str()); | ||
|
||
if (aclTable.portSet.empty()) | ||
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 don't think this condition will be ever true in this flow. Can you check? 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. you are correct, I removed this flow. |
||
{ | ||
SWSS_LOG_ERROR("Port list is not configured for %s table", aclTable.id.c_str()); | ||
return SAI_STATUS_FAILURE; | ||
} | ||
|
||
if (aclTable.ports.empty()) | ||
{ | ||
if (bind) | ||
{ | ||
SWSS_LOG_ERROR("Port list is not configured for %s table", aclTable.id.c_str()); | ||
return SAI_STATUS_FAILURE; | ||
} | ||
else | ||
{ | ||
return SAI_STATUS_SUCCESS; | ||
} | ||
SWSS_LOG_WARN("Binding port list is empty for %s table", aclTable.id.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. It could be a normal flow to delete aclTable which is not yet bind to any port list. We wouldn't want to log warning if it is in the delete flow. 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. condition check added. |
||
return SAI_STATUS_SUCCESS; | ||
} | ||
|
||
if (bind) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -248,6 +248,10 @@ class AclTable { | |
std::map<sai_object_id_t, sai_object_id_t> ports; | ||
// Map rule name to rule data | ||
map<string, shared_ptr<AclRule>> rules; | ||
// Set to store the ACL table port alias | ||
set<string> portSet; | ||
// Set to store the not cofigured ACL table port alias | ||
set<string> pendingPortSet; | ||
|
||
AclTable() | ||
: type(ACL_TABLE_UNKNOWN) | ||
|
@@ -294,7 +298,7 @@ inline void split(string str, Iterable& out, char delim = ' ') | |
class AclOrch : public Orch, public Observer | ||
{ | ||
public: | ||
AclOrch(DBConnector *db, vector<string> tableNames, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch); | ||
AclOrch(vector<TableConnector>& connectors, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch); | ||
~AclOrch(); | ||
void update(SubjectType, void *); | ||
|
||
|
@@ -319,6 +323,7 @@ class AclOrch : public Orch, public Observer | |
void doTask(Consumer &consumer); | ||
void doAclTableTask(Consumer &consumer); | ||
void doAclRuleTask(Consumer &consumer); | ||
void doAclTablePortUpdateTask(Consumer &consumer); | ||
void doTask(SelectableTimer &timer); | ||
|
||
static void collectCountersThread(AclOrch *pAclOrch); | ||
|
@@ -329,8 +334,10 @@ class AclOrch : public Orch, public Observer | |
|
||
bool processAclTableType(string type, acl_table_type_t &table_type); | ||
bool processAclTableStage(string stage, acl_stage_type_t &acl_stage); | ||
bool processPorts(string portsList, std::function<void (sai_object_id_t)> inserter); | ||
bool processPorts(AclTable &aclTable, string portsList, std::function<void (sai_object_id_t)> inserter); | ||
bool processPendingPort(AclTable &aclTable, string portAlias, std::function<void (sai_object_id_t)> inserter); | ||
bool validateAclTable(AclTable &aclTable); | ||
sai_object_id_t getValidPortId(string alias, Port port); | ||
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.
to reflect the true meaning, it is better to rename it to getBindPortId. Besides, it makes more sense to move this into portsyncd since it is retrieving a port property. 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. renamed and move it to portOrch. |
||
|
||
//vector <AclTable> m_AclTables; | ||
map <sai_object_id_t, AclTable> m_AclTables; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -247,11 +247,12 @@ int main(int argc, char **argv) | |
SWSS_LOG_NOTICE("Created underlay router interface ID %lx", gUnderlayIfId); | ||
|
||
/* Initialize orchestration components */ | ||
DBConnector *appl_db = new DBConnector(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); | ||
DBConnector *config_db = new DBConnector(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); | ||
DBConnector appl_db(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); | ||
DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); | ||
DBConnector state_db(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); | ||
|
||
OrchDaemon *orchDaemon = new OrchDaemon(appl_db, config_db); | ||
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 don't think we would need to have orchDaemon allocate from stack. This could still be retained as it is (allocate via 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. revised. |
||
if (!orchDaemon->init()) | ||
OrchDaemon orchDaemon(&appl_db, &config_db, &state_db); | ||
if (!orchDaemon.init()) | ||
{ | ||
SWSS_LOG_ERROR("Failed to initialize orchstration daemon"); | ||
exit(EXIT_FAILURE); | ||
|
@@ -271,7 +272,7 @@ int main(int argc, char **argv) | |
exit(EXIT_FAILURE); | ||
} | ||
|
||
orchDaemon->start(); | ||
orchDaemon.start(); | ||
} | ||
catch (char const *e) | ||
{ | ||
|
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.
are we still hardcoding this separator? We need to get rid of such hardcoded symbol.