Skip to content

Commit

Permalink
Fix for issue p4lang#298
Browse files Browse the repository at this point in the history
  • Loading branch information
mbudiu-vmw committed Feb 12, 2017
1 parent 28601ab commit cc6daa1
Show file tree
Hide file tree
Showing 10 changed files with 750 additions and 16 deletions.
28 changes: 19 additions & 9 deletions backends/bmv2/jsonconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,17 @@ class ExpressionConverter : public Inspector {
// TODO: deal with references that return bool
auto result = new Util::JsonObject();

// handle errors
auto parentType = converter->typeMap->getType(expression->expr, true);
cstring fieldName = expression->member.name;
if (parentType->is<IR::Type_StructLike>()) {
auto st = parentType->to<IR::Type_StructLike>();
auto field = st->getField(expression->member);
if (field != nullptr)
// field could be a method call, i.e., isValid.
fieldName = field->externalName();
}

// handle the 'error' type
{
auto type = converter->typeMap->getType(expression, true);
if (type->is<IR::Type_Error>()) {
Expand All @@ -403,16 +413,15 @@ class ExpressionConverter : public Inspector {
auto param = enclosingParamReference(expression->expr);
if (param != nullptr) {
auto type = converter->typeMap->getType(expression, true);
auto parentType = converter->typeMap->getType(expression->expr, true);
if (param == converter->stdMetadataParameter) {
result->emplace("type", "field");
auto e = mkArrayField(result, "value");
e->append(converter->jsonMetadataParameterName);
e->append(expression->member);
e->append(fieldName);
} else {
if (type->is<IR::Type_Stack>()) {
result->emplace("type", "header_stack");
result->emplace("value", expression->member.name);
result->emplace("value", fieldName);
} else if (parentType->is<IR::Type_StructLike>() &&
(type->is<IR::Type_Bits>() || type->is<IR::Type_Boolean>())) {
auto field = parentType->to<IR::Type_StructLike>()->getField(
Expand All @@ -428,7 +437,7 @@ class ExpressionConverter : public Inspector {
// This may be wrong, but the caller will handle it properly
// (e.g., this can be a method, such as packet.lookahead)
result->emplace("type", "header");
result->emplace("value", expression->member.name);
result->emplace("value", fieldName);
}
}
} else {
Expand All @@ -446,7 +455,7 @@ class ExpressionConverter : public Inspector {
e->append(l->to<Util::JsonObject>()->get("value"));
else
e->append(l);
e->append(expression->member);
e->append(fieldName);
done = true;
}
}
Expand All @@ -459,6 +468,7 @@ class ExpressionConverter : public Inspector {
if (l->is<Util::JsonObject>()) {
auto lv = l->to<Util::JsonObject>()->get("value");
if (lv->is<Util::JsonArray>()) {
// TODO: is this case still necessary after eliminating nested structs?
// nested struct reference [ ["m", "f"], "x" ] => [ "m", "f.x" ]
auto array = lv->to<Util::JsonArray>();
BUG_CHECK(array->size() == 2, "expected 2 elements");
Expand All @@ -467,17 +477,17 @@ class ExpressionConverter : public Inspector {
BUG_CHECK(second->is<Util::JsonValue>(), "expected a value");
e->append(first);
cstring nestedField = second->to<Util::JsonValue>()->getString();
nestedField += "." + expression->member.name;
nestedField += "." + fieldName;
e->append(nestedField);
} else if (lv->is<Util::JsonValue>()) {
e->append(lv);
e->append(expression->member.name);
e->append(fieldName);
} else {
BUG("%1%: Unexpected json", lv);
}
} else {
e->append(l);
e->append(expression->member.name);
e->append(fieldName);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion frontends/p4/frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ FrontEnd::run(const CompilerOptions &options, const IR::P4Program* program) {
new BindTypeVariables(&typeMap),
// Another round of constant folding, using type information.
new ClearTypeMap(&typeMap),
new TableKeyNames(),
new TableKeyNames(&refMap, &typeMap),
new ConstantFolding(&refMap, &typeMap),
new StrengthReduction(),
new SimplifyControlFlow(&refMap, &typeMap),
Expand Down
18 changes: 14 additions & 4 deletions frontends/p4/tableKeyNames.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ namespace P4 {

class KeyNameGenerator : public Inspector {
std::map<const IR::Expression*, cstring> name;
const TypeMap* typeMap;

public:
KeyNameGenerator() { setName("KeyNameGenerator"); }
explicit KeyNameGenerator(const TypeMap* typeMap) : typeMap(typeMap)
{ setName("KeyNameGenerator"); }

void error(const IR::Expression* expression) {
::error("%1%: Complex key expression requires a @name annotation", expression);
Expand All @@ -35,8 +37,16 @@ class KeyNameGenerator : public Inspector {
}

void postorder(const IR::Member* expression) override {
auto type = typeMap->getType(expression->expr, true);
cstring fname = expression->member.name;
if (type->is<IR::Type_StructLike>()) {
auto st = type->to<IR::Type_StructLike>();
auto field = st->getField(expression->member);
if (field != nullptr)
fname = field->externalName();
}
if (cstring n = getName(expression->expr))
name.emplace(expression, n + "." + expression->member);
name.emplace(expression, n + "." + fname);
}

void postorder(const IR::ArrayIndex* expression) override {
Expand Down Expand Up @@ -77,12 +87,12 @@ class KeyNameGenerator : public Inspector {
}
};

const IR::Node* TableKeyNames::postorder(IR::KeyElement* keyElement) {
const IR::Node* DoTableKeyNames::postorder(IR::KeyElement* keyElement) {
LOG3("Visiting " << getOriginal());
if (keyElement->annotations->getSingle(IR::Annotation::nameAnnotation) != nullptr)
// already present: no changes
return keyElement;
KeyNameGenerator kng;
KeyNameGenerator kng(typeMap);;
(void)keyElement->expression->apply(kng);
cstring name = kng.getName(keyElement->expression);

Expand Down
15 changes: 13 additions & 2 deletions frontends/p4/tableKeyNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,23 @@ namespace P4 {
// if the expression is "simple" enough. If the expression is not
// simple the compiler will give an error. Simple expressions are
// PathExpression, ArrayIndex, Member, .isValid(), Constant, Slice
class TableKeyNames : public Transform {
class DoTableKeyNames : public Transform {
const TypeMap* typeMap;
public:
TableKeyNames() { setName("TableKeyNames"); }
DoTableKeyNames(const TypeMap* typeMap) :typeMap(typeMap)
{ CHECK_NULL(typeMap); setName("DoTableKeyNames"); }
const IR::Node* postorder(IR::KeyElement* keyElement) override;
};

class TableKeyNames : public PassManager {
public:
TableKeyNames(ReferenceMap* refMap, TypeMap* typeMap) {
passes.push_back(new TypeChecking(refMap, typeMap));
passes.push_back(new DoTableKeyNames(typeMap));
setName("TableKeyNames");
}
};

} // namespace P4

#endif /* _FRONTENDS_P4_TABLEKEYNAMES_H_ */
196 changes: 196 additions & 0 deletions testdata/p4_16_samples/issue298-bmv2.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*
Copyright 2017 VMware, 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>

typedef bit<48> EthernetAddress;
typedef bit<32> IPv4Address;
typedef bit<4> PortId;

const PortId DROP_PORT = 0xF;

header ethernet_t {
EthernetAddress dstAddr;
EthernetAddress srcAddr;
bit<16> etherType;
}

header ipv4_t {
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;
}

header udp_t {
bit<16> srcPort;
bit<16> dstPort;
bit<16> length_;
bit<16> checksum;
}


#define MSGTYPE_SIZE 16
#define INSTANCE_SIZE 32
#define ROUND_SIZE 16
#define INSTANCE_COUNT 65536


header myhdr_t {
bit<MSGTYPE_SIZE> msgtype;
bit<INSTANCE_SIZE> inst;
bit<ROUND_SIZE> rnd;
}

struct headers {
@name("ethernet")
ethernet_t ethernet;
@name("ipv4")
ipv4_t ipv4;
@name("udp")
udp_t udp;
@name("myhdr")
myhdr_t myhdr;
}

struct ingress_metadata_t {
bit<ROUND_SIZE> round;
bit<1> set_drop;
}

struct metadata {
@name("ingress_metadata")
ingress_metadata_t local_metadata;
}

#define ETHERTYPE_IPV4 16w0x0800
#define UDP_PROTOCOL 8w0x11
#define myhdr_PROTOCOL 16w0x8888

parser TopParser(packet_in b, out headers p, inout metadata meta, inout standard_metadata_t standard_metadata) {
state start {
transition parse_ethernet;
}

state parse_ethernet {
b.extract(p.ethernet);
transition select(p.ethernet.etherType) {
ETHERTYPE_IPV4 : parse_ipv4;
}
}

state parse_ipv4 {
b.extract(p.ipv4);
transition select(p.ipv4.protocol) {
UDP_PROTOCOL : parse_udp;
default : accept;
}
}

state parse_udp {
b.extract(p.udp);
transition select(p.udp.dstPort) {
myhdr_PROTOCOL : parse_myhdr;
default : accept;
}
}

state parse_myhdr {
b.extract(p.myhdr);
transition accept;
}
}

control TopDeparser(packet_out packet, in headers hdr) {
apply {
packet.emit(hdr.ethernet);
packet.emit(hdr.ipv4);
packet.emit(hdr.udp);
packet.emit(hdr.myhdr);
}
}

control verifyChecksum(in headers hdr, inout metadata meta) {
Checksum16() ipv4_checksum;
apply {
if (hdr.ipv4.hdrChecksum == ipv4_checksum.get({hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }))
mark_to_drop();
}
}

control computeChecksum(inout headers hdr, inout metadata meta) {
Checksum16() ipv4_checksum;
apply {
hdr.ipv4.hdrChecksum = ipv4_checksum.get({hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr });
}
}

control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) {

action _drop() {
mark_to_drop();
}

table drop_tbl {
key = { meta.local_metadata.set_drop : exact; }
actions = {
_drop;
NoAction;
}
size = 2;
default_action = NoAction();
}

apply {
drop_tbl.apply();
}
}

control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) {
register<bit<ROUND_SIZE>>(INSTANCE_COUNT) registerRound;

action read_round() {
registerRound.read(meta.local_metadata.round, hdr.myhdr.inst);
}

table round_tbl {
key = {}
actions = {
read_round;
}
size = 8;
default_action = read_round;
}

apply {
if (hdr.ipv4.isValid()) {
if (hdr.myhdr.isValid()) {
round_tbl.apply();
}
}
}
}

V1Switch(TopParser(), verifyChecksum(), ingress(), egress(), computeChecksum(), TopDeparser()) main;
Empty file.
Loading

0 comments on commit cc6daa1

Please sign in to comment.