From 2b0fb581d72aeccf208480631e9bba5a2fd2d492 Mon Sep 17 00:00:00 2001 From: Ryan Goodfellow Date: Wed, 9 Nov 2022 18:46:28 -0800 Subject: [PATCH] implement confused-endian semantics The p4 spec states that the first bit from a packet extracts into the last bit of bit-string types, this means that we go from protocol-endian to p4-endian and then back to protocol-endian on the way out. Fixes #5. --- codegen/rust/src/control.rs | 2 +- codegen/rust/src/expression.rs | 2 +- codegen/rust/src/header.rs | 23 +++++++++++++++++++-- codegen/rust/src/pipeline.rs | 4 ++-- dtrace/accepted.d | 3 +++ dtrace/dropped.d | 3 +++ dtrace/dtrace-list-probes.sh | 3 +++ dtrace/softnpu-monitor.d | 31 ++++++++++++++++++++++++++++ dtrace/softnpu-stats.d | 37 ++++++++++++++++++++++++++++++++++ lang/p4rs/src/lib.rs | 26 ++++++++++++++++-------- lang/p4rs/src/table.rs | 10 +++++++++ p4/examples/codegen/hub.p4 | 6 +++--- p4/examples/codegen/softnpu.p4 | 4 ++-- test/src/p4/router.p4 | 19 +++++++++++++---- test/src/p4/sidecar-lite.p4 | 4 ++-- test/src/softnpu.rs | 4 +++- 16 files changed, 155 insertions(+), 26 deletions(-) create mode 100644 dtrace/accepted.d create mode 100644 dtrace/dropped.d create mode 100755 dtrace/dtrace-list-probes.sh create mode 100644 dtrace/softnpu-monitor.d create mode 100644 dtrace/softnpu-stats.d diff --git a/codegen/rust/src/control.rs b/codegen/rust/src/control.rs index a1f56ec2..618b3125 100644 --- a/codegen/rust/src/control.rs +++ b/codegen/rust/src/control.rs @@ -399,7 +399,7 @@ impl<'a> ControlGenerator<'a> { let size = n as usize; action_fn_args.push(quote! {{ let mut x = bitvec![mut u8, Msb0; 0; #size]; - x.store_be(#v); + x.store_le(#v); x }}); } diff --git a/codegen/rust/src/expression.rs b/codegen/rust/src/expression.rs index 0334bece..ba4e5040 100644 --- a/codegen/rust/src/expression.rs +++ b/codegen/rust/src/expression.rs @@ -113,7 +113,7 @@ impl<'a> ExpressionGenerator<'a> { quote! { { let mut x = bitvec![mut u8, Msb0; 0; #width]; - x.store_be(#value); + x.store_le(#value); x } } diff --git a/codegen/rust/src/header.rs b/codegen/rust/src/header.rs index ceff1c0f..d39b8ec7 100644 --- a/codegen/rust/src/header.rs +++ b/codegen/rust/src/header.rs @@ -65,10 +65,24 @@ impl<'a> HeaderGenerator<'a> { }); let end = offset + size; set_statements.push(quote! { - self.#name = buf.view_bits::()[#offset..#end].to_owned() + self.#name = { + let mut b = buf.view_bits::()[#offset..#end].to_owned(); + // NOTE this barfing and then unbarfing a vec is to handle + // the p4 confused-endian data model. + let mut v = b.into_vec(); + v.reverse(); + let b = BitVec::::from_vec(v); + b + } }); to_bitvec_statements.push(quote! { - x[#offset..#end] |= &self.#name + // NOTE this barfing and then unbarfing a vec is to handle + // the p4 confused-endian data model. + let mut v = self.#name.clone().into_vec(); + v.reverse(); + let b = BitVec::::from_vec(v); + x[#offset..#end] |= &b; + }); checksum_statements.push(quote! { csum = p4rs::bitmath::add(csum.clone(), self.#name.csum()) @@ -116,6 +130,11 @@ impl<'a> HeaderGenerator<'a> { fn to_bitvec(&self) -> BitVec { let mut x = bitvec![u8, Msb0; 0u8; Self::size()]; #(#to_bitvec_statements);*; + // NOTE handling P4s confused endian byte ordering + //let mut v = x.into_vec(); + //v.reverse(); + //let x = BitVec::::from_vec(v); + //x.reverse(); x } } diff --git a/codegen/rust/src/pipeline.rs b/codegen/rust/src/pipeline.rs index a944daf2..474a255e 100644 --- a/codegen/rust/src/pipeline.rs +++ b/codegen/rust/src/pipeline.rs @@ -174,7 +174,7 @@ impl<'a> PipelineGenerator<'a> { let mut ingress_metadata = IngressMetadata{ port: { let mut x = bitvec![mut u8, Msb0; 0; 16]; - x.store_be(port); + x.store_le(port); x }, ..Default::default() @@ -227,7 +227,7 @@ impl<'a> PipelineGenerator<'a> { //println!("{}", "---".dimmed()); return None; } else { - egress_metadata.port.load_be() + egress_metadata.port.load_le() //egress_metadata.port.as_raw_slice()[0] }; diff --git a/dtrace/accepted.d b/dtrace/accepted.d new file mode 100644 index 00000000..b340bccf --- /dev/null +++ b/dtrace/accepted.d @@ -0,0 +1,3 @@ +control_accepted* { + printf("\n%s\n", copyinstr(arg0)); +} diff --git a/dtrace/dropped.d b/dtrace/dropped.d new file mode 100644 index 00000000..8d7695a9 --- /dev/null +++ b/dtrace/dropped.d @@ -0,0 +1,3 @@ +control_dropped* { + printf("\n%s\n", copyinstr(arg0)); +} diff --git a/dtrace/dtrace-list-probes.sh b/dtrace/dtrace-list-probes.sh new file mode 100755 index 00000000..0a67288c --- /dev/null +++ b/dtrace/dtrace-list-probes.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +pfexec dtrace -l -n softnpu_provider*::: diff --git a/dtrace/softnpu-monitor.d b/dtrace/softnpu-monitor.d new file mode 100644 index 00000000..f9e0a716 --- /dev/null +++ b/dtrace/softnpu-monitor.d @@ -0,0 +1,31 @@ +::parser_transition{ + printf("%s", copyinstr(arg0)); +} + +::parser_dropped { + printf("parser dropped\n"); +} + +::parser_accepted { + printf("%s", copyinstr(arg0)); +} + +::control_apply{ + printf("%s", copyinstr(arg0)); +} + +::control_dropped { + printf("control dropped\n"); +} + +::control_accepted { + printf("control accepted\n"); +} + +::control_table_hit { + printf("%s", copyinstr(arg0)); +} + +::control_table_miss { + printf("%s", copyinstr(arg0)); +} diff --git a/dtrace/softnpu-stats.d b/dtrace/softnpu-stats.d new file mode 100644 index 00000000..2ac79a17 --- /dev/null +++ b/dtrace/softnpu-stats.d @@ -0,0 +1,37 @@ +::parser_transition{ + @stats["parser transition", copyinstr(arg0)] = count(); +} + +::parser_dropped { + @stats["parser", "drop"] = count(); +} + +::parser_accepted { + @stats["parser", "accept"] = count(); +} + +::control_apply{ + @stats["control apply", copyinstr(arg0)]= count(); +} + +::control_dropped { + @stats["control", "drop"] = count(); +} + +::control_accepted { + @stats["control", "accept"] = count(); +} + +::control_table_hit { + @stats["table hit", copyinstr(arg0)] = count(); +} + +::control_table_miss { + @stats["table miss", copyinstr(arg0)] = count(); +} + +tick-10sec +{ + printa(@stats); + printf("==========================================================================================================================\n"); +} diff --git a/lang/p4rs/src/lib.rs b/lang/p4rs/src/lib.rs index 7d4afdd2..de4638d8 100644 --- a/lang/p4rs/src/lib.rs +++ b/lang/p4rs/src/lib.rs @@ -237,7 +237,8 @@ pub fn bitvec_to_biguint(bv: &BitVec) -> num::BigUint { } pub fn bitvec_to_ip6addr(bv: &BitVec) -> std::net::IpAddr { - let arr: [u8; 16] = bv.as_raw_slice().try_into().unwrap(); + let mut arr: [u8; 16] = bv.as_raw_slice().try_into().unwrap(); + arr.reverse(); std::net::IpAddr::V6(std::net::Ipv6Addr::from(arr)) } @@ -255,7 +256,7 @@ pub fn dump_bv(x: &BitVec) -> String { if x.is_empty() { "∅".into() } else { - let v: u128 = x.load_be(); + let v: u128 = x.load_le(); format!("{:x}", v) } } @@ -265,7 +266,7 @@ pub fn extract_exact_key( offset: usize, len: usize, ) -> table::Key { - table::Key::Exact(num::BigUint::from_bytes_be( + table::Key::Exact(num::BigUint::from_bytes_le( &keyset_data[offset..offset + len], )) } @@ -276,8 +277,8 @@ pub fn extract_range_key( len: usize, ) -> table::Key { table::Key::Range( - num::BigUint::from_bytes_be(&keyset_data[offset..offset + len]), - num::BigUint::from_bytes_be( + num::BigUint::from_bytes_le(&keyset_data[offset..offset + len]), + num::BigUint::from_bytes_le( &keyset_data[offset + len..offset + len + len], ), ) @@ -299,14 +300,16 @@ pub fn extract_lpm_key( let (addr, len) = match keyset_data.len() { // IPv4 5 => { - let data: [u8; 4] = + let mut data: [u8; 4] = keyset_data[offset..offset + 4].try_into().unwrap(); + data.reverse(); (IpAddr::from(data), keyset_data[offset + 4]) } // IPv6 17 => { - let data: [u8; 16] = + let mut data: [u8; 16] = keyset_data[offset..offset + 16].try_into().unwrap(); + data.reverse(); (IpAddr::from(data), keyset_data[offset + 16]) } x => { @@ -330,5 +333,12 @@ pub fn extract_bit_action_parameter( size: usize, ) -> BitVec { let size = size >> 3; - BitVec::from_slice(¶meter_data[offset..offset + size]) + let b: BitVec = + BitVec::from_slice(¶meter_data[offset..offset + size]); + + // NOTE this barfing and then unbarfing a vec is to handle the p4 + // confused-endian data model. + let mut v = b.into_vec(); + v.reverse(); + BitVec::::from_vec(v) } diff --git a/lang/p4rs/src/table.rs b/lang/p4rs/src/table.rs index 4dafcdd1..d49fb7a3 100644 --- a/lang/p4rs/src/table.rs +++ b/lang/p4rs/src/table.rs @@ -205,7 +205,17 @@ pub fn key_matches(selector: &BigUint, key: &Key) -> bool { } else { ((1u128 << p.len) - 1) << (128 - p.len) }; + let mask = mask.to_be(); let selector_v6 = selector.to_u128().unwrap(); + println!( + "{} & {} == {} & {} | {} = {}", + selector_v6, + mask, + key, + mask, + selector_v6 & mask, + key & mask + ); selector_v6 & mask == key & mask } IpAddr::V4(addr) => { diff --git a/p4/examples/codegen/hub.p4 b/p4/examples/codegen/hub.p4 index f209df4d..d941a901 100644 --- a/p4/examples/codegen/hub.p4 +++ b/p4/examples/codegen/hub.p4 @@ -39,7 +39,7 @@ control ingress( action drop() { } - action forward(bit<8> port) { + action forward(bit<16> port) { egress.port = port; } @@ -53,8 +53,8 @@ control ingress( } default_action = drop; const entries = { - 8w0 : forward(1); - 8w1 : forward(0); + 16w0 : forward(16w1); + 16w1 : forward(16w0); } } diff --git a/p4/examples/codegen/softnpu.p4 b/p4/examples/codegen/softnpu.p4 index 5b3c8895..f8afbfd6 100644 --- a/p4/examples/codegen/softnpu.p4 +++ b/p4/examples/codegen/softnpu.p4 @@ -1,11 +1,11 @@ struct IngressMetadata { - bit<8> port; + bit<16> port; bool nat; bit<16> nat_id; } struct EgressMetadata { - bit<8> port; + bit<16> port; bit<128> nexthop; bool drop; } diff --git a/test/src/p4/router.p4 b/test/src/p4/router.p4 index 663527ee..1f5d80a4 100644 --- a/test/src/p4/router.p4 +++ b/test/src/p4/router.p4 @@ -69,12 +69,15 @@ control local( const entries = { //fe80::aae1:deff:fe01:701c 128w0xfe80000000000000aae1defffe01701c: local(); + //128w0x1c7001feffdee1aa00000000000080fe: local(); //fe80::aae1:deff:fe01:701d 128w0xfe80000000000000aae1defffe01701d : local(); + //128w0x1d7001feffdee1aa00000000000080fe : local(); //fe80::aae1:deff:fe01:701e 128w0xfe80000000000000aae1defffe01701e : local(); + //128w0x1e7001feffdee1aa00000000000080fe : local(); } } @@ -84,8 +87,8 @@ control local( bit<16> ll = 16w0xff02; //TODO this is backwards should be - //if(hdr.ipv6.dst[127:112] == ll) { - if(hdr.ipv6.dst[15:0] == ll) { + if(hdr.ipv6.dst[127:112] == ll) { + //if(hdr.ipv6.dst[15:0] == ll) { is_local = true; } } @@ -116,16 +119,22 @@ control router( const entries = { // fd00:1000::/24 + //128w0x000000000000000000000000001000fd &&& + //128w0x00000000000000000000000000ffffff : 128w0xfd001000000000000000000000000000 &&& 128w0xffffff00000000000000000000000000 : forward(16w1); // fd00:2000::/24 + //128w0x000000000000000000000000002000fd &&& + //128w0x00000000000000000000000000ffffff : 128w0xfd002000000000000000000000000000 &&& 128w0xffffff00000000000000000000000000 : forward(16w2); // fd00:3000::/24 + //128w0x000000000000000000000000003000fd &&& + //128w0x00000000000000000000000000ffffff : 128w0xfd003000000000000000000000000000 &&& 128w0xffffff00000000000000000000000000 : forward(16w3); @@ -161,7 +170,8 @@ control ingress( // Decap the sidecar header. hdr.sidecar.setInvalid(); - hdr.ethernet.ether_type = 16w0x86dd; + //hdr.ethernet.ether_type = 16w0x86dd; + hdr.ethernet.ether_type = 16w0xdd86; // No more processing is required for sidecar packets, they simple // go out the sidecar port corresponding to the source scrimlet @@ -181,7 +191,8 @@ control ingress( if (local_dst) { hdr.sidecar.setValid(); - hdr.ethernet.ether_type = 16w0x0901; + //hdr.ethernet.ether_type = 16w0x0901; + hdr.ethernet.ether_type = 16w0x0109; //SC_FORWARD_TO_USERSPACE hdr.sidecar.sc_code = 8w0x01; diff --git a/test/src/p4/sidecar-lite.p4 b/test/src/p4/sidecar-lite.p4 index f2c1f51f..5808ebe3 100644 --- a/test/src/p4/sidecar-lite.p4 +++ b/test/src/p4/sidecar-lite.p4 @@ -395,8 +395,8 @@ control local( local_v6.apply(); bit<16> ll = 16w0xff02; //TODO this is backwards should be? - //if(hdr.ipv6.dst[127:112] == ll) { - if(hdr.ipv6.dst[15:0] == ll) { + if(hdr.ipv6.dst[127:112] == ll) { + //if(hdr.ipv6.dst[15:0] == ll) { is_local = true; } } diff --git a/test/src/softnpu.rs b/test/src/softnpu.rs index 4662543f..6c849a0f 100644 --- a/test/src/softnpu.rs +++ b/test/src/softnpu.rs @@ -122,7 +122,9 @@ pub fn run_pipeline< egress_count[port] += 1; } - None => {} + None => { + println!("drop"); + } } } ig.consume(frames_in).unwrap();