-
Notifications
You must be signed in to change notification settings - Fork 444
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
Add duplicate action control plane name check pass #4951
Closed
jafingerhut
wants to merge
32
commits into
p4lang:main
from
jafingerhut:add-duplicate-hierarchical-name-check-pass
Closed
Changes from 27 commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
e429c8a
Add pass to give error if duplicate hierarchical names are present
jafingerhut 39538bf
Add new source files to CMakeLists.txt
jafingerhut 98940fb
Skip new checks when compiling certain source files including: + Sour…
jafingerhut a2792ce
Skip new checks for P4-14 source files in run-bmv2-test.py
jafingerhut a553fe1
Fix lint error
jafingerhut 26f0501
Fix lint problems.
jafingerhut da456fe
Do not give errors for variable declarations with identical names
jafingerhut b683571
Limit search for duplicate names to actions, tables, or "other objects"
jafingerhut ad40fe9
Update test programs that had errors in their name annotations
jafingerhut 91166c8
Update expected output files for modified test programs
jafingerhut 9acb7e0
Move new test program with error into p4_16_errors directory
jafingerhut b133b28
Add expected output files for new test programs
jafingerhut 76bf24f
More fine-tuning to enable tests to pass
jafingerhut f7ec2fe
Fix lint error
jafingerhut 1cc8224
Fix lint error
jafingerhut 4b03eb5
Merge branch 'master' into add-duplicate-hierarchical-name-check-pass
jafingerhut 93daba5
Address some review comments
jafingerhut 66a0a0a
Rewording documentation of new pass for clarity.
jafingerhut 083db34
Merge remote-tracking branch 'upstream/main' into add-duplicate-hiera…
jafingerhut 99beb30
Enable the new pass only if P4Runtime control plane API gen is enabled
jafingerhut 2b7c58a
Merge branch 'add-duplicate-hierarchical-name-check-pass' of github.c…
jafingerhut 54007df
Merge remote-tracking branch 'upstream/main' into add-duplicate-hiera…
jafingerhut d89f214
Undo changes to Python test scripts
jafingerhut 7424db3
Undo changes to gtestp4c source
jafingerhut 55ad18f
Merge remote-tracking branch 'upstream/main' into add-duplicate-hiera…
jafingerhut 799448a
Use abseil StrCat and StrAppend instead of loop
jafingerhut 377f41a
Fix formatting with clang-format
jafingerhut d265e1c
Also catch duplicates involving top-level actions without @name annot…
jafingerhut 606300e
Merge remote-tracking branch 'upstream/main' into add-duplicate-hiera…
jafingerhut 6bcb614
Add new test program to exercise latest code changes
jafingerhut 55da2c3
Change pass name to reflect only checking action control plane names
jafingerhut d67df83
Fix lint warning, and add one more successful test program
jafingerhut File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
Copyright 2024 Cisco Systems, Inc. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
#include "duplicateHierarchicalNameCheck.h" | ||
|
||
#include "lib/log.h" | ||
|
||
namespace P4 { | ||
|
||
cstring DuplicateHierarchicalNameCheck::getName(const IR::IDeclaration *decl) { | ||
return decl->getName(); | ||
} | ||
|
||
const IR::Node *DuplicateHierarchicalNameCheck::postorder(IR::Annotation *annotation) { | ||
if (annotation->name != IR::Annotation::nameAnnotation) return annotation; | ||
|
||
cstring name = annotation->getName(); | ||
if (!name.startsWith(".")) { | ||
if (!stack.empty()) { | ||
name = absl::StrCat(absl::StrJoin(stack, ".", | ||
[](std::string *out, cstring s) { | ||
absl::StrAppend(out, s.string_view()); | ||
}), | ||
".", name.string_view()); | ||
} | ||
} | ||
// The node the annotation belongs to | ||
CHECK_NULL(getContext()->parent); | ||
auto *annotatedNode = getContext()->parent->node; | ||
CHECK_NULL(annotatedNode); | ||
// variable and struct declarations are fine if they have identical | ||
// name annotations, and such name annotations can be synthesized by | ||
// p4c before this pass. Ignore them. | ||
if (annotatedNode->is<IR::Declaration_Variable>() || annotatedNode->is<IR::Type_Struct>()) { | ||
return annotation; | ||
} | ||
bool foundDuplicate = false; | ||
auto *otherNode = annotatedNode; | ||
if (annotatedNode->is<IR::P4Table>()) { | ||
if (annotatedTables.count(name)) { | ||
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 could probably save one map lookup here, e.g.: auto [it, inserted] = annotatedTables.insert(name, annotatedNode);
if (!inserted) {
foundDuplicate = true;
otherNode = *it;
} Same for code below. Probable the code could be deduplicated as well? Something like this: auto checkForDuplicates = [&foundDuplicate, &otherNode](auto &namesToCheck, const IR::Node *annotatedNode) {
auto [it, inserted] = namesToCheck.insert(name, annotatedNode);
if (!inserted) {
foundDuplicate = true;
otherNode = *it;
}
} And then just call this lambda in each of this if (annotatedNode->is<IR::P4Table>() {
checkForDuplicates(annotatedTables, annotatedNode);
} else () ... |
||
foundDuplicate = true; | ||
otherNode = annotatedTables[name]; | ||
} else { | ||
annotatedTables[name] = annotatedNode; | ||
} | ||
} else if (annotatedNode->is<IR::P4Action>()) { | ||
if (annotatedActions.count(name)) { | ||
foundDuplicate = true; | ||
otherNode = annotatedActions[name]; | ||
} else { | ||
annotatedActions[name] = annotatedNode; | ||
} | ||
} else { | ||
if (annotatedOthers.count(name)) { | ||
foundDuplicate = true; | ||
otherNode = annotatedOthers[name]; | ||
} else { | ||
annotatedOthers[name] = annotatedNode; | ||
} | ||
} | ||
if (foundDuplicate) { | ||
error(ErrorType::ERR_DUPLICATE, "%1%: conflicting control plane name: %2%", annotatedNode, | ||
otherNode); | ||
} | ||
return annotation; | ||
} | ||
|
||
} // namespace P4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
Copyright 2024 Cisco Systems, Inc. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
#ifndef FRONTENDS_P4_DUPLICATEHIERARCHICALNAMECHECK_H_ | ||
#define FRONTENDS_P4_DUPLICATEHIERARCHICALNAMECHECK_H_ | ||
|
||
#include "ir/ir.h" | ||
#include "ir/visitor.h" | ||
|
||
namespace P4 { | ||
|
||
/** | ||
* This pass does not change anything in the IR. It only gives an | ||
* error if it finds two objects with the same hierarchical name. I | ||
* am not certain, but it might be that at this point in the front | ||
* end, the only way such a duplicate can happen is due to @name | ||
* annotations. @name annotations are definitely taken into account | ||
* in this duplicate check. | ||
* | ||
* See also the pass HierarchicalNames, on which the implementation of | ||
* this pass was based. | ||
* | ||
* This pass should be run before pass LocalizeAllActions, because | ||
* LocalizeAllActions can create actions with duplicate names, by | ||
* design, that were not created by the P4 developer. We should not | ||
* issue an error if that pass creates duplicate hierarchical names. | ||
*/ | ||
class DuplicateHierarchicalNameCheck : public Transform { | ||
std::vector<cstring> stack; | ||
/// Used for detection of conflicting control plane names among actions. | ||
string_map<const IR::Node *> annotatedActions; | ||
/// Used for detection of conflicting control plane names among tables. | ||
string_map<const IR::Node *> annotatedTables; | ||
/// Used for detection of conflicting control plane names among | ||
/// objects other than actions and tables. | ||
string_map<const IR::Node *> annotatedOthers; | ||
|
||
public: | ||
cstring getName(const IR::IDeclaration *decl); | ||
|
||
DuplicateHierarchicalNameCheck() { | ||
setName("DuplicateHierarchicalNameCheck"); | ||
visitDagOnce = false; | ||
} | ||
const IR::Node *preorder(IR::P4Parser *parser) override { | ||
stack.push_back(getName(parser)); | ||
return parser; | ||
} | ||
const IR::Node *postorder(IR::P4Parser *parser) override { | ||
stack.pop_back(); | ||
return parser; | ||
} | ||
|
||
const IR::Node *preorder(IR::P4Control *control) override { | ||
stack.push_back(getName(control)); | ||
return control; | ||
} | ||
const IR::Node *postorder(IR::P4Control *control) override { | ||
stack.pop_back(); | ||
return control; | ||
} | ||
|
||
const IR::Node *preorder(IR::P4Table *table) override { | ||
visit(table->annotations); | ||
prune(); | ||
return table; | ||
} | ||
|
||
const IR::Node *postorder(IR::Annotation *annotation) override; | ||
// Do not change name annotations on parameters | ||
const IR::Node *preorder(IR::Parameter *parameter) override { | ||
prune(); | ||
return parameter; | ||
} | ||
}; | ||
|
||
} // namespace P4 | ||
|
||
#endif /* FRONTENDS_P4_DUPLICATEHIERARCHICALNAMECHECK_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/* | ||
Copyright 2019 Cisco Systems, Inc. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
#include <core.p4> | ||
#include <v1model.p4> | ||
|
||
header h1_t { | ||
bit<8> f1; | ||
bit<8> f2; | ||
} | ||
|
||
struct headers_t { | ||
h1_t h1; | ||
} | ||
|
||
struct metadata_t { | ||
} | ||
|
||
parser parserImpl(packet_in packet, | ||
out headers_t hdr, | ||
inout metadata_t meta, | ||
inout standard_metadata_t stdmeta) | ||
{ | ||
state start { | ||
packet.extract(hdr.h1); | ||
transition accept; | ||
} | ||
} | ||
|
||
control ingressImpl(inout headers_t hdr, | ||
inout metadata_t meta, | ||
inout standard_metadata_t stdmeta) | ||
{ | ||
@name(".foo") action act1() { | ||
hdr.h1.f1 = hdr.h1.f1 >> 2; | ||
} | ||
@name(".foo") action act2() { | ||
hdr.h1.f1 = hdr.h1.f1 << 3; | ||
} | ||
table t1 { | ||
key = { hdr.h1.f1 : exact; } | ||
actions = { act1; act2; NoAction; } | ||
const default_action = NoAction; | ||
} | ||
apply { | ||
t1.apply(); | ||
} | ||
} | ||
|
||
control verifyChecksum(inout headers_t hdr, inout metadata_t meta) { | ||
apply { | ||
} | ||
} | ||
|
||
control egressImpl(inout headers_t hdr, inout metadata_t meta, inout standard_metadata_t stdmeta) { | ||
apply { | ||
} | ||
} | ||
|
||
control updateChecksum(inout headers_t hdr, inout metadata_t meta) { | ||
apply { | ||
} | ||
} | ||
|
||
control deparserImpl(packet_out packet, in headers_t hdr) { | ||
apply { | ||
} | ||
} | ||
|
||
V1Switch<headers_t, metadata_t>(parserImpl(), verifyChecksum(), ingressImpl(), egressImpl(), updateChecksum(), deparserImpl()) main; | ||
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Probably it would be better to use
absl::StrJoin
here, something like this:absl::StrCat(absl::StrJoin(stack, "."), name.string_view())
. Though this might break up as we'd need to explicitly cast fromcstring
tostring_view
, then we'd need to provide lambda toStrJoin
.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 would like to address this comment, but my C++-fu is pretty weak these days, even with your code snippet and other tips. If you or someone else has the time to provide a specific working replacement, I am happy to use it.
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.
@asl As of commit 25 on this PR, I have tried to address 2 of your 3 comments, and I think it is ready for a fresh review. If you have more specific suggestions for code changes on this commentt, which I have not addressed as mentioned in my comment above, please let me know.
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.
So, does the following work?
Yes, we have not finished the cstring-related implicit conversion saga (I need to find another continuous chunk of time to convert everything...), so we cannot make
cstring
implicitly converted tostring_view
(yet), so these.string_view()
calls are sadly necessary.After the conversion it would be much nicer:
name = absl::StrCat(absl::StrJoin(stack, "."), name);
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.
addressed in commit 26
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.
@jafingerhut After #4971 I believe we can just do
name = absl::StrCat(absl::StrJoin(stack, "."), name);
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 will try to keep an eye out for when that PR is merged in, but feel free to ping me when it is, in case I miss it.