summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bloomfilter/P4 Bloom Filter设计文档(基于Silkroad中的设计).md136
-rw-r--r--bloomfilter/cmd.txt16
-rw-r--r--bloomfilter/image/1.jpgbin0 -> 82071 bytes
-rw-r--r--bloomfilter/image/2.pngbin0 -> 129374 bytes
-rw-r--r--bloomfilter/p4src/silkroad_bf.p4466
-rw-r--r--bloomfilter/ptf-test/test.py233
6 files changed, 851 insertions, 0 deletions
diff --git a/bloomfilter/P4 Bloom Filter设计文档(基于Silkroad中的设计).md b/bloomfilter/P4 Bloom Filter设计文档(基于Silkroad中的设计).md
new file mode 100644
index 0000000..e9ee3a9
--- /dev/null
+++ b/bloomfilter/P4 Bloom Filter设计文档(基于Silkroad中的设计).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<bit<32>>(HashAlgorithm_t.CRC16) bfhash_crc16;
+ Hash<bit<32>>(HashAlgorithm_t.CRC32) bfhash_crc32;
+```
+
+3)由于在一个周期只能对寄存器进行一次操作,所以创建两个寄存器实例,用于存储对应索引位置的存在位(值为1),num_boxes为寄存器槽的个数,第一个bit<8>为每个槽的大小,第二个bit<8>为索引大小;
+
+```C
+ Register<bit<8>,bit<8>>(num_boxes) crc16_set;
+ Register<bit<8>,bit<8>>(num_boxes) crc32_set;
+```
+
+4)在TNA架构下对寄存器进行操作不可以使用write()和read(),必须使用在tofino.p4和tofino2.p4中提供的RegisterAction。对每个寄存器实例分别创建读写操作的RegisterAction,用于BloomFilter的写入和查询;
+
+```C
+ RegisterAction<bit<8>, 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>, 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<bit<16>>(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
--- /dev/null
+++ b/bloomfilter/image/1.jpg
Binary files differ
diff --git a/bloomfilter/image/2.png b/bloomfilter/image/2.png
new file mode 100644
index 0000000..223b7da
--- /dev/null
+++ b/bloomfilter/image/2.png
Binary files 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 <core.p4>
+#include <tna.p4>
+
+/*************************************************************************
+ ************* 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<bit<32>>(HashAlgorithm_t.CRC16) bfhash_crc16;
+ Hash<bit<32>>(HashAlgorithm_t.CRC32) bfhash_crc32;
+
+ /* Register<T,I>(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>,bit<8>>(num_boxes) crc16_set;
+ RegisterAction<bit<8>, 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>, bit<8>>(crc16_set) crc16_checkout = {
+ void apply(inout bit<8> value, out bit<8> ret){
+ ret = value;
+ }
+ };
+
+ //hash_2 crc32
+ Register<bit<8>,bit<8>>(num_boxes) crc32_set;
+ RegisterAction<bit<8>, 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>, 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<bit<16>>(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.<table_name> = self.bfrt_info.table_get("Ingress.<table_name>")
+ 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):
+ # <variable_name> = test_param_get(<key>, <value>);
+ 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.")
+
+
+