From 99811a47c201a62e471e55bf2f1d8674b75545ab Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 17 Jun 2019 12:44:12 +0200 Subject: [PATCH] [p4src] add mini p4 program that modifies ipv6 data --- netpfga/minip4/src/minip4_solution-mirror.p4 | 133 +++++++++++++++ netpfga/minip4/src/minip4_solution-v6zero.p4 | 126 +++++++++++++++ netpfga/minip4/src/minip4_solution.p4 | 134 +--------------- netpfga/minip4/testdata/gen_testdata-port1.py | 151 ++++++++++++++++++ 4 files changed, 411 insertions(+), 133 deletions(-) create mode 100644 netpfga/minip4/src/minip4_solution-mirror.p4 create mode 100644 netpfga/minip4/src/minip4_solution-v6zero.p4 mode change 100644 => 120000 netpfga/minip4/src/minip4_solution.p4 create mode 100755 netpfga/minip4/testdata/gen_testdata-port1.py diff --git a/netpfga/minip4/src/minip4_solution-mirror.p4 b/netpfga/minip4/src/minip4_solution-mirror.p4 new file mode 100644 index 0000000..5d7fc51 --- /dev/null +++ b/netpfga/minip4/src/minip4_solution-mirror.p4 @@ -0,0 +1,133 @@ +#include +#include +#include "headers.p4" + +/******************************************************************************** + * Header + */ + +typedef bit<48> EthAddr_t; +header Ethernet_h { + EthAddr_t dstAddr; + EthAddr_t srcAddr; + bit<16> etherType; +} + +struct Parsed_packet { + Ethernet_h ethernet; +} + +// user defined metadata: can be used to share information between +// TopParser, TopPipe, and TopDeparser +struct user_metadata_t { + bit<8> unused; +} + +// digest_data, MUST be 256 bits -- what is this used for? +struct digest_data_t { + bit<256> unused; +} + + +/******************************************************************************** + * Parser + */ + +@Xilinx_MaxPacketRegion(1024) +parser TopParser(packet_in b, + out Parsed_packet p, + out user_metadata_t user_metadata, + out digest_data_t digest_data, + inout sume_metadata_t sume_metadata) { + state start { + b.extract(p.ethernet); + user_metadata.unused = 0; + digest_data.unused = 0; + + transition accept; + } +} + +/******************************************************************************** + * Main + */ +control TopPipe(inout Parsed_packet p, + inout user_metadata_t user_metadata, + inout digest_data_t digest_data, + inout sume_metadata_t sume_metadata) { + + action swap_eth_addresses() { + EthAddr_t temp = p.ethernet.dstAddr; + p.ethernet.dstAddr = p.ethernet.srcAddr; + p.ethernet.srcAddr = temp; + + /* set egress port */ + sume_metadata.dst_port = sume_metadata.src_port; + } + + action send_to_port1() { + sume_metadata.dst_port = 1; + } + + action send_to_all_ports() { + /* Taken from commands.txt of the "int" project: + table_cam_add_entry forward set_output_port 0xffffffffffff => 0b01010101 + + python convert: + >>> 0b01010101 + 85 + + */ + sume_metadata.dst_port = 85; + } + + action do_nothing() { + EthAddr_t temp = p.ethernet.dstAddr; + } + + table lookup_table { + key = { + p.ethernet.dstAddr: exact; + } + + actions = { + swap_eth_addresses; + do_nothing; + send_to_port1; + send_to_all_ports; + } + size = 64; +// default_action = swap_eth_addresses; // test_mirror(): in gen_testdata.py +// default_action = send_to_port1; // test_port1() + default_action = send_to_all_ports; // test_allports(): + } + + apply { + lookup_table.apply(); + } +} + +/******************************************************************************** + * Deparser + */ + +@Xilinx_MaxPacketRegion(1024) +control TopDeparser(packet_out b, + in Parsed_packet p, + in user_metadata_t user_metadata, + inout digest_data_t digest_data, + inout sume_metadata_t sume_metadata) { + apply { + b.emit(p.ethernet); + } +} + +/******************************************************************************** + * Switch + */ + +SimpleSumeSwitch( + TopParser(), + TopPipe(), + TopDeparser() +) main; diff --git a/netpfga/minip4/src/minip4_solution-v6zero.p4 b/netpfga/minip4/src/minip4_solution-v6zero.p4 new file mode 100644 index 0000000..508cac1 --- /dev/null +++ b/netpfga/minip4/src/minip4_solution-v6zero.p4 @@ -0,0 +1,126 @@ +#include +#include +#include "headers.p4" + +/******************************************************************************** + * Header + */ + +typedef bit<48> EthAddr_t; +header Ethernet_h { + EthAddr_t dstAddr; + EthAddr_t srcAddr; + bit<16> etherType; +} + +struct Parsed_packet { + Ethernet_h ethernet; +} + +// user defined metadata: can be used to share information between +// TopParser, TopPipe, and TopDeparser +struct user_metadata_t { + bit<8> unused; +} + +// digest_data, MUST be 256 bits -- what is this used for? +struct digest_data_t { + bit<256> unused; +} + + +/******************************************************************************** + * Parser + */ + +@Xilinx_MaxPacketRegion(1024) +parser TopParser(packet_in packet, + out Parsed_packet hdr, + out user_metadata_t meta + out digest_data_t digest_data, + inout sume_metadata_t sume_metadata) { + state start { + meta.unused = 0; + digest_data.unused = 0; + + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.ethertype) { + TYPE_IPV6: ipv6; + default: accept; + } + } + + state ipv6 { + packet.extract(hdr.ipv6); + transition accept; + } +} + +/******************************************************************************** + * Main + */ +control TopPipe(inout Parsed_packet hdr, + inout user_metadata_t meta, + inout digest_data_t digest_data, + inout sume_metadata_t sume_metadata) { + + action do_nothing() { + EthAddr_t temp = p.ethernet.dstAddr; + } + + action send_to_port1() { + sume_metadata.dst_port = 1; + } + + action modify_ipv6 () { + hdr.ipv6.src_addr += 1; + hdr.ipv6.dst_addr += 2; + + send_to_port1(); + } + + table lookup_table { + key = { + p.ethernet.dstAddr: exact; + } + + actions = { + do_nothing; + send_to_port1; + } + size = 64; +// default_action = swap_eth_addresses; // test_mirror(): in gen_testdata.py +// default_action = send_to_port1; // test_port1() +// default_action = send_to_all_ports; // test_allports(): + default_action = modify_ipv6; + } + + apply { + lookup_table.apply(); + } +} + +/******************************************************************************** + * Deparser + */ + +@Xilinx_MaxPacketRegion(1024) +control TopDeparser(packet_out b, + in Parsed_packet p, + in user_metadata_t user_metadata, + inout digest_data_t digest_data, + inout sume_metadata_t sume_metadata) { + apply { + b.emit(p.ethernet); + } +} + +/******************************************************************************** + * Switch + */ + +SimpleSumeSwitch( + TopParser(), + TopPipe(), + TopDeparser() +) main; diff --git a/netpfga/minip4/src/minip4_solution.p4 b/netpfga/minip4/src/minip4_solution.p4 deleted file mode 100644 index 5d7fc51..0000000 --- a/netpfga/minip4/src/minip4_solution.p4 +++ /dev/null @@ -1,133 +0,0 @@ -#include -#include -#include "headers.p4" - -/******************************************************************************** - * Header - */ - -typedef bit<48> EthAddr_t; -header Ethernet_h { - EthAddr_t dstAddr; - EthAddr_t srcAddr; - bit<16> etherType; -} - -struct Parsed_packet { - Ethernet_h ethernet; -} - -// user defined metadata: can be used to share information between -// TopParser, TopPipe, and TopDeparser -struct user_metadata_t { - bit<8> unused; -} - -// digest_data, MUST be 256 bits -- what is this used for? -struct digest_data_t { - bit<256> unused; -} - - -/******************************************************************************** - * Parser - */ - -@Xilinx_MaxPacketRegion(1024) -parser TopParser(packet_in b, - out Parsed_packet p, - out user_metadata_t user_metadata, - out digest_data_t digest_data, - inout sume_metadata_t sume_metadata) { - state start { - b.extract(p.ethernet); - user_metadata.unused = 0; - digest_data.unused = 0; - - transition accept; - } -} - -/******************************************************************************** - * Main - */ -control TopPipe(inout Parsed_packet p, - inout user_metadata_t user_metadata, - inout digest_data_t digest_data, - inout sume_metadata_t sume_metadata) { - - action swap_eth_addresses() { - EthAddr_t temp = p.ethernet.dstAddr; - p.ethernet.dstAddr = p.ethernet.srcAddr; - p.ethernet.srcAddr = temp; - - /* set egress port */ - sume_metadata.dst_port = sume_metadata.src_port; - } - - action send_to_port1() { - sume_metadata.dst_port = 1; - } - - action send_to_all_ports() { - /* Taken from commands.txt of the "int" project: - table_cam_add_entry forward set_output_port 0xffffffffffff => 0b01010101 - - python convert: - >>> 0b01010101 - 85 - - */ - sume_metadata.dst_port = 85; - } - - action do_nothing() { - EthAddr_t temp = p.ethernet.dstAddr; - } - - table lookup_table { - key = { - p.ethernet.dstAddr: exact; - } - - actions = { - swap_eth_addresses; - do_nothing; - send_to_port1; - send_to_all_ports; - } - size = 64; -// default_action = swap_eth_addresses; // test_mirror(): in gen_testdata.py -// default_action = send_to_port1; // test_port1() - default_action = send_to_all_ports; // test_allports(): - } - - apply { - lookup_table.apply(); - } -} - -/******************************************************************************** - * Deparser - */ - -@Xilinx_MaxPacketRegion(1024) -control TopDeparser(packet_out b, - in Parsed_packet p, - in user_metadata_t user_metadata, - inout digest_data_t digest_data, - inout sume_metadata_t sume_metadata) { - apply { - b.emit(p.ethernet); - } -} - -/******************************************************************************** - * Switch - */ - -SimpleSumeSwitch( - TopParser(), - TopPipe(), - TopDeparser() -) main; diff --git a/netpfga/minip4/src/minip4_solution.p4 b/netpfga/minip4/src/minip4_solution.p4 new file mode 120000 index 0000000..19418c9 --- /dev/null +++ b/netpfga/minip4/src/minip4_solution.p4 @@ -0,0 +1 @@ +minip4_solution-v6zero.p4 \ No newline at end of file diff --git a/netpfga/minip4/testdata/gen_testdata-port1.py b/netpfga/minip4/testdata/gen_testdata-port1.py new file mode 100755 index 0000000..9a67dae --- /dev/null +++ b/netpfga/minip4/testdata/gen_testdata-port1.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python + +# from switch_calc_headers import * +from scapy.all import * +from nf_sim_tools import * +from collections import OrderedDict +import sss_sdnet_tuples + +######################## +# pkt generation tools # +######################## + +pktsApplied = [] +pktsExpected = [] + +# Pkt lists for SUME simulations +nf_applied = OrderedDict() +nf_applied[0] = [] +nf_applied[1] = [] +nf_applied[2] = [] +nf_applied[3] = [] +nf_expected = OrderedDict() +nf_expected[0] = [] +nf_expected[1] = [] +nf_expected[2] = [] +nf_expected[3] = [] + +nf_port_map = { + "nf0":0b00000001, + "nf1":0b00000100, + "nf2":0b00010000, + "nf3":0b01000000, + "dma0":0b00000010 +} + +nf_id_map = { + "nf0":0, + "nf1":1, + "nf2":2, + "nf3":3 +} + +sss_sdnet_tuples.clear_tuple_files() + +def applyPkt(pkt, ingress, time): + pktsApplied.append(pkt) + sss_sdnet_tuples.sume_tuple_in['src_port'] = nf_port_map[ingress] + sss_sdnet_tuples.sume_tuple_expect['src_port'] = nf_port_map[ingress] + pkt.time = time + nf_applied[nf_id_map[ingress]].append(pkt) + +def expPkt(pkt, egress): + pktsExpected.append(pkt) + sss_sdnet_tuples.sume_tuple_expect['dst_port'] = nf_port_map[egress] + sss_sdnet_tuples.write_tuples() + if egress in ["nf0","nf1","nf2","nf3"]: + nf_expected[nf_id_map[egress]].append(pkt) + elif egress == 'bcast': + nf_expected[0].append(pkt) + nf_expected[1].append(pkt) + nf_expected[2].append(pkt) + nf_expected[3].append(pkt) + +def print_summary(pkts): + for pkt in pkts: + print "summary = ", pkt.summary() + +def write_pcap_files(): + wrpcap("src.pcap", pktsApplied) + wrpcap("dst.pcap", pktsExpected) + + for i in nf_applied.keys(): + if (len(nf_applied[i]) > 0): + wrpcap('nf{0}_applied.pcap'.format(i), nf_applied[i]) + + for i in nf_expected.keys(): + if (len(nf_expected[i]) > 0): + wrpcap('nf{0}_expected.pcap'.format(i), nf_expected[i]) + + for i in nf_applied.keys(): + print "nf{0}_applied times: ".format(i), [p.time for p in nf_applied[i]] + +##################### +# generate testdata # +##################### + +MAC1 = "08:11:11:11:11:08" +MAC2 = "08:22:22:22:22:08" +pktCnt = 0 + +INDEX_WIDTH = 4 +REG_DEPTH = 2**INDEX_WIDTH + +# Not sure what this is used for +NUM_KEYS = 4 +lookup_table = { + 0: 0x00000001, + 1: 0x00000010, + 2: 0x00000100, + 3: 0x00001000 +} + +def test_port1(): + pktCnt = 0 + + # First ethernet + pktCnt += 1 + pkt = Ether(dst=MAC2, src=MAC1) + pkt = pad_pkt(pkt, 64) + applyPkt(pkt, 'nf0', pktCnt) + expPkt(pkt, 'nf0') + +# Test that packets are being mirrored +def test_mirror(): + pktCnt = 0 + + # First ethernet + pktCnt += 1 + pkt = Ether(dst=MAC2, src=MAC1) + pkt = pad_pkt(pkt, 64) + applyPkt(pkt, 'nf0', pktCnt) + + pktCnt += 1 + pkt = Ether(dst=MAC1, src=MAC2) + pkt = pad_pkt(pkt, 64) + expPkt(pkt, 'nf0') + + # # Second IP + # pktCnt += 1 + # pkt = Ether(dst=MAC2, src=MAC1) / IPv6(src="fe80::1", dst="fe80::2") + # pkt = pad_pkt(pkt, 64) + # applyPkt(pkt, 'nf0', pktCnt) + # pktCnt += 1 + # pkt = Ether(dst=MAC1, src=MAC2) / IPv6(src="fe80::2", dst="fe80::1") + # pkt = pad_pkt(pkt, 64) + # expPkt(pkt, 'nf0') + + # # Third tcp + # pktCnt += 1 + # pkt = Ether(dst=MAC2, src=MAC1) / IPv6(src="fe80::1", dst="fe80::2") / TCP(sport=42, dport=23) + # pkt = pad_pkt(pkt, 64) + # applyPkt(pkt, 'nf0', pktCnt) + # pktCnt += 1 + # pkt = Ether(dst=MAC1, src=MAC2) / IPv6(src="fe80::2", dst="fe80::1") / TCP(sport=23, dport=42) + # pkt = pad_pkt(pkt, 64) + # expPkt(pkt, 'nf0') + +#test_mirror() +test_port1() + +write_pcap_files()