Skip to content

Commit

Permalink
added and adapted dpi-logic as a Balboa-capability
Browse files Browse the repository at this point in the history
  • Loading branch information
Maximilian committed Nov 17, 2024
1 parent bc1fb17 commit 876305d
Show file tree
Hide file tree
Showing 26 changed files with 100,586 additions and 5 deletions.
158 changes: 158 additions & 0 deletions hw/hdl/network/rdma/intrusion_detection_data_aggregator.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Data aggregator in front of the RDMA packet processing pipeline - combines payloads of belonging streams to chunks of 512 bits each
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

module intrusion_detection_data_aggregator(
// Incoming clock and reset
input logic nclk,
input logic nresetn,

// Incoming Data Stream from the networking stack
AXI4S.s m_axis_rx,

// Outgoing decision signal for the QPN under supervision at the moment
output logic acceptable_traffic_o,

// Outgoing marker signal for the QPN under supervision at the moment
output logic[23:0] qpn_traffic_o
);

////////////////////////////////////////////////////////////////////////////////////////
//
// Definition of localparams as required for the calculations
//
///////////////////////////////////////////////////////////////////////////////////////

// Definition of the localparams for the decoded opcodes in the headers
localparam lp_opcode_write_first = 8'h06;
localparam lp_opcode_write_middle = 8'h07;
localparam lp_opcode_write_last = 8'h08;
localparam lp_opcode_write_only = 8'h0a;


///////////////////////////////////////////////////////////////////////////////////////
//
// Definition of data types
//
//////////////////////////////////////////////////////////////////////////////////////

// 512 Bit Data Type to hold the incoming words
typedef logic [511:0] DataWord;

// 24 Bit Data Type for QPNs
typedef logic [23:0] QPN;

// Combined Data Type for a QPN and its acceptance bit
typedef struct packed{
QPN chunk_qpn;
logic chunk_valid;
logic chunk_decision;
} DecisionCombinator;

// Combined Data Type for a QPN and its Last-Bit
typedef struct packed{
QPN chunk_qpn;
logic chunk_valid;
logic chunk_last;
} PipelineChunk;

// 32 Bit Data Type for the DMA length counter
typedef logic [31:0] DMALength;




/////////////////////////////////////////////////////////////////////////////////////////
//
// Definition of required registers and registerfiles
//
/////////////////////////////////////////////////////////////////////////////////////////

// Wires to extract opcode and QPN from the headers of incoming packets
logic [7:0] opcode_extractor;
QPN qpn_extractor;

// Regs for sidechannelling the ML-pipeline with QPN and last-flag over 16 pipeline stages for ML-core #1 and #2
PipelineChunk qpn_sidechannel_ml_1 [16];
PipelineChunk qpn_sidechannel_ml_2 [16];

// Final registerfile to keep track of all QPNs under supervision at the moment
DecisionCombinator decision_combinator[16];

// Reg to store the current QPN if multiple 512-bit lines for a single message are received in the beginning
QPN current_qpn;

// Reg to store if there's an ongoing transmission at the moment
logic current_transmission;


///////////////////////////////////////////////////////////////////////////////////////////
//
// Combinatorial logic
//
//////////////////////////////////////////////////////////////////////////////////////////

// ML-model is always ready to receive new input, no backpressure provided
assign m_axis_rx.tready = 1;

// Extract opcode and QPN from the headers of incoming packets for easier comparisons
assign opcode_extractor = m_axis_rx.tdata[231:224];
assign qpn_extractor = m_axis_rx.tdata[287:264];


//////////////////////////////////////////////////////////////////////////////////////////
//
// Sequential logic
//
//////////////////////////////////////////////////////////////////////////////////////////

always_ff @(posedge nclk) begin
if(!nresetn) begin

// Reset the registerfile for output combination at the end of the pipeline
for(integer reg_file_cnt = 0; reg_file_cnt < 16; reg_file_cnt++) begin
decision_combinator[reg_file_cnt].chunk_qpn <= 24'b0;
decision_combinator[reg_file_cnt].chunk_valid <= 1'b0;
decision_combinator[reg_file_cnt].chunk_decision <= 1'b0;
end

// Reset of the sidechannel pipelines
for(integer pipeline_cnt = 0; pipeline_cnt < 16; pipeline_cnt++) begin
qpn_sidechannel_ml_1[pipeline_cnt].chunk_qpn <= 24'b0;
qpn_sidechannel_ml_1[pipeline_cnt].chunk_valid <= 1'b0;
qpn_sidechannel_ml_1[pipeline_cnt].chunk_last <= 1'b0;
qpn_sidechannel_ml_2[pipeline_cnt].chunk_qpn <= 24'b0;
qpn_sidechannel_ml_2[pipeline_cnt].chunk_valid <= 1'b0;
qpn_sidechannel_ml_2[pipeline_cnt].chunk_last <= 1'b0;
end

// Reset of the current QPN
current_qpn <= 24'b0;

// Reset of the current transmission
current_transmission <= 1'b0;

end else begin
// Check for incoming traffic
if(m_axis_rx.tvalid) begin
// Check if there is already an ongoing / registered transmission to which this chunk of data belongs to
if(!ongoing_transmission) begin
// Step 1: Check if the incoming burst is a WRITE - only such are treated
if(opcode_extractor == lp_opcode_write_first || opcode_extractor == lp_opcode_write_last || opcode_extractor == lp_opcode_write_middle || opcode_extractor == lp_opcode_write_only) begin
ongoing_transmission <= 1'b1;
current_qpn <= qpn_extractor;
end

end else begin
// Incoming chunk is part of a larger, already started transmission

end
end
end

end


endmodule
239 changes: 239 additions & 0 deletions hw/hdl/network/rdma/intrusion_detection_decider.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
//////////////////////////////////////////////////////////////////////////////////
//
// Intrusion Detection Decider - receives payload and leads it to the ML-model for decision
//
//////////////////////////////////////////////////////////////////////////////////

module intrusion_detection_decider(
// Incoming clock and reset
input logic nclk,
input logic nresetn,

// Incoming stream of extracted payload
AXI4S.s s_axis_payload_rx,

// Incoming Meta-Information consisting of QPN and opcode
input logic [31:0] meta_rx_i,

// Incoming meta-interface for qp-establishment that allows to extract information whether DPI is selected or not for a specific flow
metaIntf.s s_rdma_qp_interface,

// Outgoing Meta-Interface: communicates combination of QPN & ML-Decision, valid and ack
metaIntf.m m_rdma_intrusion_decision
);

////////////////////////////////////////////////////////////////////////////////
//
// Definition of data types
//
///////////////////////////////////////////////////////////////////////////////

// 512 Bit Data Type to hold the incoming words
typedef logic [511:0] DataWord;

// Pointer to indicate fill-level of the DataWord
typedef logic [9:0] DataFillIndicator;

// 64 Bit Data Type to hold the keep signal
typedef logic [63:0] DataKeep;

// 24 Bit Signal to hold the QPN for meta-information
typedef logic [23:0] MetaQPN;

// 8 Bit Signal to hold the RDMA-Opcode
typedef logic [7:0] MetaOpcode;

// Combine QPN and Opcode to a single Meta-Datatype
typedef struct packed{
MetaQPN QPN;
MetaOpcode Opcode;
logic incomplete;
logic valid;
logic last;
logic dpi_required;
} MetaInformation;

// Decision-Word, combines QPN and decision for outgoing FIFO-port
typedef struct packed{
MetaQPN QPN; // 24 Bit
logic acceptable; // 1 Bit
} DecisionWord;


///////////////////////////////////////////////////////////////////////////////
//
// Definition of all required registers
//
//////////////////////////////////////////////////////////////////////////////

// Side-channel pipeline of meta-information besides the ML-model
MetaInformation meta_pipeline[11];

// Inverted Reset for sanity
logic rst_inverted;

// Connections to the ML-model interfaces
logic mlm_ready;
logic mlm_idle;
logic mlm_done;
logic mlm_decision_data;
logic mlm_decision_valid;
logic mlm_start;
DataWord mlm_input_word;

// Intermediate ML-decision aggregator
DecisionWord ml_decision_aggregator;

// Decision calculator
logic decision_calculator;

// Input delay
DataWord input_data_delayed;
logic input_valid_delayed;

// Definition of a 1024-bit register memory that stores whether DPI is required for a certain flow or not. Support for up to 1024 QPs.
logic dpi_required[1024];


///////////////////////////////////////////////////////////////////////////////
//
// Combinatorial logic
//
///////////////////////////////////////////////////////////////////////////////

// Reversal of the reset for my own sanity
assign rst_inverted = ~nresetn;

// Calculation of the final ACK / NAK decision
assign decision_calculator = ((meta_pipeline[10].incomplete) ? (ml_decision_aggregator.acceptable) : (ml_decision_aggregator.acceptable & (~mlm_decision_data)));

// Bit-Reversal of the input
always_comb begin
for(integer bit_index = 0; bit_index < 512; bit_index++) begin
mlm_input_word[bit_index] = s_axis_payload_rx.tdata[511-bit_index];
end
end

///////////////////////////////////////////////////////////////////////////////
//
// Integration of the ML-Decision-Model on the datapath
//
//////////////////////////////////////////////////////////////////////////////

myproject intrusion_detector_1(
.ap_clk(nclk),
.ap_rst(rst_inverted),
.ap_start(s_axis_payload_rx.tvalid),
.ap_done(mlm_done),
.ap_idle(mlm_idle),
.ap_ready(mlm_ready),
.q_dense_input_ap_vld(s_axis_payload_rx.tvalid),
.q_dense_input(mlm_input_word),
.layer12_out(mlm_decision_data),
.layer12_out_ap_vld(mlm_decision_valid)
);

// ILA around the ML
/*ila_ml_internal inst_ila_ml_internal(
.clk(nclk),
.probe0(mlm_done), // 1
.probe1(mlm_idle), // 1
.probe2(mlm_ready), // 1
.probe3(mlm_input_word), // 512
.probe4(mlm_decision_data), // 1
.probe5(mlm_decision_valid) // 1
);*/

///////////////////////////////////////////////////////////////////////////////
//
// Sequential logic of the meta-side channel
//
///////////////////////////////////////////////////////////////////////////////

always_ff @(posedge nclk) begin
if(rst_inverted) begin
// Reset of the sidechannel-pipeline
for(integer pipeline_stage = 0; pipeline_stage < 11; pipeline_stage++) begin
meta_pipeline[pipeline_stage].QPN <= 24'b0;
meta_pipeline[pipeline_stage].Opcode <= 8'b0;
meta_pipeline[pipeline_stage].incomplete <= 1'b0;
meta_pipeline[pipeline_stage].valid <= 1'b0;
meta_pipeline[pipeline_stage].last <= 1'b0;
end

// Reset of the 1024-bit register for DPI-requirements
dpi_required <= 1024'b0;

end else begin
// When a new QP is set up via the qp_interface, the DPI-bit is stored in the reg-file
dpi_required[s_rdma_qp_interface.data.qp_num] <= s_rdma_qp_interface.data.dpi_enabled;

// Activate the first stage of the pipeline if there is a valid input
if(s_axis_payload_rx.tvalid) begin
meta_pipeline[0].QPN <= meta_rx_i[31:8];
meta_pipeline[0].Opcode <= meta_rx_i[7:0];
meta_pipeline[0].incomplete <= ~(s_axis_payload_rx.tkeep == 64'hffffffffffffffff);
meta_pipeline[0].valid <= s_axis_payload_rx.tvalid;
meta_pipeline[0].last <= s_axis_payload_rx.tlast;
meta_pipeline[0].dpi_required <= dpi_required[meta_rx_i[31:8]];
end else begin
meta_pipeline[0].QPN <= 24'b0;
meta_pipeline[0].Opcode <= 8'b0;
meta_pipeline[0].incomplete <= 1'b0;
meta_pipeline[0].valid <= 1'b0;
meta_pipeline[0].last <= 1'b0;
meta_pipeline[0].dpi_required <= 1'b0;
end

// Subsequent pipeline stages
for(integer pipeline_stage = 1; pipeline_stage < 11; pipeline_stage++) begin
meta_pipeline[pipeline_stage] <= meta_pipeline[pipeline_stage-1];
end
end
end


//////////////////////////////////////////////////////////////////////////////////////
//
// Sequential logic of the ML-decision-aggregator
//
/////////////////////////////////////////////////////////////////////////////////////

always_ff @(posedge nclk) begin
if(rst_inverted) begin
// Reset the ML-decision aggregator
ml_decision_aggregator.QPN <= 24'b0;
ml_decision_aggregator.acceptable <= 1'b1;

// Reset the outgoing interface port
m_rdma_intrusion_decision.valid <= 1'b0;
m_rdma_intrusion_decision.data <= 25'b0;
end else begin
if(meta_pipeline[10].valid) begin
if(meta_pipeline[10].last) begin
// Send out ML-decision for the whole payload-chunk
m_rdma_intrusion_decision.valid <= 1'b1;
m_rdma_intrusion_decision.data[24:1] <= ml_decision_aggregator.QPN;
m_rdma_intrusion_decision.data[0] <= decision_calculator || (~meta_pipeline[10].dpi_required); // Acceptable if either the aggregated decision says it's acceptable or it's not required at all

// Reset the ml_decision_aggregator
ml_decision_aggregator.QPN <= 24'b0;
ml_decision_aggregator.acceptable <= 1'b1;
end else begin
// Reset the ML-decision interface output
m_rdma_intrusion_decision.valid <= 1'b0;
m_rdma_intrusion_decision.data[24:0] <= 25'b0;

// Concatenate the ML-output in the ml_decision_aggregator
ml_decision_aggregator.QPN <= meta_pipeline[10].QPN;
ml_decision_aggregator.acceptable <= decision_calculator;
end
end else begin
// Reset the ML-decision interface output
m_rdma_intrusion_decision.valid <= 1'b0;
m_rdma_intrusion_decision.data[24:0] <= 25'b0;
end
end
end

endmodule
Loading

0 comments on commit 876305d

Please sign in to comment.