-
Notifications
You must be signed in to change notification settings - Fork 445
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add test of v1model update_checksum implementation (#882)
* Add test of v1model update_checksum implementation It does not test the verify_checksum implementation. * Mark the new test case as XFAIL until it is supported
- Loading branch information
1 parent
faf5ec2
commit 91f9fef
Showing
4 changed files
with
262 additions
and
0 deletions.
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,212 @@ | ||
#include <core.p4> | ||
#include <v1model.p4> | ||
|
||
typedef bit<48> EthernetAddress; | ||
typedef bit<32> IPv4Address; | ||
|
||
header ethernet_t { | ||
bit<48> dstAddr; | ||
bit<48> srcAddr; | ||
bit<16> etherType; | ||
} | ||
|
||
// IPv4 header _with_ options | ||
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; | ||
varbit<320> options; | ||
} | ||
|
||
header tcp_t { | ||
bit<16> srcPort; | ||
bit<16> dstPort; | ||
bit<32> seqNo; | ||
bit<32> ackNo; | ||
bit<4> dataOffset; | ||
bit<3> res; | ||
bit<3> ecn; | ||
bit<6> ctrl; | ||
bit<16> window; | ||
bit<16> checksum; | ||
bit<16> urgentPtr; | ||
} | ||
|
||
header IPv4_up_to_ihl_only_h { | ||
bit<4> version; | ||
bit<4> ihl; | ||
} | ||
|
||
struct headers { | ||
ethernet_t ethernet; | ||
ipv4_t ipv4; | ||
tcp_t tcp; | ||
} | ||
|
||
struct mystruct1_t { | ||
bit<4> a; | ||
bit<4> b; | ||
} | ||
|
||
struct metadata { | ||
mystruct1_t mystruct1; | ||
} | ||
|
||
typedef tuple< | ||
bit<4>, | ||
bit<4>, | ||
bit<8>, | ||
varbit<56> | ||
> myTuple1; | ||
|
||
// Declare user-defined errors that may be signaled during parsing | ||
error { | ||
IPv4HeaderTooShort, | ||
IPv4IncorrectVersion, | ||
IPv4ChecksumError | ||
} | ||
|
||
parser parserI(packet_in pkt, | ||
out headers hdr, | ||
inout metadata meta, | ||
inout standard_metadata_t stdmeta) | ||
{ | ||
state start { | ||
pkt.extract(hdr.ethernet); | ||
transition select(hdr.ethernet.etherType) { | ||
0x0800: parse_ipv4; | ||
default: accept; | ||
} | ||
} | ||
state parse_ipv4 { | ||
// The 4-bit IHL field of the IPv4 base header is the number | ||
// of 32-bit words in the entire IPv4 header. It is an error | ||
// for it to be less than 5. There are only IPv4 options | ||
// present if the value is at least 6. The length of the IPv4 | ||
// options alone, without the 20-byte base header, is thus ((4 | ||
// * ihl) - 20) bytes, or 8 times that many bits. | ||
pkt.extract(hdr.ipv4, | ||
(bit<32>) | ||
(8 * | ||
(4 * (bit<9>) (pkt.lookahead<IPv4_up_to_ihl_only_h >().ihl) | ||
- 20))); | ||
verify(hdr.ipv4.version == 4w4, error.IPv4IncorrectVersion); | ||
verify(hdr.ipv4.ihl >= 4w5, error.IPv4HeaderTooShort); | ||
transition select (hdr.ipv4.protocol) { | ||
6: parse_tcp; | ||
default: accept; | ||
} | ||
} | ||
state parse_tcp { | ||
pkt.extract(hdr.tcp); | ||
transition accept; | ||
} | ||
} | ||
|
||
control cIngress(inout headers hdr, | ||
inout metadata meta, | ||
inout standard_metadata_t stdmeta) | ||
{ | ||
action foo() { | ||
hdr.tcp.srcPort = hdr.tcp.srcPort + 1; | ||
hdr.ipv4.ttl = hdr.ipv4.ttl - 1; | ||
hdr.ipv4.dstAddr = hdr.ipv4.dstAddr + 4; | ||
} | ||
table guh { | ||
key = { | ||
hdr.tcp.dstPort : exact; | ||
} | ||
actions = { foo; } | ||
default_action = foo; | ||
} | ||
apply { | ||
guh.apply(); | ||
} | ||
} | ||
|
||
control cEgress(inout headers hdr, | ||
inout metadata meta, | ||
inout standard_metadata_t stdmeta) | ||
{ | ||
apply { | ||
} | ||
} | ||
|
||
control vc(in headers hdr, | ||
inout metadata meta) | ||
{ | ||
apply { | ||
// There is code similar to this in Github repo p4lang/p4c in | ||
// file testdata/p4_16_samples/flowlet_switching-bmv2.p4 | ||
// However in that file it is only for a fixed length IPv4 | ||
// header with no options. When I try to do this, it gives an | ||
// error for having a varbit<> element in the tuple. | ||
|
||
// The compiler does not give any error when one includes a | ||
// varbit<> as an element of a tuple in a typedef, as you can | ||
// see from the definition of myTuple1 above. | ||
verify_checksum(true, | ||
{ 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, | ||
hdr.ipv4.options | ||
}, | ||
hdr.ipv4.hdrChecksum, HashAlgorithm.csum16); | ||
} | ||
} | ||
|
||
control uc(inout headers hdr, | ||
inout metadata meta) | ||
{ | ||
apply { | ||
update_checksum(true, | ||
{ 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, | ||
hdr.ipv4.options | ||
}, | ||
hdr.ipv4.hdrChecksum, HashAlgorithm.csum16); | ||
} | ||
} | ||
|
||
control DeparserI(packet_out packet, | ||
in headers hdr) | ||
{ | ||
apply { | ||
packet.emit(hdr.ethernet); | ||
packet.emit(hdr.ipv4); | ||
packet.emit(hdr.tcp); | ||
} | ||
} | ||
|
||
V1Switch<headers, metadata>(parserI(), | ||
vc(), | ||
cIngress(), | ||
cEgress(), | ||
uc(), | ||
DeparserI()) main; |
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,42 @@ | ||
# The packets in the 'packet' lines below were created using the | ||
# Python Scapy library. | ||
# | ||
# First define these Python functions: | ||
# | ||
# def str_to_hex(s): | ||
# return ''.join(map(lambda x: '%02x' % (ord(x)), s)) | ||
# | ||
# import re | ||
# def hex_to_str(hex_s): | ||
# tmp = re.sub('[ \t]', '', hex_s) | ||
# return str(bytearray.fromhex(tmp)) | ||
|
||
# The first packet was created with these Python statements: | ||
# pkt1=Ether() / IP(dst='10.1.0.1') / TCP(sport=5793, dport=80) | ||
# str_to_hex(str(pkt1)) | ||
|
||
# The packet in the first 'expect' line was created by running the P4 | ||
# program checksum1-bmv2.p4 using simple_switch, and sending in pkt1, | ||
# and using tcpdump to record the output packet. It was verified | ||
# correct by hand, and using Wireshark to very that the IPv4 header | ||
# checksum is correct. | ||
|
||
# Any of these packets can be converted back into a Scapy packet | ||
# object with Python statements like this: | ||
|
||
# s1='525400123502080027018bbc0800 45000028000100003f0665bb0a00020f0a010005 16a2005000000000000000005002200062e10000' | ||
# pkt1=Ether(hex_to_str(s1)) | ||
|
||
packet 0 525400123502080027018bbc0800 4500002800010000400664bf0a00020f0a010001 16a1005000000000000000005002200062e10000 | ||
expect 0 525400123502080027018bbc0800 45000028000100003f0665bb0a00020f0a010005 16a2005000000000000000005002200062e10000 | ||
|
||
# The second packet was created with these Python statements: | ||
# pkt2=Ether() / IP(dst='10.2.3.4', options=IPOption('\x83\x03\x10')) / TCP(sport=5501, dport=80) | ||
# str_to_hex(str(pkt2)) | ||
|
||
# This tests that the P4 code for calculating a fresh IPv4 header | ||
# checksum also works with a varbit field 'options' in the ipv4_t | ||
# header type. | ||
|
||
packet 0 525400123502080027018bbc0800 4600002c000100004006cdb30a00020f0a02030483031000 157d005000000000000000005002200061010000 | ||
expect 0 525400123502080027018bbc0800 4600002c000100003f06ceaf0a00020f0a02030883031000 157e005000000000000000005002200061010000 |