-
Notifications
You must be signed in to change notification settings - Fork 448
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
ebpf/PSA: Support for wide fields in Register and Meter #3854
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
This commit allows to use Registers and Meters with fields wider than 64 bits.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -242,13 +242,15 @@ bool StateTranslationVisitor::preorder(const IR::SelectCase *selectCase) { | |
return false; | ||
} | ||
|
||
void StateTranslationVisitor::compileExtractField(const IR::Expression *expr, cstring field, | ||
unsigned alignment, EBPFType *type) { | ||
void StateTranslationVisitor::compileExtractField(const IR::Expression *expr, | ||
const IR::StructField *field, unsigned alignment, | ||
EBPFType *type) { | ||
unsigned widthToExtract = dynamic_cast<IHasWidth *>(type)->widthInBits(); | ||
auto program = state->parser->program; | ||
cstring msgStr; | ||
cstring fieldName = field->name.name; | ||
|
||
msgStr = Util::printf_format("Parser: extracting field %s", field); | ||
msgStr = Util::printf_format("Parser: extracting field %s", fieldName); | ||
builder->target->emitTraceMessage(builder, msgStr.c_str()); | ||
|
||
if (widthToExtract <= 64) { | ||
|
@@ -277,7 +279,7 @@ void StateTranslationVisitor::compileExtractField(const IR::Expression *expr, cs | |
unsigned shift = loadSize - alignment - widthToExtract; | ||
builder->emitIndent(); | ||
visit(expr); | ||
builder->appendFormat(".%s = (", field.c_str()); | ||
builder->appendFormat(".%s = (", fieldName.c_str()); | ||
type->emit(builder); | ||
builder->appendFormat(")((%s(%s, BYTES(%s))", helper, program->packetStartVar.c_str(), | ||
program->offsetVar.c_str()); | ||
|
@@ -293,6 +295,23 @@ void StateTranslationVisitor::compileExtractField(const IR::Expression *expr, cs | |
builder->append(")"); | ||
builder->endOfStatement(true); | ||
} else { | ||
if (program->options.arch == "psa" && widthToExtract % 8 != 0) { | ||
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. yes, in my implementation I never figured out how all this stuff should be handled. |
||
// To explain the problem in error lets assume that we have bit<68> field with value: | ||
// 0x11223344556677889 | ||
// ^ this digit will be parsed into a half of byte | ||
// Such fields are parsed into a table of bytes in network byte order, so possible | ||
// values in dataplane are (note the position of additional '0' at the end): | ||
// 0x112233445566778809 | ||
// 0x112233445566778890 | ||
// To correctly insert that padding, the length of field must be known, but tools like | ||
// nikss-ctl (and the nikss library) don't consume P4info.txt to have such knowledge. | ||
// There is also a bug in (de)parser causing that such fields aren't deparsed correctly. | ||
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. causing such fields to be deparsed incorrectly. |
||
::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, | ||
"%1%: fields wider than 64 bits must have size in multiply of 8 bits (1 byte) " | ||
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. a size multiple of 8 bits |
||
"due to ambiguous padding in the LSB byte when the condition is not met", | ||
field); | ||
} | ||
|
||
// wide values; read all bytes one by one. | ||
unsigned shift; | ||
if (alignment == 0) | ||
|
@@ -310,7 +329,7 @@ void StateTranslationVisitor::compileExtractField(const IR::Expression *expr, cs | |
for (unsigned i = 0; i < bytes; i++) { | ||
builder->emitIndent(); | ||
visit(expr); | ||
builder->appendFormat(".%s[%d] = (", field.c_str(), i); | ||
builder->appendFormat(".%s[%d] = (", fieldName.c_str(), i); | ||
bt->emit(builder); | ||
builder->appendFormat(")((%s(%s, BYTES(%s) + %d) >> %d)", helper, | ||
program->packetStartVar.c_str(), program->offsetVar.c_str(), i, | ||
|
@@ -343,13 +362,13 @@ void StateTranslationVisitor::compileExtractField(const IR::Expression *expr, cs | |
expr->to<IR::Member>()->expr->to<IR::PathExpression>()->path->name.name)) { | ||
exprStr = exprStr.replace(".", "->"); | ||
} | ||
cstring tmp = Util::printf_format("(unsigned long long) %s.%s", exprStr, field); | ||
cstring tmp = Util::printf_format("(unsigned long long) %s.%s", exprStr, fieldName); | ||
|
||
msgStr = | ||
Util::printf_format("Parser: extracted %s=0x%%llx (%u bits)", field, widthToExtract); | ||
msgStr = Util::printf_format("Parser: extracted %s=0x%%llx (%u bits)", fieldName, | ||
widthToExtract); | ||
builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, tmp.c_str()); | ||
} else { | ||
msgStr = Util::printf_format("Parser: extracted %s (%u bits)", field, widthToExtract); | ||
msgStr = Util::printf_format("Parser: extracted %s (%u bits)", fieldName, widthToExtract); | ||
builder->target->emitTraceMessage(builder, msgStr.c_str()); | ||
} | ||
|
||
|
@@ -428,7 +447,7 @@ void StateTranslationVisitor::compileExtract(const IR::Expression *destination) | |
"Only headers with fixed widths supported %1%", f); | ||
return; | ||
} | ||
compileExtractField(destination, f->name, alignment, etype); | ||
compileExtractField(destination, f, alignment, etype); | ||
alignment += et->widthInBits(); | ||
alignment %= 8; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -619,7 +619,8 @@ table caching pass `--table-caching` to the compiler. | |
|
||
We list the known bugs/limitations below. Refer to the Roadmap section for features planned in the near future. | ||
|
||
- Larger bit fields (e.g. IPv6 addresses) may not work properly. | ||
- Fields wider than 64 bits must have size multiply of 8 bits, otherwise they may have unexpected value in the LSB byte. | ||
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. multiple |
||
These fields may not work with all the externs and not all the operations on them are possible. | ||
- We noticed that `bpf_xdp_adjust_meta()` isn't implemented by some NIC drivers, so the `meta` XDP2TC mode may not work | ||
with some NICs. So far, we have verified the correct behavior with Intel 82599ES. If a NIC doesn't support the `meta` XDP2TC mode you can use `head` or `cpumap` modes. | ||
- `lookahead()` with bit fields (e.g., `bit<16>`) doesn't work. | ||
|
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.
the only place where this can happen as far I know is in rhs of shifts.
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 can't recall where exactly hit the problem with this type.
For now I am able to make this statement true with slice, like
field[127:64]
(which is translated using bit shifts).