Skip to content

Commit

Permalink
Fix off-by-one bug in ebpf backend mask computation (#2815)
Browse files Browse the repository at this point in the history
* Fix off-by-one bug in ebpf backend
  • Loading branch information
Mihai Budiu authored Jun 23, 2021
1 parent 138eb79 commit d9ba230
Show file tree
Hide file tree
Showing 8 changed files with 358 additions and 7 deletions.
9 changes: 3 additions & 6 deletions backends/ebpf/ebpfParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,9 @@ bool StateTranslationVisitor::preorder(const IR::ParserState* parserState) {

bool StateTranslationVisitor::preorder(const IR::SelectExpression* expression) {
hasDefault = false;
if (expression->select->components.size() != 1) {
// TODO: this does not handle correctly tuples
::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET,
"%1%: only supporting a single argument for select", expression->select);
return false;
}
BUG_CHECK(expression->select->components.size() == 1,
"%1%: tuple not eliminated in select",
expression->select);
builder->emitIndent();
builder->append("switch (");
visit(expression->select);
Expand Down
2 changes: 1 addition & 1 deletion backends/ebpf/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const IR::Node* LowerExpressions::postorder(IR::Concat* expression) {
auto cast1 = new IR::Cast(expression->right->srcInfo, resulttype, expression->right);

auto sh = new IR::Shl(cast0->srcInfo, cast0, new IR::Constant(sizeofb));
big_int m = Util::maskFromSlice(sizeofb, 0);
big_int m = Util::maskFromSlice(sizeofb-1, 0);
auto mask = new IR::Constant(expression->right->srcInfo,
IR::Type_Bits::get(sizeofresult), m, 16);
auto and0 = new IR::BAnd(expression->right->srcInfo, cast1, mask);
Expand Down
54 changes: 54 additions & 0 deletions testdata/p4_16_samples/issue2791_ebpf.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include <ebpf_model.p4>
#include <core.p4>

#include "ebpf_headers.p4"

struct Headers_t {
Ethernet_h ethernet;
IPv4_h ipv4;
}

parser prs(packet_in p, out Headers_t headers) {
state start {
p.extract(headers.ethernet);
transition select(headers.ethernet.etherType, 16w1) {
(16w0x800, 16w1) : ip;
default : reject;
}
}

state ip {
p.extract(headers.ipv4);
transition accept;
}
}

control pipe(inout Headers_t headers, out bool pass) {
action invalidate() {
headers.ipv4.setInvalid();
headers.ethernet.setInvalid();
pass = true;
}
action drop() {
pass = false;
}
table t {
key = {
headers.ipv4.srcAddr : exact;
headers.ipv4.dstAddr : exact;
headers.ethernet.dstAddr : exact;
headers.ethernet.srcAddr: exact;
}
actions = {
invalidate; drop;
}
implementation = hash_table(10);
default_action = drop;
}

apply {
t.apply();
}
}

ebpfFilter(prs(), pipe()) main;
75 changes: 75 additions & 0 deletions testdata/p4_16_samples_outputs/issue2791_ebpf-first.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <core.p4>
#include <ebpf_model.p4>

@ethernetaddress typedef bit<48> EthernetAddress;
@ipv4address typedef bit<32> IPv4Address;
header Ethernet_h {
EthernetAddress dstAddr;
EthernetAddress srcAddr;
bit<16> etherType;
}

header IPv4_h {
bit<4> version;
bit<4> ihl;
bit<8> diffserv;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
IPv4Address srcAddr;
IPv4Address dstAddr;
}

struct Headers_t {
Ethernet_h ethernet;
IPv4_h ipv4;
}

parser prs(packet_in p, out Headers_t headers) {
state start {
p.extract<Ethernet_h>(headers.ethernet);
transition select(headers.ethernet.etherType, 16w1) {
(16w0x800, 16w1): ip;
default: reject;
}
}
state ip {
p.extract<IPv4_h>(headers.ipv4);
transition accept;
}
}

control pipe(inout Headers_t headers, out bool pass) {
action invalidate() {
headers.ipv4.setInvalid();
headers.ethernet.setInvalid();
pass = true;
}
action drop() {
pass = false;
}
table t {
key = {
headers.ipv4.srcAddr : exact @name("headers.ipv4.srcAddr") ;
headers.ipv4.dstAddr : exact @name("headers.ipv4.dstAddr") ;
headers.ethernet.dstAddr: exact @name("headers.ethernet.dstAddr") ;
headers.ethernet.srcAddr: exact @name("headers.ethernet.srcAddr") ;
}
actions = {
invalidate();
drop();
}
implementation = hash_table(32w10);
default_action = drop();
}
apply {
t.apply();
}
}

ebpfFilter<Headers_t>(prs(), pipe()) main;

75 changes: 75 additions & 0 deletions testdata/p4_16_samples_outputs/issue2791_ebpf-frontend.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <core.p4>
#include <ebpf_model.p4>

@ethernetaddress typedef bit<48> EthernetAddress;
@ipv4address typedef bit<32> IPv4Address;
header Ethernet_h {
EthernetAddress dstAddr;
EthernetAddress srcAddr;
bit<16> etherType;
}

header IPv4_h {
bit<4> version;
bit<4> ihl;
bit<8> diffserv;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
IPv4Address srcAddr;
IPv4Address dstAddr;
}

struct Headers_t {
Ethernet_h ethernet;
IPv4_h ipv4;
}

parser prs(packet_in p, out Headers_t headers) {
state start {
p.extract<Ethernet_h>(headers.ethernet);
transition select(headers.ethernet.etherType, 16w1) {
(16w0x800, 16w1): ip;
default: reject;
}
}
state ip {
p.extract<IPv4_h>(headers.ipv4);
transition accept;
}
}

control pipe(inout Headers_t headers, out bool pass) {
@name("pipe.invalidate") action invalidate() {
headers.ipv4.setInvalid();
headers.ethernet.setInvalid();
pass = true;
}
@name("pipe.drop") action drop() {
pass = false;
}
@name("pipe.t") table t_0 {
key = {
headers.ipv4.srcAddr : exact @name("headers.ipv4.srcAddr") ;
headers.ipv4.dstAddr : exact @name("headers.ipv4.dstAddr") ;
headers.ethernet.dstAddr: exact @name("headers.ethernet.dstAddr") ;
headers.ethernet.srcAddr: exact @name("headers.ethernet.srcAddr") ;
}
actions = {
invalidate();
drop();
}
implementation = hash_table(32w10);
default_action = drop();
}
apply {
t_0.apply();
}
}

ebpfFilter<Headers_t>(prs(), pipe()) main;

75 changes: 75 additions & 0 deletions testdata/p4_16_samples_outputs/issue2791_ebpf-midend.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <core.p4>
#include <ebpf_model.p4>

@ethernetaddress typedef bit<48> EthernetAddress;
@ipv4address typedef bit<32> IPv4Address;
header Ethernet_h {
EthernetAddress dstAddr;
EthernetAddress srcAddr;
bit<16> etherType;
}

header IPv4_h {
bit<4> version;
bit<4> ihl;
bit<8> diffserv;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
IPv4Address srcAddr;
IPv4Address dstAddr;
}

struct Headers_t {
Ethernet_h ethernet;
IPv4_h ipv4;
}

parser prs(packet_in p, out Headers_t headers) {
state start {
p.extract<Ethernet_h>(headers.ethernet);
transition select(headers.ethernet.etherType, 16w1) {
(16w0x800, 16w1): ip;
default: reject;
}
}
state ip {
p.extract<IPv4_h>(headers.ipv4);
transition accept;
}
}

control pipe(inout Headers_t headers, out bool pass) {
@name("pipe.invalidate") action invalidate() {
headers.ipv4.setInvalid();
headers.ethernet.setInvalid();
pass = true;
}
@name("pipe.drop") action drop() {
pass = false;
}
@name("pipe.t") table t_0 {
key = {
headers.ipv4.srcAddr : exact @name("headers.ipv4.srcAddr") ;
headers.ipv4.dstAddr : exact @name("headers.ipv4.dstAddr") ;
headers.ethernet.dstAddr: exact @name("headers.ethernet.dstAddr") ;
headers.ethernet.srcAddr: exact @name("headers.ethernet.srcAddr") ;
}
actions = {
invalidate();
drop();
}
implementation = hash_table(32w10);
default_action = drop();
}
apply {
t_0.apply();
}
}

ebpfFilter<Headers_t>(prs(), pipe()) main;

75 changes: 75 additions & 0 deletions testdata/p4_16_samples_outputs/issue2791_ebpf.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <core.p4>
#include <ebpf_model.p4>

@ethernetaddress typedef bit<48> EthernetAddress;
@ipv4address typedef bit<32> IPv4Address;
header Ethernet_h {
EthernetAddress dstAddr;
EthernetAddress srcAddr;
bit<16> etherType;
}

header IPv4_h {
bit<4> version;
bit<4> ihl;
bit<8> diffserv;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
IPv4Address srcAddr;
IPv4Address dstAddr;
}

struct Headers_t {
Ethernet_h ethernet;
IPv4_h ipv4;
}

parser prs(packet_in p, out Headers_t headers) {
state start {
p.extract(headers.ethernet);
transition select(headers.ethernet.etherType, 16w1) {
(16w0x800, 16w1): ip;
default: reject;
}
}
state ip {
p.extract(headers.ipv4);
transition accept;
}
}

control pipe(inout Headers_t headers, out bool pass) {
action invalidate() {
headers.ipv4.setInvalid();
headers.ethernet.setInvalid();
pass = true;
}
action drop() {
pass = false;
}
table t {
key = {
headers.ipv4.srcAddr : exact;
headers.ipv4.dstAddr : exact;
headers.ethernet.dstAddr: exact;
headers.ethernet.srcAddr: exact;
}
actions = {
invalidate;
drop;
}
implementation = hash_table(10);
default_action = drop;
}
apply {
t.apply();
}
}

ebpfFilter(prs(), pipe()) main;

Empty file.

0 comments on commit d9ba230

Please sign in to comment.