Add tcam test, fix tcam

This commit is contained in:
2026-08-14 09:32:09 -07:00
parent 9f8654f03c
commit 4ee539a694
10 changed files with 185 additions and 8 deletions

View 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.

View File

@@ -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
View 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.

View File

@@ -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">

View File

@@ -1,2 +1,3 @@
yaml:
- "parser/sim.yaml"
- "parser/sim.yaml"
- "tcam/sim.yaml"

View File

@@ -0,0 +1,7 @@
tests:
- name: "tcam_sanity"
toplevel: "tcam"
modules:
- "tcam_sanity"
sources: "sources.list"
waves: True

View File

@@ -0,0 +1,4 @@
../../verilator.vlt
../../../src/net_core/sources.list
../../../src/common/taxi_sources.list

View 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")

View File

@@ -1,3 +1,4 @@
net_core_pkg.sv
parser.sv
parser.sv
tcam.sv

59
src/net_core/tcam.sv Normal file
View 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