From 2440c8f1ad5b5e8618b82f4f1af73071fcce1879 Mon Sep 17 00:00:00 2001 From: yyyIce Date: Thu, 7 May 2020 17:36:40 +0800 Subject: add bloom filter --- ...232\204\350\256\276\350\256\241\357\274\211.md" | 136 ++++++ bloomfilter/cmd.txt | 16 + bloomfilter/image/1.jpg | Bin 0 -> 82071 bytes bloomfilter/image/2.png | Bin 0 -> 129374 bytes bloomfilter/p4src/silkroad_bf.p4 | 466 +++++++++++++++++++++ bloomfilter/ptf-test/test.py | 233 +++++++++++ 6 files changed, 851 insertions(+) create mode 100644 "bloomfilter/P4 Bloom Filter\350\256\276\350\256\241\346\226\207\346\241\243\357\274\210\345\237\272\344\272\216Silkroad\344\270\255\347\232\204\350\256\276\350\256\241\357\274\211.md" create mode 100644 bloomfilter/cmd.txt create mode 100644 bloomfilter/image/1.jpg create mode 100644 bloomfilter/image/2.png create mode 100644 bloomfilter/p4src/silkroad_bf.p4 create mode 100644 bloomfilter/ptf-test/test.py diff --git "a/bloomfilter/P4 Bloom Filter\350\256\276\350\256\241\346\226\207\346\241\243\357\274\210\345\237\272\344\272\216Silkroad\344\270\255\347\232\204\350\256\276\350\256\241\357\274\211.md" "b/bloomfilter/P4 Bloom Filter\350\256\276\350\256\241\346\226\207\346\241\243\357\274\210\345\237\272\344\272\216Silkroad\344\270\255\347\232\204\350\256\276\350\256\241\357\274\211.md" new file mode 100644 index 0000000..e9ee3a9 --- /dev/null +++ "b/bloomfilter/P4 Bloom Filter\350\256\276\350\256\241\346\226\207\346\241\243\357\274\210\345\237\272\344\272\216Silkroad\344\270\255\347\232\204\350\256\276\350\256\241\357\274\211.md" @@ -0,0 +1,136 @@ +## P4 Bloom Filter设计及实现文档(基于Silkroad中的设计) + +### 一、流程设计 + + SilkRoad中的设计如下: + +![silkroad_bloom_filter_img](./image/1.jpg) + +其中TransitTable就是BloomFilter,根据文章应该是通过CPU控制其读写,将连接摘要写入寄存器。考虑到目前个人能力,还无法实现数据面和控制面的交互。所以增加一张TransitTable,在其中设置固定的条目,来控制寄存器的写入和读取。为方便测试BloomFilter是否正常运行,更改后的Bloom Filter流程图如下: + +![my_bloom_filter_design_img](./image/2.png) + +所有数据包都将匹配ConnTable,当未命中ConnTable且该数据包是连接的第一个数据包(TCP SYN包)时,匹配Transit Table和Bloom Filter,当 + +1)命中BloomFliter时,令命中标志位result = 1,将数据包转发到10号端口; + +2)未命中BloomFilter时,即result = 0时,将数据包转发到5号端口。 + +### 二、具体实现 + +##### 1.BloomFilter控件 + +1)将BloomFilter定义为一个Control块,在块内实现BloomFilter应该具备的功能。传入参数有两个,一是用户自定义元数据meta,其中包括了连接五元组摘要、读写操作位,二是传出结果result,用于传递BloomFilter查询的结果。 + +```C +control BloomFilter( + inout my_ingress_metadata_t meta, + inout bit<1> result) + (bit<32> num_boxes) +{ ... } +``` + +2)在该块里创建两个hash实例,CRC16和CRC32,用于BloomFilter中元素存在位索引的计算; + +```C + Hash>(HashAlgorithm_t.CRC16) bfhash_crc16; + Hash>(HashAlgorithm_t.CRC32) bfhash_crc32; +``` + +3)由于在一个周期只能对寄存器进行一次操作,所以创建两个寄存器实例,用于存储对应索引位置的存在位(值为1),num_boxes为寄存器槽的个数,第一个bit<8>为每个槽的大小,第二个bit<8>为索引大小; + +```C + Register,bit<8>>(num_boxes) crc16_set; + Register,bit<8>>(num_boxes) crc32_set; +``` + +4)在TNA架构下对寄存器进行操作不可以使用write()和read(),必须使用在tofino.p4和tofino2.p4中提供的RegisterAction。对每个寄存器实例分别创建读写操作的RegisterAction,用于BloomFilter的写入和查询; + +```C + RegisterAction, bit<8>, bit<8>>(crc16_set) crc16_insert = { + void apply(inout bit<8> set_store){ + set_store = (bit<8>)meta.insert; + } + }; + + RegisterAction, bit<8>, bit<8>>(crc16_set) crc16_checkout = { + void apply(inout bit<8> value, out bit<8> ret){ + ret = value; + } + }; + ... +``` + +5)在apply{}中对上述实例进行应用,当meta.insert = 1时,向两个寄存器写入,当meta.checkout = 1时,读两个寄存器,如果读取结果都为1,则令传入参数result = 1,否则result = 0。 + +```C + apply { + //计算hash值 + ... + if(meta.insert == 1){ + crc16_insert.execute(crc16_value); + crc32_insert.execute(crc32_value); + } + else if(meta.checkout == 1){ + bit<1> crc16_ret = (bit<1>)crc16_checkout.execute(crc16_value); + bit<1> crc32_ret = (bit<1>)crc32_checkout.execute(crc32_value); + if(crc32_ret == 1 && crc16_ret == 1){ + result = 1; + } + } + } +``` + + + +##### 2.流程实现 + +1)在Ingress中创建一个用于计算连接五元组摘要的Hash实例,这里选用CRC16; + +```C + Hash>(HashAlgorithm_t.CRC16) hash_digest; +``` + +2)创建一个BloomFilter实例; + +```C + BloomFilter(num_boxes=256) bloom_filter; +``` + +3)创建ConnTable、TransitTable、VipTable; + +4)在apply中应用它们,匹配ConnTable,当ConnTable未命中时,若syn=1,则匹配TransitTable和BloomFilter;如果result=0,则匹配VipTable。 + +```C + apply { + ig_tm_md.ucast_egress_port = 5; + meta.conn_digest = hash_digest.get(IPV4_TCP_HASH_FIELDS); + //calc_conn_digest_hash.apply(hdr, meta.conn_digest); + if(!conn.apply().hit){ + //syn == 1, then goto transit and vip table + if(hdr.tcp.syn == 1){ + transit.apply(); + bloom_filter.apply(meta, result); + //if result == 1 return old_ver else goto vip table + } + if(result == 1) { + ig_tm_md.ucast_egress_port = 10; //test 'checkout' function + } + vip.apply(); + } + } +``` + + + +### 三、测试 + +由于主要测试BloomFilter的功能是否正常,所以不对其他表进行单独测试。 + +设置两个连接: + +- TCP 192.168.1.3:222 ----> 192.168.2.3:666 +- TCP 192.168.1.4:444 ----> 192.168.2.4:888 + +将第一个连接写入bloomfilter,第二个连接不写入bloomfilter,对两个连接执行查询操作,连接在bloomfilter中,数据包被转发到10号端口,连接不在bloomfilter中,数据包被转发到5号端口。则第一个连接的SYN数据包被转发到10号端口,第二个连接的SYN数据包被转发到5号端口。 + diff --git a/bloomfilter/cmd.txt b/bloomfilter/cmd.txt new file mode 100644 index 0000000..0e5dc4f --- /dev/null +++ b/bloomfilter/cmd.txt @@ -0,0 +1,16 @@ +#set_path +cd ~/bf-sde-9.0.0 +. ~/tools/set_sde.bash + +#compile +~/tools/p4_build.sh ~/labs/silkroad_bf/silkroad_bf.p4 + +#tty1 +sudo $SDE_INSTALL/bin/veth_setup.sh +./run_tofino_model.sh -p silkroad_bf + +#tty2 +./run_switchd.sh -p silkroad_bf + +#tty3 +./run_p4_tests.sh -p silkroad_bf -t ~/labs/silkroad_bf/ -s test.BloomFilter diff --git a/bloomfilter/image/1.jpg b/bloomfilter/image/1.jpg new file mode 100644 index 0000000..c305797 Binary files /dev/null and b/bloomfilter/image/1.jpg differ diff --git a/bloomfilter/image/2.png b/bloomfilter/image/2.png new file mode 100644 index 0000000..223b7da Binary files /dev/null and b/bloomfilter/image/2.png differ diff --git a/bloomfilter/p4src/silkroad_bf.p4 b/bloomfilter/p4src/silkroad_bf.p4 new file mode 100644 index 0000000..b1a7038 --- /dev/null +++ b/bloomfilter/p4src/silkroad_bf.p4 @@ -0,0 +1,466 @@ +/* -*- P4_16 -*- */ + +#include +#include + +/************************************************************************* + ************* C O N S T A N T S A N D T Y P E S ******************* +*************************************************************************/ +const bit<16> ETHERTYPE_TPID = 0x8100; +const bit<16> ETHERTYPE_IPV4 = 0x0800; + +const int CONN_TABLE_SIZE = 12288; +const int VIP_TABLE_SIZE = 12288; +const int TRANSIT_TABLE_SIZE = 12288; + +#define IPV4_TCP_HASH_FIELDS { \ + hdr.ipv4.src_addr, \ + hdr.ipv4.dst_addr, \ + hdr.ipv4.protocol, \ + hdr.tcp.src_port, \ + hdr.tcp.dst_port \ +} + +/************************************************************************* + *********************** H E A D E R S ********************************* + *************************************************************************/ +/* Define all the headers the program will recognize */ +/* The actual sets of headers processed by each gress can differ */ + +/* Standard ethernet header */ +header ethernet_t { + bit<48> dst_addr; + bit<48> src_addr; + bit<16> ether_type; +} + +header vlan_tag_t { + bit<3> pcp; + bit<1> cfi; + bit<12> vid; + bit<16> ether_type; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> total_len; + bit<16> identification; + bit<3> flags; + bit<13> frag_offset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdr_checksum; + bit<32> src_addr; + bit<32> dst_addr; +} + +header ipv4_options_t { + varbit<320> data; +} + +header icmp_t { + bit<16> type_code; + bit<16> checksum; +} + +header igmp_t { + bit<16> type_code; + bit<16> checksum; +} + +header tcp_t { + bit<16> src_port; + bit<16> dst_port; + bit<32> seq_no; + bit<32> ack_no; + bit<4> data_offset; + bit<6> res; + bit<1> urg; + bit<1> ack; + bit<1> psh; + bit<1> rst; + bit<1> syn; + bit<1> fin; + bit<16> window; + bit<16> checksum; + bit<16> urgent_ptr; +} + +header udp_t { + bit<16> src_port; + bit<16> dst_port; + bit<16> len; + bit<16> checksum; +} + +/************************************************************************* + ************** I N G R E S S P R O C E S S I N G ******************* + *************************************************************************/ + + /*********************** H E A D E R S ************************/ + +struct my_ingress_headers_t { + ethernet_t ethernet; + vlan_tag_t[2] vlan_tag; + ipv4_t ipv4; + ipv4_options_t ipv4_options; + icmp_t icmp; + igmp_t igmp; + tcp_t tcp; + udp_t udp; +} + + /****** G L O B A L I N G R E S S M E T A D A T A *********/ +struct my_ingress_metadata_t { + bit<16> conn_digest; + bit<6> conn_version; + bit<1> insert; + bit<1> checkout; + bit<1> first_frag; +} + + /*********************** P A R S E R **************************/ + +parser IngressParser(packet_in pkt, + /* User */ + out my_ingress_headers_t hdr, + out my_ingress_metadata_t meta, + /* Intrinsic */ + out ingress_intrinsic_metadata_t ig_intr_md) +{ + /* This is a mandatory state, required by Tofino Architecture */ + state start { + pkt.extract(ig_intr_md); + pkt.advance(PORT_METADATA_SIZE); + transition meta_init; + } + + state meta_init { + meta.conn_digest = 0; + meta.conn_version = 0; + meta.insert = 0; + meta.checkout = 0; + meta.first_frag = 0; + transition parse_ethernet; + } + + state parse_ethernet { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.ether_type) { + ETHERTYPE_TPID: parse_vlan_tag; + ETHERTYPE_IPV4: parse_ipv4; + default: accept; + } + } + + state parse_vlan_tag { + pkt.extract(hdr.vlan_tag.next); + transition select(hdr.vlan_tag.last.ether_type) { + ETHERTYPE_TPID : parse_vlan_tag; + ETHERTYPE_IPV4 : parse_ipv4; + default: accept; + } + } + + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition select(hdr.ipv4.ihl) { + 0x5 : parse_ipv4_no_options; + 0x6 &&& 0xE : parse_ipv4_options; + 0x8 &&& 0x8 : parse_ipv4_options; + default: reject; + } + } + + state parse_ipv4_options { + pkt.extract( + hdr.ipv4_options, + ((bit<32>)hdr.ipv4.ihl - 32w5) * 32); + transition parse_ipv4_no_options; + } + + state parse_ipv4_no_options { + transition select(hdr.ipv4.frag_offset, + hdr.ipv4.protocol, + hdr.ipv4.ihl) { + ( 0, 1, 5 ) : parse_icmp; + ( 0, 2, 5 ) : parse_igmp; + ( 0, 6, 5 ) : parse_tcp; + ( 0, 17, 5 ) : parse_udp; + ( 0, _ , 5 ) : parse_first_fragment; + default : accept; + } + } + + state parse_icmp { + pkt.extract(hdr.icmp); + transition parse_first_fragment; + } + + state parse_igmp { + pkt.extract(hdr.igmp); + transition parse_first_fragment; + } + + state parse_tcp { + pkt.extract(hdr.tcp); + transition parse_first_fragment; + } + + state parse_udp { + pkt.extract(hdr.udp); + transition parse_first_fragment; + } + + state parse_first_fragment { + meta.first_frag = 1; + transition accept; + } + +} + +/**************** TransitTable(Bloom Filter) ********************/ +control BloomFilter( + inout my_ingress_metadata_t meta, + inout bit<1> result) + (bit<32> num_boxes) +{ + Hash>(HashAlgorithm_t.CRC16) bfhash_crc16; + Hash>(HashAlgorithm_t.CRC32) bfhash_crc32; + + /* Register(bit<32> size) -> size / T <= 2^I + * 2048 / 8 = 256 = 2^8 + * T:bit<8> I:bit<8> size=2048 + */ + + //hash_1 crc16 + Register,bit<8>>(num_boxes) crc16_set; + RegisterAction, bit<8>, bit<8>>(crc16_set) crc16_insert = { + void apply(inout bit<8> set_store){ + set_store = (bit<8>)meta.insert; + } + }; + + RegisterAction, bit<8>, bit<8>>(crc16_set) crc16_checkout = { + void apply(inout bit<8> value, out bit<8> ret){ + ret = value; + } + }; + + //hash_2 crc32 + Register,bit<8>>(num_boxes) crc32_set; + RegisterAction, bit<8>, bit<8>>(crc32_set) crc32_insert = { + void apply(inout bit<8> set_store){ + set_store = (bit<8>)meta.insert; + } + }; + + RegisterAction, bit<8>, bit<8>>(crc32_set) crc32_checkout = { + void apply(inout bit<8> value, out bit<8> ret){ + ret = value; + } + }; + + apply{ + bit<8> crc16_value = (bit<8>)bfhash_crc16.get(meta.conn_digest)[7:0]; + bit<8> crc32_value = (bit<8>)bfhash_crc32.get(meta.conn_digest)[7:0]; + if(meta.insert == 1){ + crc16_insert.execute(crc16_value); + crc32_insert.execute(crc32_value); + } + else if(meta.checkout == 1){ + bit<1> crc16_ret = (bit<1>)crc16_checkout.execute(crc16_value); + bit<1> crc32_ret = (bit<1>)crc32_checkout.execute(crc32_value); + if(crc32_ret == 1 && crc16_ret == 1){ + result = 1; + } + } + } +} + +/***************** M A T C H - A C T I O N *********************/ +control Ingress( + /* User */ + inout my_ingress_headers_t hdr, + inout my_ingress_metadata_t meta, + /* Intrinsic */ + in ingress_intrinsic_metadata_t ig_intr_md, + in ingress_intrinsic_metadata_from_parser_t ig_prsr_md, + inout ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md, + inout ingress_intrinsic_metadata_for_tm_t ig_tm_md) +{ + bit<1> result = 0; + Hash>(HashAlgorithm_t.CRC16) hash_digest; + BloomFilter(num_boxes=256) bloom_filter; + + /************************ ConnTable ***********************/ + action conn_miss(){ + } + + action get_vip_version(bit<6> dip_ver){ + meta.conn_version = dip_ver; + } + + table conn { + key = { + meta.conn_digest : exact; + } + actions = { + get_vip_version; + conn_miss; + } + default_action = conn_miss(); + size = CONN_TABLE_SIZE; + } + /************************ VIPTable ***********************/ + action vip_miss(){ + exit; + } + table vip { + key = { + hdr.ipv4.dst_addr : exact; + } + actions = { + get_vip_version; + vip_miss; + } + default_action = vip_miss(); + size = VIP_TABLE_SIZE; + } + + action set_opt(bit<1> is_insert, bit<1> is_checkout){ + meta.insert = is_insert; + meta.checkout = is_checkout; + } + + /* To set 'insert' or 'checkout' entries in bloom filter */ + table transit { + actions = { + set_opt; + } + key = { + meta.conn_digest: exact; + } + size = 1024; + default_action = set_opt(0,0); + } + + /* The algorithm */ + apply { + ig_tm_md.ucast_egress_port = 5; + meta.conn_digest = hash_digest.get(IPV4_TCP_HASH_FIELDS); + //calc_conn_digest_hash.apply(hdr, meta.conn_digest); + if(!conn.apply().hit){ + //syn == 1, then goto transit and vip table + if(hdr.tcp.syn == 1){ + transit.apply(); + bloom_filter.apply(meta, result); + //if result == 1 return old_ver else goto vip table + } + if(result == 1) { + ig_tm_md.ucast_egress_port = 10; //test 'checkout' function + } + vip.apply(); + } + } +} + + /********************* D E P A R S E R ************************/ + +control IngressDeparser(packet_out pkt, + /* User */ + inout my_ingress_headers_t hdr, + in my_ingress_metadata_t meta, + /* Intrinsic */ + in ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md) +{ + apply { + pkt.emit(hdr); + } +} + + +/************************************************************************* + **************** E G R E S S P R O C E S S I N G ******************* + *************************************************************************/ + + /*********************** H E A D E R S ************************/ + +struct my_egress_headers_t { + ethernet_t ethernet; + vlan_tag_t[2] vlan_tag; + ipv4_t ipv4; + ipv4_options_t ipv4_options; + icmp_t icmp; + igmp_t igmp; + tcp_t tcp; + udp_t udp; +} + + /******** G L O B A L E G R E S S M E T A D A T A *********/ + +struct my_egress_metadata_t { + +} + + /*********************** P A R S E R **************************/ + +parser EgressParser(packet_in pkt, + /* User */ + out my_egress_headers_t hdr, + out my_egress_metadata_t meta, + /* Intrinsic */ + out egress_intrinsic_metadata_t eg_intr_md) +{ + /* This is a mandatory state, required by Tofino Architecture */ + state start { + pkt.extract(eg_intr_md); + transition accept; + } + +} + + /***************** M A T C H - A C T I O N *********************/ + +control Egress( + /* User */ + inout my_egress_headers_t hdr, + inout my_egress_metadata_t meta, + /* Intrinsic */ + in egress_intrinsic_metadata_t eg_intr_md, + in egress_intrinsic_metadata_from_parser_t eg_prsr_md, + inout egress_intrinsic_metadata_for_deparser_t eg_dprsr_md, + inout egress_intrinsic_metadata_for_output_port_t eg_oport_md) +{ + apply { + } +} + + /********************* D E P A R S E R ************************/ + +control EgressDeparser(packet_out pkt, + /* User */ + inout my_egress_headers_t hdr, + in my_egress_metadata_t meta, + /* Intrinsic */ + in egress_intrinsic_metadata_for_deparser_t eg_dprsr_md) +{ + apply { + pkt.emit(hdr); + } +} + + +/************ F I N A L P A C K A G E ******************************/ +Pipeline( + IngressParser(), + Ingress(), + IngressDeparser(), + EgressParser(), + Egress(), + EgressDeparser() +) pipe; + +Switch(pipe) main; diff --git a/bloomfilter/ptf-test/test.py b/bloomfilter/ptf-test/test.py new file mode 100644 index 0000000..be79ed0 --- /dev/null +++ b/bloomfilter/ptf-test/test.py @@ -0,0 +1,233 @@ +################################################################################ +# BAREFOOT NETWORKS CONFIDENTIAL & PROPRIETARY +# +# Copyright (c) 2018-2019 Barefoot Networks, Inc. + +# All Rights Reserved. +# +# NOTICE: All information contained herein is, and remains the property of +# Barefoot Networks, Inc. and its suppliers, if any. The intellectual and +# technical concepts contained herein are proprietary to Barefoot Networks, +# Inc. +# and its suppliers and may be covered by U.S. and Foreign Patents, patents in +# process, and are protected by trade secret or copyright law. +# Dissemination of this information or reproduction of this material is +# strictly forbidden unless prior written permission is obtained from +# Barefoot Networks, Inc. +# +# No warranty, explicit or implicit is provided, unless granted under a +# written agreement with Barefoot Networks, Inc. +# +# +############################################################################### + + +""" +Simple PTF test for simple_l3_nexthop +""" + +######### STANDARD MODULE IMPORTS ######## +import logging +import grpc +import pdb + +######### PTF modules for BFRuntime Client Library APIs ####### +import ptf +from ptf.testutils import * +from bfruntime_client_base_tests import BfRuntimeTest +import bfrt_grpc.bfruntime_pb2 as bfruntime_pb2 +import bfrt_grpc.client as gc +import bfrt_grpc.info_parse + +########## Basic Initialization ############ +class BaseProgramTest(BfRuntimeTest): + # The setUp() method is used to prepare the test fixture. Typically + # you would use it to establich connection to the gRPC Server + # + # You can also put the initial device configuration there. However, + # if during this process an error is encountered, it will be considered + # as a test error (meaning the test is incorrect), + # rather than a test failure + # + # Here is the stuff we set up that is ready to use + # client_id + # p4_name + # bfrt_info + # dev + # dev_tgt + # allports + # tables -- the list of tables + # Individual tables of the program with short names + # ipv4_host + # ipv4_lpm + # nexthop + def setUp(self): + self.client_id = 0 + self.p4_name = "silkroad_bf" + self.dev = 0 + self.dev_tgt = gc.Target(self.dev, pipe_id=0xFFFF) + + print("\n") + print("Test Setup") + print("==========") + + BfRuntimeTest.setUp(self, self.client_id, self.p4_name) + self.bfrt_info = self.interface.bfrt_info_get(self.p4_name) + + print(" Connected to Device: {}, Program: {}, ClientId: {}".format( + self.dev, self.p4_name, self.client_id)) + + # Since this class is not a test per se, we can use the setup method + # for common setup. For example, we can have our tables and annotations + # ready + # example : self. = self.bfrt_info.table_get("Ingress.") + self.conn = self.bfrt_info.table_get("Ingress.conn") + self.transit = self.bfrt_info.table_get("Ingress.transit") + + self.vip = self.bfrt_info.table_get("Ingress.vip") + self.vip.info.key_field_annotation_add( + "hdr.ipv4.dst_addr", "ipv4") + + self.tables = [ self.conn, self.vip, self.transit ] + + # Create a list of all ports available on the device + self.swports = [] + for (device, port, ifname) in ptf.config['interfaces']: + self.swports.append(port) + self.swports.sort() + + # Optional, but highly recommended + self.cleanUp() + + # Use Cleanup Method to clear the tables before and after the test starts + # (the latter is done as a part of tearDown() + def cleanUp(self): + print("\n") + print("Table Cleanup:") + print("==============") + + try: + for t in self.tables: + print(" Clearing Table {}".format(t.info.name_get())) + keys = [] + for (d, k) in t.entry_get(self.dev_tgt): + if k is not None: + keys.append(k) + t.entry_del(self.dev_tgt, keys) + # Not all tables support default entry + try: + t.default_entry_reset(self.dev_tgt) + except: + pass + except Exception as e: + print("Error cleaning up: {}".format(e)) + + # Use tearDown() method to return the DUT to the initial state by cleaning + # all the configuration and clearing up the connection + def tearDown(self): + print("\n") + print("Test TearDown:") + print("==============") + + self.cleanUp() + + # Call the Parent tearDown + BfRuntimeTest.tearDown(self) + +# +# Individual tests can now be subclassed from BaseProgramTest +# + +############################################################################ +################# I N D I V I D U A L T E S T S ######################### +############################################################################ + +class BloomFilter(BaseProgramTest): + def runTest(self): + # = test_param_get(, ); + conn_digest = test_param_get("conn_digest", 0xF586) + unwritten_conn_digest = test_param_get("unwritten_conn_digest", 0x6317) + set_one = test_param_get("set_one", 1) + set_zero = test_param_get("set_zero", 0) + ingress_port = 0 + miss_bf_port = 5 + hit_bf_port = 10 + + print("\n") + print("Test Run") + print("========") + + # Program an entry in transit: conn -> set_opt(1, 0) + key = self.transit.make_key([gc.KeyTuple('meta.conn_digest', conn_digest)]) + + data = self.transit.make_data([gc.DataTuple('is_insert', set_one), gc.DataTuple('is_checkout', set_zero)], "Ingress.set_opt") + + self.transit.entry_add(self.dev_tgt, [key], [data]); + print(" Added an entry to transit: {} -> {},{}".format( + conn_digest, set_one, set_zero)) + + # Send a test packet to write the connction into bloom filter + print(" Sending a packet to write 'Connection 192.168.1.3->192.168.2.3 tcp 222->666' into the bloom filter") + pkt = simple_tcp_packet(eth_dst="00:98:76:54:32:10", + eth_src='00:55:55:55:55:55', + ip_src='192.168.1.3', + ip_dst='192.168.2.3', + ip_id=101, + ip_ttl=64, + ip_ihl=5, + tcp_flags="S", + tcp_sport=222, + tcp_dport=666) + send_packet(self, ingress_port, pkt) + verify_packet(self, pkt, miss_bf_port) + + # Modify the entry in transit: conn -> set_opt(0, 1) + data = self.transit.make_data([gc.DataTuple('is_insert', set_zero), gc.DataTuple('is_checkout', set_one)], "Ingress.set_opt") + self.transit.entry_mod(self.dev_tgt, [key], [data]); + print(" Modified the entry in transit: {} -> {},{}".format( + conn_digest, set_zero, set_one)) + + # Add an entry which was't written into the bloom filter to transit:conn -> set_opt(0,1) + key = self.transit.make_key([ + gc.KeyTuple('meta.conn_digest', unwritten_conn_digest)]) + + data = self.transit.make_data([gc.DataTuple('is_insert', set_zero), gc.DataTuple('is_checkout', set_one)], "Ingress.set_opt") + + self.transit.entry_add(self.dev_tgt, [key], [data]); + print(" Added an entry to transit(it's not in the bloom filter): {} -> {},{}".format( + unwritten_conn_digest, set_zero, set_one)) + + # Send the same test packet to hit the bloom filter + print(" Sending a packet to check whether 'Connection 192.168.1.3->192.168.2.3 tcp 222->666' is in the bloom filter") + pkt = simple_tcp_packet(eth_dst="00:98:76:54:32:10", + eth_src='00:55:55:55:55:55', + ip_src='192.168.1.3', + ip_dst='192.168.2.3', + ip_id=101, + ip_ttl=64, + ip_ihl=5, + tcp_flags="S", + tcp_sport=222, + tcp_dport=666) + send_packet(self, ingress_port, pkt) + verify_packet(self, pkt, hit_bf_port) + print(" The Connection '192.168.1.3->192.168.2.3 tcp 222->666' is in the bloom filter.") + + #Send another packet to prove it isn't in the bloom filter + print(" Sending a packet to check whether 'Connection 192.168.1.4->192.168.2.4 tcp 444->888' is in the bloom filter") + pkt = simple_tcp_packet(eth_dst="00:98:76:54:32:10", + eth_src='00:55:55:55:55:55', + ip_src='192.168.1.4', + ip_dst='192.168.2.4', + ip_id=101, + ip_ttl=64, + ip_ihl=5, + tcp_flags="S", + tcp_sport=444, + tcp_dport=888) + send_packet(self, ingress_port, pkt) + verify_packet(self, pkt, miss_bf_port) + print(" The Connection '192.168.1.4->192.168.2.4 tcp 444->888' is not in the bloom filter.") + + + -- cgit v1.2.3