diff --git a/codegen/rust/src/header.rs b/codegen/rust/src/header.rs index 0bbe3c99..448de5b0 100644 --- a/codegen/rust/src/header.rs +++ b/codegen/rust/src/header.rs @@ -71,10 +71,12 @@ impl<'a> HeaderGenerator<'a> { // the p4 confused-endian data model. let mut v = b.into_vec(); v.reverse(); - let mut b = BitVec::::from_vec(v); - if (#end-#offset) < 8 { - b.shift_left(#offset % 8); + if ((#end-#offset) % 8) != 0 { + if let Some(x) = v.iter_mut().last() { + *x <<= (#offset % 8); + } } + let mut b = BitVec::::from_vec(v); b.resize(#end-#offset, false); b } diff --git a/test/src/lib.rs b/test/src/lib.rs index 06e918ea..253295cd 100644 --- a/test/src/lib.rs +++ b/test/src/lib.rs @@ -20,6 +20,8 @@ mod mac_rewrite; mod range; #[cfg(test)] mod table_in_egress_and_ingress; +#[cfg(test)] +mod vlan; pub mod data; pub mod packet; diff --git a/test/src/p4/vlan_header.p4 b/test/src/p4/vlan_header.p4 new file mode 100644 index 00000000..8f2fc408 --- /dev/null +++ b/test/src/p4/vlan_header.p4 @@ -0,0 +1,43 @@ +header ethernet_h { + bit<48> dst; + bit<48> src; + bit<16> ether_type; +} + +header vlan_h { + bit<3> pcp; + bit<1> dei; + bit<12> vid; + bit<16> ether_type; +} + +header sidecar_h { + bit<8> sc_code; + bit<8> sc_pad; + bit<16> sc_ingress; + bit<16> sc_egress; + bit<16> sc_ether_type; + bit<128> sc_payload; +} + +header ipv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> total_len; + bit<16> identification; + bit<3> flags; + bit<13> frag_offset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdr_checksum; + bit<32> src; + bit<32> dst; +} + +struct headers_t { + ethernet_h ethernet; + vlan_h vlan; + sidecar_h sidecar; + ipv4_h ipv4; +} diff --git a/test/src/vlan.rs b/test/src/vlan.rs new file mode 100644 index 00000000..b804b9fc --- /dev/null +++ b/test/src/vlan.rs @@ -0,0 +1,22 @@ +p4_macro::use_p4!("test/src/p4/vlan_header.p4"); + +#[test] +fn test_vlan_parse() -> anyhow::Result<()> { + let mut data = [0u8; 256]; + data[0] = 0x0; + data[1] = 0x47; + let mut pkt = vlan_h::new(); + pkt.set(&data).unwrap(); + let vid: u16 = pkt.vid.to_owned().load_le(); + assert_eq!(vid, 0x47); + + let mut data = [0u8; 256]; + data[0] = 0x77; + data[1] = 0x47; + let mut pkt = vlan_h::new(); + pkt.set(&data).unwrap(); + let vid: u16 = pkt.vid.to_owned().load_le(); + assert_eq!(vid, 0x747); + + Ok(()) +}