Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions codegen/rust/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -729,13 +729,16 @@ impl<'a> PipelineGenerator<'a> {
});
offset += 1; // for the prefix length byte
}
MatchKind::Range => keys.push(quote! {
p4rs::extract_range_key(
keyset_data,
#offset,
#sz,
)
}),
MatchKind::Range => {
keys.push(quote! {
p4rs::extract_range_key(
keyset_data,
#offset,
#sz,
)
});
offset += sz; // range takes len + len
}
}
offset += sz;
}
Expand Down
2 changes: 2 additions & 0 deletions test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ mod table_in_egress_and_ingress;
#[cfg(test)]
mod vlan;
#[cfg(test)]
mod vlan_trunk;
#[cfg(test)]
mod vrf_router;

pub mod data;
Expand Down
67 changes: 67 additions & 0 deletions test/src/p4/vlan_trunk.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include <core.p4>
#include <softnpu.p4>
#include <headers.p4>

SoftNPU(
parse(),
ingress(),
egress()
) main;

struct headers_t {
ethernet_h ethernet;
vlan_h vlan;
}

parser parse(
packet_in pkt,
out headers_t hdr,
inout ingress_metadata_t ingress,
){
state start {
pkt.extract(hdr.ethernet);
if (hdr.ethernet.ether_type == 16w0x8100) {
transition vlan;
}
transition reject;
}

state vlan {
pkt.extract(hdr.vlan);
transition accept;
}
}

control ingress(
inout headers_t hdr,
inout ingress_metadata_t ingress,
inout egress_metadata_t egress,
) {
action forward(bit<16> port) {
egress.port = port;
}

table trunk {
key = {
hdr.vlan.vid: range;
ingress.port: exact;
}
actions = {
forward;
}
default_action = NoAction;
}

apply {
if (hdr.vlan.isValid()) {
trunk.apply();
}
}
}

control egress(
inout headers_t hdr,
inout ingress_metadata_t ingress,
inout egress_metadata_t egress,
) {
}
102 changes: 102 additions & 0 deletions test/src/vlan_trunk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use crate::softnpu::{RxFrame, SoftNpu, TxFrame};
use crate::{expect_frames, muffins};

p4_macro::use_p4!(
p4 = "test/src/p4/vlan_trunk.p4",
pipeline_name = "vlan_trunk",
);

//
// ~~~~~~~~~~
// ~ ~ * *=======*
// ~ p4 ~ | | |
// ~ ~ |---| phy 0 | ingress
// ~~~~~~~~~~ | | |
// | | *=======*
// | | *=======*
// *==========* | | |
// | | <-- ( rx ) --- |---| phy 1 | ingress
// | pipeline | | | |
// | | --- ( tx ) --> | *=======*
// *==========* | *=======*
// | | |
// |---| phy 2 | uplink
// | | |
// | *=======*
// | *=======*
// | | |
// |---| phy 3 | uplink
// | | |
// * *=======*
//

/// Return key bytes (range, exact)
fn trunk_key(begin: u16, end: u16, port: u16) -> Vec<u8> {
let mut buf = begin.to_le_bytes().to_vec();
buf.extend_from_slice(&end.to_le_bytes());
buf.extend_from_slice(&port.to_le_bytes());

buf
}

#[test]
fn vlan_trunk() -> Result<(), anyhow::Error> {
let mut pipeline = main_pipeline::new(4);

//
// add table entries
//

// port 0: [100, 199] -> port 2
let buf = trunk_key(100, 199, 0);
pipeline.add_ingress_trunk_entry("forward", &buf, &2u16.to_le_bytes(), 0);

// port 1: [100, 199] -> port 3
let buf = trunk_key(100, 199, 1);
pipeline.add_ingress_trunk_entry("forward", &buf, &3u16.to_le_bytes(), 0);

// port 0: [300, 350] -> port 3
let buf = trunk_key(300, 350, 0);
pipeline.add_ingress_trunk_entry("forward", &buf, &3u16.to_le_bytes(), 0);

//
// run program
//

let mut npu = SoftNpu::new(4, pipeline, false);
let phy0 = npu.phy(0);
let phy1 = npu.phy(1);
let phy2 = npu.phy(2);
let phy3 = npu.phy(3);

npu.run();

let et = 0;
let msg = muffins!();

// Different redirects for each port
phy0.send(&[TxFrame::newv(phy2.mac, et, msg.0, 150)])?;
expect_frames!(phy2, &[RxFrame::newv(phy0.mac, et, msg.0, 150)]);
phy1.send(&[TxFrame::newv(phy3.mac, et, msg.1, 150)])?;
expect_frames!(phy3, &[RxFrame::newv(phy1.mac, et, msg.1, 150)]);

// Range bounds are inclusive
phy0.send(&[TxFrame::newv(phy2.mac, et, msg.2, 100)])?;
expect_frames!(phy2, &[RxFrame::newv(phy0.mac, et, msg.2, 100)]);
phy0.send(&[TxFrame::newv(phy2.mac, et, msg.3, 199)])?;
expect_frames!(phy2, &[RxFrame::newv(phy0.mac, et, msg.3, 199)]);

// Testing [300, 350] block for port 0
phy0.send(&[TxFrame::newv(phy3.mac, et, msg.4, 320)])?;
expect_frames!(phy3, &[RxFrame::newv(phy0.mac, et, msg.4, 320)]);

// No match -> should drop
phy0.send(&[TxFrame::newv(phy2.mac, et, b"dropped muffin", 250)])?;
phy1.send(&[TxFrame::newv(phy3.mac, et, b"lost muffin", 320)])?;
phy2.send(&[TxFrame::newv(phy2.mac, et, b"stray muffin", 150)])?;

// Push a good one through
phy0.send(&[TxFrame::newv(phy2.mac, et, msg.5, 150)])?;
expect_frames!(phy2, &[RxFrame::newv(phy0.mac, et, msg.5, 150)]);
Ok(())
}