/net2axis

Verilog network module. Models network traffic from pcap to AXI-Stream

Primary LanguageVerilogISC LicenseISC

Net2axis

Verilog network module for simulation. Models network traffic from pcap to AXI-Stream

Table of Contents

Introduction

Net2axis is a simulation-only Verilog module that generates Master AXI-Stream transactions from network packets described in packet capture files (PCAP). It provides a convenient way for a user to develop his/hers network hardware design by simulating a Network/Ethernet/MAC/Internet Protocol IP cores.

Why use net2axis ?

Development of a network design in hardware can be very troublesome. Even when designing over simple protocols, ARP for instance, creation of a consise testbench can take time.

As FPGA vendors are increasily adopting AXI4 protocol, such as Xilinx, their proprietary network-related IPs are using AXI-Stream channels send network traffic data to (your) custom IP module. Net2axis can be used to model those proprietary IPs in simulation.

There are advantages on using PCAP files as input:

  • They can be captured in a real-world network using tcpdump or whireshark, providing your custom IP with a confident data input.

  • They can be easily created in software with scapy, for instance, even enabling description of new protocols.

Dependencies

The project dependencies are:

  • Python 2.7.X
  • Scapy 2.X

The provided testbed project example depends on Xilinx Vivado (tested on version 2017.2). However, net2axis testbench and module will probably simulate in others HDL tools as well.

Usage

In a glance, net2axis is formed by two component:

  • A python script (tool/net2axis.py)
  • A verilog module (hdl/net2axis.v), which models network IP cores and generates Master AXI-Stream transactions.

For the verilog module there are two options: package net2axis module as an (Vivado's) IP, or instantiate it in RTL. Both options will be covered latter on.

The following picture shows the net2axis workflow:

+-------------------+                          +------------------+
|                   |                          |                  |
| PCAP file (.pcap) |--->[tool/net2axis.py]--->| DATA file (.dat) |--->[hdl/net2axis.v] 
|                   |                          |                  |
+-------------------+                          +------------------+

The input PCAP file read by the net2axis.py that generates a intermediate DATA file, which filename should be configured in the C_INPUTFILE parameter of net2axis.v.

Building IP for Vivado's IP Integrator (IPI)

For using net2axis in IPI, you need just to execute:

$ make ip

And add the current directory as an IP repository in your project. You can do it graphically (check Vivado's docs) or running the follwing TCL command in Vivado's TCL console/prompt.

set_property  ip_repo_paths  [pwd] [current_project]
update_ip_catalog -rebuild 

If the Vivado's current directory is the net2axis directory, or having cloned, for instance, the repository in /home/user/net2axis:

set_property  ip_repo_paths /home/user/net2axis [current_project]
update_ip_catalog -rebuild 

You should now be able to instantiate a net2axis IP in IPI, that looks like:

Net2axis IP

Finally, a DATA file must be configured in the net2axis IP. Right-click over it, select Customize Block and add the (preferably) absolute path in the Inputfile field, or execute:

set_property CONFIG.INPUTFILE {/home/user/net2axis/arp.dat} [get_bd_cells net2axis_0]

Vivado's block design

This is not mandatory, but for convenience the tcl/net2axis_bd.tcl script creates a entire block design, including a clock/reset generator. It will be just necessary to create a HDL wrapper an then instantiate that wrapper in a testbench and connect your design to it.

In Vivado's TCL console/prompt, with a project already created, just run:

source tcl/net2axis_bd.tcl

And the following Block design will be created:

Net2axis Block Design

And don't forget to configure DATA file, as described earlier.

Verilog module instantiation

It is pretty straightforward to instantiate the net2axis verilog module. Its parameters and ports are:

  • Parameters:

    • INPUTFILE: (Mandatory) : Path to the intermediate DATA file. Absolute path is recommended.
    • TDATA_WIDTH: (Optional) : AXI-Stream TDATA bus width in bits. Default 32.
    • START_EN: (Optional) : Enables START port. When START port is asserted, tells Net2axis master to send packets. Default 0 (starts sending packets right away). Set to 1 to enable port.
  • Ports:

    • ACLK: Clock
    • ARESETN: Active-low reset
    • M_AXIS_*: Master AXI-Stream interface
    • DONE: Active-high done signal. Goes high when after the last packet is transmitted, i.e., the model reaches the end of DATA file.
    • START: Active-high start signal. When START_EN parameter is 1, and this port is asserted, starts sending packets.

See sim/net2axis_tb.v as an instantiation example.

net2axis.py tool

The net2axis.py script has the following command line options:

$ ./tool/net2axis.py -help
usage: net2axis.py [-h] [-w [DATAWIDTH]] [-i [INITDELAY]] [-d [DELAY]]
                   [-e [ENDIANNESS]]
                   pcapfile

positional arguments:
  pcapfile              Input PCAP file

optional arguments:
  -h, --help            show this help message and exit
  -w [DATAWIDTH], --datawidth [DATAWIDTH]
                        Data bus width (in bits)
  -i [INITDELAY], --initdelay [INITDELAY]
                        Initial packet delay
  -d [DELAY], --delay [DELAY]
                        Inter packet delay
  -e [ENDIANNESS], --endianness [ENDIANNESS]
                        Set endianness

Where:

  • -w : Set the TDATA bus width in bits. Default: 32
  • -i : Set initial delay (in clock cycles), i.e., first packet's delay. Default: 0
  • -d : Set delays (in clock cycles) between packets. Default: 10
  • -e : Endianness (little or big). Default: little

The output DATA file will be the same name of input PCAP file, however with .dat extension.

Usage example

First of all, clone the repository and cd to it and set exec permission on net2axis.py script:

$ chmod +x tool/net2axis.py

Having cloned the repository in /home/user/net2axis and using a PCAP file, say tcp.pcap, generate the intermediate file tcp.dat using TDATA width of 32 bits:

$ ./tool/net2axis.py tcp.pcap

Finally, instantiate net2axis module in your Verilog code using (preferably) the absolute path to the intermediate file as argument of INPUTFILE parameter:

    net2axis #(
        .INPUTFILE      ("/home/user/net2axis/tcp.dat"),
        ) net2axis_0 (
        .ACLK             (ACLK            ),
        .ARESETN          (ARESETN         ),
        .DONE             (DONE            ),
        .M_AXIS_TVALID    (M_AXIS_TVALID   ),
        .M_AXIS_TDATA     (M_AXIS_TDATA    ),
        .M_AXIS_TKEEP     (M_AXIS_TKEEP    ),
        .M_AXIS_TLAST     (M_AXIS_TLAST    ),
        .M_AXIS_TREADY    (M_AXIS_TREADY   ));

That's all folks!!

Testbench

A simple testbench is provided in the project to show how to used it. A TCL tcl/net2axis_sim.tcl script creates a Vivado project and simulates using a PCAP file containing 4 ARP packets as input.

Running make sim creates the project and runs in batch mode, which output each clock cycle of packet being sent. First column is timestamp, second is TVALID signal, third is TDATA, fourth is TKEEP and the last is TLAST.

$ make sim
[.... lots of log ....]
[120.00 ns] Reset deasserted
[221.00 ns] 0 | xxxxxxxx | x | x
[230.00 ns] Starting packet 1 after delay of 0 clock cycles
[251.00 ns] 1 | ffffffff | f | 0
[261.00 ns] 1 | bbaaffff | f | 0
[271.00 ns] 1 | 010000cc | f | 0
[281.00 ns] 1 | 01000608 | f | 0
[291.00 ns] 1 | 04060008 | f | 0
[301.00 ns] 1 | bbaa0100 | f | 0
[311.00 ns] 1 | 010000cc | f | 0
[321.00 ns] 1 | 00000000 | f | 0
[331.00 ns] 1 | ffffffff | f | 0
[341.00 ns] 1 | 000affff | f | 0
[351.00 ns] 1 | 00000100 | 3 | 1
[361.00 ns] 0 | 00000100 | 3 | 1
[390.00 ns] Starting packet 2 after delay of 10 clock cycles
[511.00 ns] 1 | ffffffff | f | 0
[521.00 ns] 1 | bbaaffff | f | 0
[531.00 ns] 1 | 010000cc | f | 0
[541.00 ns] 1 | 01000608 | f | 0
[551.00 ns] 1 | 04060008 | f | 0
[561.00 ns] 1 | bbaa0100 | f | 0
[571.00 ns] 1 | 010000cc | f | 0
[581.00 ns] 1 | 00000000 | f | 0
[591.00 ns] 1 | ffffffff | f | 0
[601.00 ns] 1 | 000affff | f | 0
[611.00 ns] 1 | 00000100 | 3 | 1
[621.00 ns] 0 | 00000100 | 3 | 1
[650.00 ns] Starting packet 3 after delay of 10 clock cycles
[771.00 ns] 1 | ffffffff | f | 0
[781.00 ns] 1 | bbaaffff | f | 0
[791.00 ns] 1 | 010000cc | f | 0
[801.00 ns] 1 | 01000608 | f | 0
[811.00 ns] 1 | 04060008 | f | 0
[821.00 ns] 1 | bbaa0200 | f | 0
[831.00 ns] 1 | 010000cc | f | 0
[841.00 ns] 1 | 0100000a | f | 0
[851.00 ns] 1 | 00ccbbaa | f | 0
[861.00 ns] 1 | 000a0100 | f | 0
[871.00 ns] 1 | 00000100 | 3 | 1
[881.00 ns] 0 | 00000100 | 3 | 1
[910.00 ns] Starting packet 4 after delay of 10 clock cycles
[1031.00 ns] 1 | ffffffff | f | 0
[1041.00 ns] 1 | bbaaffff | f | 0
[1051.00 ns] 1 | 010000cc | f | 0
[1061.00 ns] 1 | 01000608 | f | 0
[1071.00 ns] 1 | 04060008 | f | 0
[1081.00 ns] 1 | bbaa0100 | f | 0
[1091.00 ns] 1 | 010000cc | f | 0
[1101.00 ns] 1 | 0100000a | f | 0
[1111.00 ns] 1 | ffffffff | f | 0
[1121.00 ns] 1 | 000affff | f | 0
[1131.00 ns] 1 | 00000100 | 3 | 1
[1240.00 ns] Simulation finished

Running make sim-gui does the same simulation, but executes Vivado GUI, where you can graphically see the waveforms. The following figure is the testbench result as well:

Testbench result