Add tcam test, fix tcam
This commit is contained in:
20
docs/core/metadata_lookup.md
Normal file
20
docs/core/metadata_lookup.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Metadata Lookup
|
||||
|
||||
Metadata lookup is responsible for determining what operations to do to the
|
||||
packet, what data to append to the packet (ip address, port). It also stores
|
||||
the keys and counters for crypto, and increments the counters in the case of
|
||||
packet that are encrypted.
|
||||
|
||||
The packet types we care about are:
|
||||
|
||||
1. Incoming IP frames to be encrypted, check dest_ip
|
||||
2. Incoming Wireguard frames to be decrypted, check source ip, wireguard type
|
||||
3. Incoming Wireguard frames to go to cpu, check source ip, wireguard type,
|
||||
|
||||
So really we need to check the IP addreses, and the wireguard info. We can use a TCAM to check
|
||||
if they match. for the wireguard packets, we want a different rule for the type 4 packets than
|
||||
the other types, since all other types go to cpu and type 4 gets decrypted.
|
||||
|
||||
So in terms of searching, we need to search the source/dest ip, and wireguard type. Since 0 is
|
||||
an invalid wireguard type, we know that if the type is 0 then it was not a wireguard packet.
|
||||
|
||||
@@ -52,4 +52,4 @@ be 0. The outputs will either match the metadata rules or not, so we don't care
|
||||
block.
|
||||
|
||||
The pattern specifically is IPv4 Ethertype (No VLAN), IHL 5 (No options), UDP protocol,
|
||||
Wireguard dest port, and wireguard message type 4.
|
||||
Wireguard dest port, and wireguard message type 4.
|
||||
|
||||
21
docs/core/tcam.md
Normal file
21
docs/core/tcam.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# TCAM
|
||||
|
||||
we need to design a tcam for this though. the tcam does not need to store any data, the result
|
||||
we are looking for is a simple present or not present, we will look up the result in a separate
|
||||
memory after the fact.
|
||||
|
||||
We need to program the value and the mask. But really, we program value_x and value_y. X is the
|
||||
inverse of the data, and y is the data.
|
||||
|
||||
There are two comparisons, both need to be 0 for there to be a match
|
||||
|
||||
`&~((d & x) | (~d & y)`
|
||||
|
||||
to get the match for all bits, we and them all together.
|
||||
|
||||
So there are two interfaces, the programming interface and the search interface.
|
||||
|
||||
programming interface consists of read data, write data, read enable, write enable, and addresss.
|
||||
|
||||
The search interface consists of search data, and the outputs are valid, match and
|
||||
key.
|
||||
@@ -1,6 +1,6 @@
|
||||
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/29.3.0 Chrome/140.0.7339.249 Electron/38.7.2 Safari/537.36">
|
||||
<diagram name="Page-1" id="72PB9eZoycvEeqRRA-Ze">
|
||||
<mxGraphModel dx="1284" dy="863" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<mxGraphModel dx="790" dy="531" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
@@ -121,17 +121,16 @@
|
||||
<mxPoint x="-5" y="-10" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="7ZK-1vDvfmA7mbs2EBc0-75" edge="1" parent="1" source="7ZK-1vDvfmA7mbs2EBc0-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="7ZK-1vDvfmA7mbs2EBc0-74">
|
||||
<mxCell id="7ZK-1vDvfmA7mbs2EBc0-75" edge="1" parent="1" source="7ZK-1vDvfmA7mbs2EBc0-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="7ZK-1vDvfmA7mbs2EBc0-74">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="300" y="350" />
|
||||
<mxPoint x="300" y="460" />
|
||||
<mxPoint x="480" y="460" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="7ZK-1vDvfmA7mbs2EBc0-76" connectable="0" parent="7ZK-1vDvfmA7mbs2EBc0-75" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="tag" vertex="1">
|
||||
<mxGeometry relative="1" x="-0.2126" as="geometry">
|
||||
<mxPoint x="166" y="-10" as="offset" />
|
||||
<mxPoint x="95" y="-10" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="7ZK-1vDvfmA7mbs2EBc0-18" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="Parser" vertex="1">
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
yaml:
|
||||
- "parser/sim.yaml"
|
||||
- "parser/sim.yaml"
|
||||
- "tcam/sim.yaml"
|
||||
7
sim/net_core/tcam/sim.yaml
Normal file
7
sim/net_core/tcam/sim.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
tests:
|
||||
- name: "tcam_sanity"
|
||||
toplevel: "tcam"
|
||||
modules:
|
||||
- "tcam_sanity"
|
||||
sources: "sources.list"
|
||||
waves: True
|
||||
4
sim/net_core/tcam/sources.list
Normal file
4
sim/net_core/tcam/sources.list
Normal file
@@ -0,0 +1,4 @@
|
||||
../../verilator.vlt
|
||||
|
||||
../../../src/net_core/sources.list
|
||||
../../../src/common/taxi_sources.list
|
||||
65
sim/net_core/tcam/tcam_sanity.py
Normal file
65
sim/net_core/tcam/tcam_sanity.py
Normal file
@@ -0,0 +1,65 @@
|
||||
import cocotb
|
||||
|
||||
import logging
|
||||
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import Timer, RisingEdge, FallingEdge
|
||||
|
||||
import random
|
||||
|
||||
CLK_PERIOD = 20
|
||||
|
||||
|
||||
class TB:
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.log = logging.getLogger("cocotb.tb")
|
||||
self.log.setLevel(logging.INFO)
|
||||
|
||||
cocotb.start_soon(Clock(self.dut.i_clk, CLK_PERIOD, unit="ns").start())
|
||||
|
||||
|
||||
async def program_line(self, addr: int, value: int):
|
||||
self.dut.i_program_addr.value = addr
|
||||
self.dut.i_program_data.value = value & (2**32-1)
|
||||
self.dut.i_program_we.value = 1
|
||||
await RisingEdge(self.dut.i_clk)
|
||||
self.dut.i_program_addr.value = 0
|
||||
self.dut.i_program_data.value = 0
|
||||
self.dut.i_program_we.value = 0
|
||||
|
||||
async def send_data(self, value: int):
|
||||
self.dut.i_search_data.value = value & (2**32-1)
|
||||
self.dut.i_search_valid.value = 1
|
||||
await RisingEdge(self.dut.i_clk)
|
||||
self.dut.i_search_data.value = 0
|
||||
self.dut.i_search_valid.value = 0
|
||||
|
||||
@cocotb.test
|
||||
async def test_sanity(dut):
|
||||
tb = TB(dut)
|
||||
|
||||
for _ in range(4):
|
||||
await RisingEdge(tb.dut.i_clk)
|
||||
|
||||
for i in range(32):
|
||||
await tb.program_line(i, 0xffffffff)
|
||||
await tb.program_line(i+32, 0xffffffff)
|
||||
|
||||
for _ in range(4):
|
||||
await RisingEdge(tb.dut.i_clk)
|
||||
|
||||
await tb.program_line(0, 0x5432edc0)
|
||||
await tb.program_line(32, 0xabcd1230)
|
||||
|
||||
await tb.program_line(1, ~0xabcd1234)
|
||||
await tb.program_line(33, 0xabcd1234)
|
||||
|
||||
for _ in range(4):
|
||||
await RisingEdge(tb.dut.i_clk)
|
||||
|
||||
await tb.send_data(0xabcd1234)
|
||||
await tb.send_data(0xabcd1235)
|
||||
|
||||
await Timer(1, "us")
|
||||
@@ -1,3 +1,4 @@
|
||||
net_core_pkg.sv
|
||||
|
||||
parser.sv
|
||||
parser.sv
|
||||
tcam.sv
|
||||
59
src/net_core/tcam.sv
Normal file
59
src/net_core/tcam.sv
Normal file
@@ -0,0 +1,59 @@
|
||||
module tcam #(
|
||||
parameter WIDTH = 32,
|
||||
parameter DEPTH_LOG2 = 5
|
||||
) (
|
||||
input logic i_clk,
|
||||
|
||||
// 1 bit longer to account for x and y
|
||||
input logic [DEPTH_LOG2:0] i_program_addr,
|
||||
input logic i_program_we,
|
||||
input logic [WIDTH-1:0] i_program_data,
|
||||
input logic i_program_re,
|
||||
output logic [WIDTH-1:0] o_program_data,
|
||||
|
||||
input logic [WIDTH-1:0] i_search_data,
|
||||
input logic i_search_valid,
|
||||
output logic [DEPTH_LOG2-1:0] o_search_index,
|
||||
output logic o_search_valid,
|
||||
output logic o_search_match
|
||||
);
|
||||
|
||||
localparam DEPTH = 1 << DEPTH_LOG2;
|
||||
|
||||
logic [WIDTH-1:0] data_x [DEPTH];
|
||||
logic [WIDTH-1:0] data_y [DEPTH];
|
||||
|
||||
// programming interface
|
||||
always_ff @(posedge i_clk) begin
|
||||
if (i_program_we) begin
|
||||
if (i_program_addr[DEPTH_LOG2]) begin
|
||||
data_y[i_program_addr[DEPTH_LOG2-1:0]] <= i_program_data;
|
||||
end else begin
|
||||
data_x[i_program_addr[DEPTH_LOG2-1:0]] <= i_program_data;
|
||||
end
|
||||
end
|
||||
|
||||
if (i_program_re) begin
|
||||
if (i_program_addr[DEPTH_LOG2]) begin
|
||||
o_program_data <= data_y[i_program_addr[DEPTH_LOG2-1:0]];
|
||||
end else begin
|
||||
o_program_data <= data_x[i_program_addr[DEPTH_LOG2-1:0]];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge i_clk) begin
|
||||
o_search_valid <= i_search_valid;
|
||||
|
||||
o_search_index <= '0;
|
||||
o_search_match <= '0;
|
||||
|
||||
for (int i = 0; i < DEPTH; i++) begin
|
||||
if (&~((i_search_data & data_x[i[DEPTH_LOG2-1:0]]) | (~i_search_data & data_y[i[DEPTH_LOG2-1:0]]))) begin
|
||||
o_search_match <= 1;
|
||||
o_search_index <= i[DEPTH_LOG2-1:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user