diff --git a/docs/core/metadata_lookup.md b/docs/core/metadata_lookup.md new file mode 100644 index 0000000..1c497e1 --- /dev/null +++ b/docs/core/metadata_lookup.md @@ -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. + diff --git a/docs/core/parser.md b/docs/core/parser.md index 341ca21..35cb1fa 100644 --- a/docs/core/parser.md +++ b/docs/core/parser.md @@ -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. \ No newline at end of file +Wireguard dest port, and wireguard message type 4. diff --git a/docs/core/tcam.md b/docs/core/tcam.md new file mode 100644 index 0000000..cd86cf8 --- /dev/null +++ b/docs/core/tcam.md @@ -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. \ No newline at end of file diff --git a/docs/core/top_diagram.drawio b/docs/core/top_diagram.drawio index 2149594..6fa97b1 100644 --- a/docs/core/top_diagram.drawio +++ b/docs/core/top_diagram.drawio @@ -1,6 +1,6 @@ - + @@ -121,17 +121,16 @@ - + - - + - + diff --git a/sim/net_core/sim.yaml b/sim/net_core/sim.yaml index 993ffd1..f9b4591 100644 --- a/sim/net_core/sim.yaml +++ b/sim/net_core/sim.yaml @@ -1,2 +1,3 @@ yaml: - - "parser/sim.yaml" \ No newline at end of file + - "parser/sim.yaml" + - "tcam/sim.yaml" \ No newline at end of file diff --git a/sim/net_core/tcam/sim.yaml b/sim/net_core/tcam/sim.yaml new file mode 100644 index 0000000..7baa750 --- /dev/null +++ b/sim/net_core/tcam/sim.yaml @@ -0,0 +1,7 @@ +tests: + - name: "tcam_sanity" + toplevel: "tcam" + modules: + - "tcam_sanity" + sources: "sources.list" + waves: True \ No newline at end of file diff --git a/sim/net_core/tcam/sources.list b/sim/net_core/tcam/sources.list new file mode 100644 index 0000000..edb1589 --- /dev/null +++ b/sim/net_core/tcam/sources.list @@ -0,0 +1,4 @@ +../../verilator.vlt + +../../../src/net_core/sources.list +../../../src/common/taxi_sources.list diff --git a/sim/net_core/tcam/tcam_sanity.py b/sim/net_core/tcam/tcam_sanity.py new file mode 100644 index 0000000..e62d61d --- /dev/null +++ b/sim/net_core/tcam/tcam_sanity.py @@ -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") diff --git a/src/net_core/sources.list b/src/net_core/sources.list index 0bfffe8..157785c 100644 --- a/src/net_core/sources.list +++ b/src/net_core/sources.list @@ -1,3 +1,4 @@ net_core_pkg.sv -parser.sv \ No newline at end of file +parser.sv +tcam.sv \ No newline at end of file diff --git a/src/net_core/tcam.sv b/src/net_core/tcam.sv new file mode 100644 index 0000000..c932df9 --- /dev/null +++ b/src/net_core/tcam.sv @@ -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 \ No newline at end of file