Skip to content

Commit

Permalink
implement confused-endian semantics
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rcgoodfellow committed Nov 10, 2022
1 parent bbefd1a commit 2b0fb58
Show file tree
Hide file tree
Showing 16 changed files with 155 additions and 26 deletions.
2 changes: 1 addition & 1 deletion codegen/rust/src/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}});
}
Expand Down
2 changes: 1 addition & 1 deletion codegen/rust/src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
23 changes: 21 additions & 2 deletions codegen/rust/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,24 @@ impl<'a> HeaderGenerator<'a> {
});
let end = offset + size;
set_statements.push(quote! {
self.#name = buf.view_bits::<Msb0>()[#offset..#end].to_owned()
self.#name = {
let mut b = buf.view_bits::<Msb0>()[#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::<u8, Msb0>::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::<u8, Msb0>::from_vec(v);
x[#offset..#end] |= &b;

});
checksum_statements.push(quote! {
csum = p4rs::bitmath::add(csum.clone(), self.#name.csum())
Expand Down Expand Up @@ -116,6 +130,11 @@ impl<'a> HeaderGenerator<'a> {
fn to_bitvec(&self) -> BitVec<u8, Msb0> {
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::<u8, Msb0>::from_vec(v);
//x.reverse();
x
}
}
Expand Down
4 changes: 2 additions & 2 deletions codegen/rust/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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]
};

Expand Down
3 changes: 3 additions & 0 deletions dtrace/accepted.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
control_accepted* {
printf("\n%s\n", copyinstr(arg0));
}
3 changes: 3 additions & 0 deletions dtrace/dropped.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
control_dropped* {
printf("\n%s\n", copyinstr(arg0));
}
3 changes: 3 additions & 0 deletions dtrace/dtrace-list-probes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

pfexec dtrace -l -n softnpu_provider*:::
31 changes: 31 additions & 0 deletions dtrace/softnpu-monitor.d
Original file line number Diff line number Diff line change
@@ -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));
}
37 changes: 37 additions & 0 deletions dtrace/softnpu-stats.d
Original file line number Diff line number Diff line change
@@ -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");
}
26 changes: 18 additions & 8 deletions lang/p4rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ pub fn bitvec_to_biguint(bv: &BitVec<u8, Msb0>) -> num::BigUint {
}

pub fn bitvec_to_ip6addr(bv: &BitVec<u8, Msb0>) -> 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))
}

Expand All @@ -255,7 +256,7 @@ pub fn dump_bv(x: &BitVec<u8, Msb0>) -> String {
if x.is_empty() {
"∅".into()
} else {
let v: u128 = x.load_be();
let v: u128 = x.load_le();
format!("{:x}", v)
}
}
Expand All @@ -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],
))
}
Expand All @@ -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],
),
)
Expand All @@ -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 => {
Expand All @@ -330,5 +333,12 @@ pub fn extract_bit_action_parameter(
size: usize,
) -> BitVec<u8, Msb0> {
let size = size >> 3;
BitVec::from_slice(&parameter_data[offset..offset + size])
let b: BitVec<u8, Msb0> =
BitVec::from_slice(&parameter_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::<u8, Msb0>::from_vec(v)
}
10 changes: 10 additions & 0 deletions lang/p4rs/src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
6 changes: 3 additions & 3 deletions p4/examples/codegen/hub.p4
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ control ingress(

action drop() { }

action forward(bit<8> port) {
action forward(bit<16> port) {
egress.port = port;
}

Expand All @@ -53,8 +53,8 @@ control ingress(
}
default_action = drop;
const entries = {
8w0 : forward(1);
8w1 : forward(0);
16w0 : forward(16w1);
16w1 : forward(16w0);
}
}

Expand Down
4 changes: 2 additions & 2 deletions p4/examples/codegen/softnpu.p4
Original file line number Diff line number Diff line change
@@ -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;
}
Expand Down
19 changes: 15 additions & 4 deletions test/src/p4/router.p4
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions test/src/p4/sidecar-lite.p4
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
4 changes: 3 additions & 1 deletion test/src/softnpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ pub fn run_pipeline<

egress_count[port] += 1;
}
None => {}
None => {
println!("drop");
}
}
}
ig.consume(frames_in).unwrap();
Expand Down

0 comments on commit 2b0fb58

Please sign in to comment.