-
Notifications
You must be signed in to change notification settings - Fork 449
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 support for ternary match kind to eBPF backend #3256
Conversation
Co-authored-by: Mateusz Kossakowski <mateusz.kossakowski@orange.com> Co-authored-by: Jan Palimąka <jan.palimaka@orange.com>
|
||
An `lpm` table is implemented using the BPF `LPM_TRIE` map. A P4 table is considered an `lpm` table if it contains a single `lpm` field and no `ternary` fields. | ||
The PSA-eBPF compiler generates a BPF `LPM_TRIE` map instance for each P4 table instance. The hash map key as a concatenation of P4 match fields translated to eBPF representation. | ||
Moreover, the PSA-eBPF compiler shuffles the match fields and places the `lpm` field in the last position. Each `apply()` operation is translated into a lookup to the `LPM_TRIE` map. |
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.
This may be a problem since the control-plane has to know this. For example, if you plan p4Runtime support, I am not sure it will be easy. (Perhaps it is, just shuffle the data from the control-plane in the same way).
Wouldn't it be simpler to just require users to put the field last and reject other programs?
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.
Shuffling the data from control plane shouldn't be a problem, since we have P4Info. IDK we might want to revisit that later (once we start integrating PSA-eBPF with a P4Runtime stack), but I'd keep it as is, for now.
- the `<TBL-NAME>_prefixes` map is a BPF hash map that stores all unique ternary masks. The ternary masks are created based on the runtime table entries that are installed by a user. | ||
- the `<TBL-NAME>_tuples_map` map is a BPF array map of maps that stores all "tuples". A single tuple is a BPF hash map that stores all flow rules with the same ternary mask. | ||
|
||
Note that the `psabpf-ctl table add` CLI command greatly simplifies the process of adding/removing flow rules to ternary tables. |
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 assume that this provides the illusion of a ternary table to the control-plane. This will be a consideration if you do p4Runtime too.
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.
Basically, psabpf
provides not only a CLI tool, but also a C library that we plan to use, when it comes to the P4Runtime integration. So, the psabpf C API hides the underlying complexity.
backends/ebpf/psa/README.md
Outdated
For each `apply()` operation, the PSA-eBPF compiler generates the piece of code performing lookup to the above maps. The lookup code iterates over the `<TBL-NAME>_prefixes` map to | ||
retrieve a ternary mask. Next, the lookup key (a concatenation of match keys) is masked with the obtained ternary mask and lookup to a corresponding tuple map is performed. | ||
If a match is found, the best match with the highest priority is saved, and the algorithm continues to examine other tuples. If an entry with a higher priority is found in other tuples, | ||
the best match is overwritten. The algorithm exists when there is no more tuples to examine left. |
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 more tuples are left.
backends/ebpf/psa/README.md
Outdated
|
||
For each `apply()` operation, the PSA-eBPF compiler generates the piece of code performing lookup to the above maps. The lookup code iterates over the `<TBL-NAME>_prefixes` map to | ||
retrieve a ternary mask. Next, the lookup key (a concatenation of match keys) is masked with the obtained ternary mask and lookup to a corresponding tuple map is performed. | ||
If a match is found, the best match with the highest priority is saved, and the algorithm continues to examine other tuples. If an entry with a higher priority is found in other tuples, |
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.
remove "in other tuples"?
backends/ebpf/psa/README.md
Outdated
If a match is found, the best match with the highest priority is saved, and the algorithm continues to examine other tuples. If an entry with a higher priority is found in other tuples, | ||
the best match is overwritten. The algorithm exists when there is no more tuples to examine left. | ||
|
||
The snippet below shows the example of C code generated by the PSA-eBPF compiler for a lookup into a ternary table. The steps are explained below. |
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.
remove "example of"
if (val && val->has_next != 0) { | ||
struct ingress_tbl_ternary_1_key_mask next = val->next_tuple_mask; | ||
#pragma clang loop unroll(disable) | ||
for (int i = 0; i < MAX_INGRESS_TBL_TERNARY_1_KEY_MASKS; i++) { // (1) |
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.
This works because the upper bound is a constant?
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, exactly.
backends/ebpf/psa/README.md
Outdated
4. Next, a lookup to the inner BPF map (a tuple map) is performed. The returned value stores the action ID, action params and priority. | ||
5. The priority of an obtained value is compared with a current "best match" entry. An entry that is returned from the ternary classification is the one with the highest priority among different tuples. | ||
|
||
Note that the TSS algorithm has linear O(n) packet classification complexity, but the lookup cost depends on the number of unique ternary masks and does not depend on the number of total entries. |
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.
Just say what n is.
# flow rules for 'tbl_ternary_0' | ||
# 1. ipv4.srcAddr=1.2.3.4/0xffffff00 => action 0 priority 1 | ||
# 2. ipv4.srcAddr=1.2.3.4/0xffff00ff => action 1 priority 10 | ||
self.table_add(table="ingress_tbl_ternary_0", keys=["1.2.3.4^0xffffff00"], action=0, priority=1) |
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 ^ is the mask operator?
Would it make sense to use &&& to resemble P4 more?
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.
Yeah, the problem is that &&& collides with the bash "&". Since psabpf-ctl is primarily a CLI tool (the Python functions just wrap it), we found it better to use "^" as the mask operator.
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.
Is this documented someplace visible?
@mbudiu-vmw I've addressed your comments |
Co-authored-by: Mateusz Kossakowski mateusz.kossakowski@orange.com
Co-authored-by: Jan Palimąka jan.palimaka@orange.com