summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.DS_Storebin0 -> 8196 bytes
-rw-r--r--README.md9
-rw-r--r--bfrt_python/setup.py113
-rw-r--r--p4src/.DS_Storebin0 -> 6148 bytes
-rw-r--r--p4src/super_vlan_0409.p4566
-rw-r--r--p4src/super_vlan_0410.p4566
-rw-r--r--pkt/subin_test.py25
-rw-r--r--pkt/twosub_test.py23
-rw-r--r--ptf/.DS_Storebin0 -> 6148 bytes
-rw-r--r--ptf/test0410.py836
10 files changed, 2138 insertions, 0 deletions
diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..24bee69
--- /dev/null
+++ b/.DS_Store
Binary files differ
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..443ca31
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+1. ./run_bfshell.sh -b ~/labs/super_vlan/bfrt_python/setup.py
+## 测试两个sub_vlan之间ARP
+2. sudo ip addr add 192.168.1.254/24 dev veth3
+3. sudo scapy
+4. p = sr1(ARP(psrc='192.168.1.13',pdst='192.168.1.1'))
+
+## 测试同一个sub_vlan二层通信
+5. 进入到/super_vlan/pkt/目录
+6. 运行发送数据包的脚本:sudo python ./subin_send.py \ No newline at end of file
diff --git a/bfrt_python/setup.py b/bfrt_python/setup.py
new file mode 100644
index 0000000..5010594
--- /dev/null
+++ b/bfrt_python/setup.py
@@ -0,0 +1,113 @@
+from ipaddress import ip_address
+
+p4 = bfrt.super_vlan_test.pipe
+
+# This function can clear all the tables and later on other fixed objects
+# once bfrt support is added.
+def clear_all(verbose=True, batching=True):
+ global p4
+ global bfrt
+
+ def _clear(table, verbose=False, batching=False):
+ if verbose:
+ print("Clearing table {:<40} ... ".
+ format(table['full_name']), end='', flush=True)
+ try:
+ entries = table['node'].get(regex=True, print_ents=False)
+ try:
+ if batching:
+ bfrt.batch_begin()
+ for entry in entries:
+ entry.remove()
+ except Exception as e:
+ print("Problem clearing table {}: {}".format(
+ table['name'], e.sts))
+ finally:
+ if batching:
+ bfrt.batch_end()
+ except Exception as e:
+ if e.sts == 6:
+ if verbose:
+ print('(Empty) ', end='')
+ finally:
+ if verbose:
+ print('Done')
+
+ # Optionally reset the default action, but not all tables
+ # have that
+ try:
+ table['node'].reset_default()
+ except:
+ pass
+
+ # The order is important. We do want to clear from the top, i.e.
+ # delete objects that use other objects, e.g. table entries use
+ # selector groups and selector groups use action profile members
+
+
+ # Clear Match Tables
+ for table in p4.info(return_info=True, print_info=False):
+ if table['type'] in ['MATCH_DIRECT', 'MATCH_INDIRECT_SELECTOR']:
+ _clear(table, verbose=verbose, batching=batching)
+
+ # Clear Selectors
+ for table in p4.info(return_info=True, print_info=False):
+ if table['type'] in ['SELECTOR']:
+ _clear(table, verbose=verbose, batching=batching)
+
+ # Clear Action Profiles
+ for table in p4.info(return_info=True, print_info=False):
+ if table['type'] in ['ACTION_PROFILE']:
+ _clear(table, verbose=verbose, batching=batching)
+
+#clear_all()
+
+is_l2_switch = p4.Ingress.is_l2_switch
+is_l2_switch.add_with_l2_switch(dst_addr=0x000002000002, port=11)
+is_l2_switch.add_with_set_l3_flag(dst_addr=0xFFFFFFFFFFFF)
+
+Port_to_srcvid = p4.Ingress.Port_to_srcvid
+Port_to_srcvid.add_with_set_src_vid(ingress_port=0, subvid=2, supervid=10)
+
+dstIP_to_dstvid = p4.Ingress.dstIP_to_dstvid
+dstIP_to_dstvid.add_with_set_dst_vid(dst_addr=ip_address('192.168.1.1'), subvid=3, supervid=10)
+
+src_supervid_to_mac = p4.Ingress.src_supervid_to_mac
+src_supervid_to_mac.add_with_set_super_MAC(src_supervid=10, new_mac_switch=0x00000A00000A)
+
+ipv4_host = p4.Ingress.ipv4_host
+ipv4_host.add_with_set_nexthop(
+ same_flag=True, dst_addr=ip_address('192.168.1.2'), nexthop=0)
+ipv4_host.add_with_set_nexthop(
+ same_flag=False, dst_addr=ip_address('192.168.1.1'), nexthop=100)
+
+ipv4_lpm = p4.Ingress.ipv4_lpm
+ipv4_lpm.add_with_set_nexthop(
+ same_flag=True, dst_addr=ip_address('192.168.1.0'), dst_addr_p_length=24, nexthop=0)
+
+nexthop = p4.Ingress.nexthop
+nexthop.add_with_send(nexthop_id=0)
+nexthop.add_with_l3_switch(nexthop_id=100,port=2, new_mac_da=0x000003000003,new_mac_sa=0x00000A00000A)
+
+bfrt.complete_operations()
+
+# Final programming
+print("""
+******************* PROGAMMING RESULTS *****************
+""")
+print ("Table is_l2_switch:")
+is_l2_switch.dump(table=True)
+print ("Table Port_to_srcvid:")
+Port_to_srcvid.dump(table=True)
+print ("Table dstIP_to_dstvid:")
+dstIP_to_dstvid.dump(table=True)
+print ("Table src_supervid_to_mac:")
+src_supervid_to_mac.dump(table=True)
+print ("Table ipv4_host:")
+ipv4_host.dump(table=True)
+print ("Table ipv4_lpm:")
+ipv4_lpm.dump(table=True)
+print ("Table nexthop:")
+nexthop.dump(table=True)
+
+
diff --git a/p4src/.DS_Store b/p4src/.DS_Store
new file mode 100644
index 0000000..12edfb5
--- /dev/null
+++ b/p4src/.DS_Store
Binary files differ
diff --git a/p4src/super_vlan_0409.p4 b/p4src/super_vlan_0409.p4
new file mode 100644
index 0000000..638928d
--- /dev/null
+++ b/p4src/super_vlan_0409.p4
@@ -0,0 +1,566 @@
+/* -*- 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 *******************
+*************************************************************************/
+
+/* Header Stuff */
+enum bit<16> ether_type_t {
+ TPID = 0x8100,
+ IPV4 = 0x0800,
+ ARP = 0x0806,
+ IPV6 = 0x86DD,
+ MPLS = 0x8847
+}
+
+enum bit<8> ip_protocol_t {
+ ICMP = 1,
+ IGMP = 2,
+ TCP = 6,
+ UDP = 17
+}
+
+enum bit<16> arp_opcode_t {
+ REQUEST = 1,
+ REPLY = 2
+}
+
+
+enum bit<8> icmp_type_t {
+ ECHO_REPLY = 0,
+ ECHO_REQUEST = 8
+}
+
+typedef bit<48> mac_addr_t;
+typedef bit<32> ipv4_addr_t;
+
+/* Metadata and Table Stuff */
+const int IPV4_HOST_SIZE = 65536;
+const int IPV4_LPM_SIZE = 12288;
+
+#define NEXTHOP_ID_WIDTH 14
+#define SUBVLAN_ID_WIDTH 12
+#define SUPERVLAN_ID_WIDTH 8
+typedef bit<NEXTHOP_ID_WIDTH> nexthop_id_t;
+const int NEXTHOP_SIZE = 1 << NEXTHOP_ID_WIDTH;
+typedef bit<SUBVLAN_ID_WIDTH> subvlan_id_t;
+typedef bit<SUPERVLAN_ID_WIDTH> supervlan_id_t;
+const int VLAN_SIZE = 512;
+
+/*************************************************************************
+ *********************** 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_h {
+ mac_addr_t dst_addr;
+ mac_addr_t src_addr;
+ ether_type_t ether_type;
+}
+
+header vlan_tag_h {
+ bit<3> pcp;
+ bit<1> cfi;
+ bit<12> vid;
+ ether_type_t ether_type;
+}
+
+header ipv4_h {
+ 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;
+ ip_protocol_t protocol;
+ bit<16> hdr_checksum;
+ ipv4_addr_t src_addr;
+ ipv4_addr_t dst_addr;
+}
+
+header ipv4_options_h {
+ varbit<320> data;
+}
+
+header icmp_h {
+ icmp_type_t msg_type;
+ bit<8> msg_code;
+ bit<16> checksum;
+}
+
+header arp_h {
+ bit<16> hw_type;
+ ether_type_t proto_type;
+ bit<8> hw_addr_len;
+ bit<8> proto_addr_len;
+ arp_opcode_t opcode;
+}
+
+header arp_ipv4_h {
+ mac_addr_t src_hw_addr;
+ ipv4_addr_t src_proto_addr;
+ mac_addr_t dst_hw_addr;
+ ipv4_addr_t dst_proto_addr;
+}
+
+
+
+/*************************************************************************
+ ************** 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_h ethernet;
+ vlan_tag_h[2] vlan_tag;
+ arp_h arp;
+ arp_ipv4_h arp_ipv4;
+ ipv4_h ipv4;
+ icmp_h icmp;
+}
+
+ /****** 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 {
+ ipv4_addr_t dst_ipv4;
+ mac_addr_t dst_mac;
+ subvlan_id_t src_subvid;
+ bit<1> ipv4_csum_err;
+}
+
+ /*********************** 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)
+{
+ Checksum() ipv4_checksum;
+
+ /* 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.ipv4_csum_err = 0;
+ meta.dst_ipv4 = 0;
+ meta.dst_mac = 0;
+ transition parse_ethernet;
+ }
+
+ state parse_ethernet {
+ pkt.extract(hdr.ethernet);
+ transition select(hdr.ethernet.ether_type) {
+ ether_type_t.TPID : parse_vlan_tag;
+ ether_type_t.IPV4 : parse_ipv4;
+ ether_type_t.ARP : parse_arp;
+ default: accept;
+ }
+ }
+
+ state parse_vlan_tag {
+ pkt.extract(hdr.vlan_tag.next);
+ transition select(hdr.vlan_tag.last.ether_type) {
+ ether_type_t.TPID : parse_vlan_tag;
+ ether_type_t.IPV4 : parse_ipv4;
+ ether_type_t.ARP : parse_arp;
+ default: accept;
+ }
+ }
+
+ state parse_ipv4 {
+ pkt.extract(hdr.ipv4);
+ meta.dst_ipv4 = hdr.ipv4.dst_addr;
+
+ ipv4_checksum.add(hdr.ipv4);
+ meta.ipv4_csum_err = (bit<1>)ipv4_checksum.verify();
+
+ transition select(
+ hdr.ipv4.ihl,
+ hdr.ipv4.frag_offset,
+ hdr.ipv4.protocol)
+ {
+ (5, 0, ip_protocol_t.ICMP) : parse_icmp;
+ default: accept;
+ }
+ }
+
+ state parse_icmp {
+ pkt.extract(hdr.icmp);
+ transition accept;
+ }
+
+ state parse_arp {
+ pkt.extract(hdr.arp);
+ transition select(hdr.arp.hw_type, hdr.arp.proto_type) {
+ (0x0001, ether_type_t.IPV4) : parse_arp_ipv4;
+ default: reject; // Currently the same as accept
+ }
+ }
+
+ state parse_arp_ipv4 {
+ pkt.extract(hdr.arp_ipv4);
+ meta.dst_ipv4 = hdr.arp_ipv4.dst_proto_addr;
+ transition accept;
+ }
+}
+
+ /***************** 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)
+{
+ nexthop_id_t nexthop_id = 0;
+ mac_addr_t mac_da = 0;
+ mac_addr_t mac_sa = 0;
+ PortId_t egress_port = 511; /* Non-existent port */
+ bit<8> ttl_dec = 0;
+ subvlan_id_t tmp_vid = 0;
+ subvlan_id_t src_subvid = 0;
+ subvlan_id_t dst_subvid = 0;
+ supervlan_id_t src_supervid = 0;
+ supervlan_id_t dst_supervid = 0;
+ supervlan_id_t tmp_supervid = 0;
+ bool same_flag = false;
+ bool l3_flag = false;
+ bit<48> switch_mac = 0;
+
+ action l2_switch(PortId_t port){
+ egress_port = port;
+ mac_da = hdr.ethernet.dst_addr;
+ mac_sa = hdr.ethernet.src_addr;
+ ttl_dec = 0;
+ }
+ action set_l3_flag(){
+ l3_flag = true;
+ }
+
+ table is_l2_switch {
+ key = {
+ hdr.ethernet.dst_addr : exact;
+ }
+ actions = {l2_switch; set_l3_flag;@defaultonly NoAction;}
+ size = 512;
+ const default_action = NoAction();
+ }
+
+
+ action set_trunk_port(PortId_t port){
+ egress_port = port;
+ mac_da = hdr.ethernet.dst_addr;
+ mac_sa = hdr.ethernet.src_addr;
+ ttl_dec = 0;
+ }
+ action drop() {
+ ig_dprsr_md.drop_ctl = 1;
+ }
+
+ table Trunk_switch{
+ key = {
+ hdr.ethernet.dst_addr : exact;
+ }
+ actions = {set_trunk_port; drop;}
+ size = 512;
+ default_action = drop();
+ }
+
+
+ action set_src_vid(subvlan_id_t subvid, supervlan_id_t supervid){
+ meta.src_subvid = subvid;
+ src_supervid = supervid;
+ }
+ table Port_to_srcvid {
+ key = {ig_intr_md.ingress_port : exact;}
+ actions = {set_src_vid; @defaultonly NoAction; }
+ size = VLAN_SIZE;
+ const default_action = NoAction();
+ }
+
+
+ action set_dst_vid(subvlan_id_t subvid, supervlan_id_t supervid){
+ dst_subvid = subvid;
+ dst_supervid = supervid;
+ }
+ table dstIP_to_dstvid {
+ key = {
+ hdr.ipv4.dst_addr : exact;
+ }
+ actions = {set_dst_vid; @defaultonly NoAction; }
+ size = 512;
+ const default_action = NoAction();
+ }
+
+
+ action set_super_MAC(bit<48> new_mac_switch){
+ switch_mac = new_mac_switch;
+ }
+ table src_supervid_to_mac{
+ key = {
+ src_supervid : exact;
+ }
+ actions = {set_super_MAC; @defaultonly NoAction; }
+ size = 512;
+ const default_action = NoAction();
+ }
+
+/****************** IPv4 Lookup ********************/
+ action set_nexthop(nexthop_id_t nexthop) {
+ nexthop_id = nexthop;
+ }
+
+ table ipv4_host {
+ key = {
+ same_flag : exact;
+ hdr.ipv4.dst_addr : exact;
+ }
+ actions = { set_nexthop; @defaultonly NoAction; }
+ size = IPV4_HOST_SIZE;
+ const default_action = NoAction();
+ }
+
+ table ipv4_lpm {
+ key = {
+ same_flag : exact;
+ hdr.ipv4.dst_addr : lpm;
+ }
+ actions = { set_nexthop; }
+
+ default_action = set_nexthop(0);
+ size = IPV4_LPM_SIZE;
+ }
+
+ /****************** Nexthop ********************/
+ action send(PortId_t port) {
+ mac_da = hdr.ethernet.dst_addr;
+ mac_sa = hdr.ethernet.src_addr;
+ egress_port = port;
+ ttl_dec = 0;
+ }
+
+ action l3_switch(PortId_t port, bit<48> new_mac_da, bit<48> new_mac_sa) {
+ mac_da = new_mac_da;
+ mac_sa = new_mac_sa; /*目的ip对应的交换机MAC*/
+ egress_port = port;
+ ttl_dec = 1;
+ }
+
+ table nexthop {
+ key = { nexthop_id : exact; }
+ actions = { send; drop; l3_switch; }
+ size = NEXTHOP_SIZE;
+ default_action = drop();
+ }
+
+ /****************** Metadata Processing ********************/
+ action send_back() {
+ ig_tm_md.ucast_egress_port = ig_intr_md.ingress_port;
+ }
+
+ action forward_ipv4() {
+ hdr.ethernet.dst_addr = mac_da;
+ hdr.ethernet.src_addr = mac_sa;
+ hdr.ipv4.ttl = hdr.ipv4.ttl |-| ttl_dec;
+ ig_tm_md.ucast_egress_port = egress_port;
+ }
+
+ action send_arp_reply_in() {
+ hdr.ethernet.dst_addr = hdr.arp_ipv4.src_hw_addr;
+ hdr.ethernet.src_addr = mac_da; /*ARP请求同一个sub_vlan中的主机MAC,把主机的真实MAC作为源MAC回复*/
+
+ hdr.arp.opcode = arp_opcode_t.REPLY;
+ hdr.arp_ipv4.dst_hw_addr = hdr.arp_ipv4.src_hw_addr;
+ hdr.arp_ipv4.dst_proto_addr = hdr.arp_ipv4.src_proto_addr;
+ hdr.arp_ipv4.src_hw_addr = mac_da;
+ hdr.arp_ipv4.src_proto_addr = meta.dst_ipv4;
+
+ send_back();
+ }
+
+ action send_arp_reply_out() {
+ hdr.ethernet.dst_addr = hdr.arp_ipv4.src_hw_addr;
+ hdr.ethernet.src_addr = switch_mac; /*ARP请求不同sub_vlan中的主机MAC,把交换机的MAC作为源MAC回复*/
+
+ hdr.arp.opcode = arp_opcode_t.REPLY;
+ hdr.arp_ipv4.dst_hw_addr = hdr.arp_ipv4.src_hw_addr;
+ hdr.arp_ipv4.dst_proto_addr = hdr.arp_ipv4.src_proto_addr;
+ hdr.arp_ipv4.src_hw_addr = mac_sa;
+ hdr.arp_ipv4.src_proto_addr = meta.dst_ipv4;
+
+ send_back();
+ }
+
+ table forward_or_respond {
+ key = {
+ same_flag : exact;
+ hdr.arp.isValid() : exact;
+ hdr.arp_ipv4.isValid() : exact;
+ hdr.ipv4.isValid() : exact;
+ hdr.arp.opcode : ternary;
+ }
+ actions = {
+ forward_ipv4;
+ send_arp_reply_in;
+ send_arp_reply_out;
+ drop;
+ }
+ const entries = {
+ (true, false, false, true, _) :
+ forward_ipv4();
+ (false, false, false, true, _) :
+ forward_ipv4();
+ (true, true, true, false, arp_opcode_t.REQUEST) :
+ send_arp_reply_in();
+ (false, true, true, false, arp_opcode_t.REQUEST) :
+ send_arp_reply_out();
+ }
+ default_action = drop();
+ }
+
+ apply{
+ if(meta.ipv4_csum_err == 0){
+ if(!is_l2_switch.apply().hit){
+ Trunk_switch.apply();
+ }
+ if(!l3_flag){
+ same_flag = true;
+ }
+ if(!same_flag){
+ Port_to_srcvid.apply();
+ dstIP_to_dstvid.apply();
+ if((src_supervid == dst_supervid)&&(meta.src_subvid == dst_subvid)){
+ same_flag = true;
+ }
+ src_supervid_to_mac.apply();
+ if (!ipv4_host.apply().hit) {
+ ipv4_lpm.apply();
+ }
+ nexthop.apply();
+ }
+ forward_or_respond.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)
+{
+ Checksum() ipv4_checksum;
+
+ apply {
+ hdr.ipv4.hdr_checksum = ipv4_checksum.update({
+ hdr.ipv4.version,
+ hdr.ipv4.ihl,
+ hdr.ipv4.diffserv,
+ hdr.ipv4.total_len,
+ hdr.ipv4.identification,
+ hdr.ipv4.flags,
+ hdr.ipv4.frag_offset,
+ hdr.ipv4.ttl,
+ hdr.ipv4.protocol,
+ hdr.ipv4.src_addr,
+ hdr.ipv4.dst_addr
+ /* Adding hdr.ipv4_options.data results in an error */
+ });
+ 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 {
+}
+
+ /******** 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/p4src/super_vlan_0410.p4 b/p4src/super_vlan_0410.p4
new file mode 100644
index 0000000..1a2da7d
--- /dev/null
+++ b/p4src/super_vlan_0410.p4
@@ -0,0 +1,566 @@
+/* -*- 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 *******************
+*************************************************************************/
+
+/* Header Stuff */
+enum bit<16> ether_type_t {
+ TPID = 0x8100,
+ IPV4 = 0x0800,
+ ARP = 0x0806,
+ IPV6 = 0x86DD,
+ MPLS = 0x8847
+}
+
+enum bit<8> ip_protocol_t {
+ ICMP = 1,
+ IGMP = 2,
+ TCP = 6,
+ UDP = 17
+}
+
+enum bit<16> arp_opcode_t {
+ REQUEST = 1,
+ REPLY = 2
+}
+
+
+enum bit<8> icmp_type_t {
+ ECHO_REPLY = 0,
+ ECHO_REQUEST = 8
+}
+
+typedef bit<48> mac_addr_t;
+typedef bit<32> ipv4_addr_t;
+
+/* Metadata and Table Stuff */
+const int IPV4_HOST_SIZE = 65536;
+const int IPV4_LPM_SIZE = 12288;
+
+#define NEXTHOP_ID_WIDTH 14
+#define SUBVLAN_ID_WIDTH 12
+#define SUPERVLAN_ID_WIDTH 8
+typedef bit<NEXTHOP_ID_WIDTH> nexthop_id_t;
+const int NEXTHOP_SIZE = 1 << NEXTHOP_ID_WIDTH;
+typedef bit<SUBVLAN_ID_WIDTH> subvlan_id_t;
+typedef bit<SUPERVLAN_ID_WIDTH> supervlan_id_t;
+const int VLAN_SIZE = 512;
+
+/*************************************************************************
+ *********************** 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_h {
+ mac_addr_t dst_addr;
+ mac_addr_t src_addr;
+ ether_type_t ether_type;
+}
+
+header vlan_tag_h {
+ bit<3> pcp;
+ bit<1> cfi;
+ bit<12> vid;
+ ether_type_t ether_type;
+}
+
+header ipv4_h {
+ 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;
+ ip_protocol_t protocol;
+ bit<16> hdr_checksum;
+ ipv4_addr_t src_addr;
+ ipv4_addr_t dst_addr;
+}
+
+header ipv4_options_h {
+ varbit<320> data;
+}
+
+header icmp_h {
+ icmp_type_t msg_type;
+ bit<8> msg_code;
+ bit<16> checksum;
+}
+
+header arp_h {
+ bit<16> hw_type;
+ ether_type_t proto_type;
+ bit<8> hw_addr_len;
+ bit<8> proto_addr_len;
+ arp_opcode_t opcode;
+}
+
+header arp_ipv4_h {
+ mac_addr_t src_hw_addr;
+ ipv4_addr_t src_proto_addr;
+ mac_addr_t dst_hw_addr;
+ ipv4_addr_t dst_proto_addr;
+}
+
+
+
+/*************************************************************************
+ ************** 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_h ethernet;
+ vlan_tag_h[2] vlan_tag;
+ arp_h arp;
+ arp_ipv4_h arp_ipv4;
+ ipv4_h ipv4;
+ icmp_h icmp;
+}
+
+ /****** 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 {
+ ipv4_addr_t dst_ipv4;
+ mac_addr_t dst_mac;
+ subvlan_id_t src_subvid;
+ bit<1> ipv4_csum_err;
+}
+
+ /*********************** 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)
+{
+ Checksum() ipv4_checksum;
+
+ /* 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.ipv4_csum_err = 0;
+ meta.dst_ipv4 = 0;
+ meta.dst_mac = 0;
+ transition parse_ethernet;
+ }
+
+ state parse_ethernet {
+ pkt.extract(hdr.ethernet);
+ transition select(hdr.ethernet.ether_type) {
+ ether_type_t.TPID : parse_vlan_tag;
+ ether_type_t.IPV4 : parse_ipv4;
+ ether_type_t.ARP : parse_arp;
+ default: accept;
+ }
+ }
+
+ state parse_vlan_tag {
+ pkt.extract(hdr.vlan_tag.next);
+ transition select(hdr.vlan_tag.last.ether_type) {
+ ether_type_t.TPID : parse_vlan_tag;
+ ether_type_t.IPV4 : parse_ipv4;
+ ether_type_t.ARP : parse_arp;
+ default: accept;
+ }
+ }
+
+ state parse_ipv4 {
+ pkt.extract(hdr.ipv4);
+ meta.dst_ipv4 = hdr.ipv4.dst_addr;
+
+ ipv4_checksum.add(hdr.ipv4);
+ meta.ipv4_csum_err = (bit<1>)ipv4_checksum.verify();
+
+ transition select(
+ hdr.ipv4.ihl,
+ hdr.ipv4.frag_offset,
+ hdr.ipv4.protocol)
+ {
+ (5, 0, ip_protocol_t.ICMP) : parse_icmp;
+ default: accept;
+ }
+ }
+
+ state parse_icmp {
+ pkt.extract(hdr.icmp);
+ transition accept;
+ }
+
+ state parse_arp {
+ pkt.extract(hdr.arp);
+ transition select(hdr.arp.hw_type, hdr.arp.proto_type) {
+ (0x0001, ether_type_t.IPV4) : parse_arp_ipv4;
+ default: reject; // Currently the same as accept
+ }
+ }
+
+ state parse_arp_ipv4 {
+ pkt.extract(hdr.arp_ipv4);
+ meta.dst_ipv4 = hdr.arp_ipv4.dst_proto_addr;
+ transition accept;
+ }
+}
+
+ /***************** 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)
+{
+ nexthop_id_t nexthop_id = 0;
+ mac_addr_t mac_da = 0;
+ mac_addr_t mac_sa = 0;
+ PortId_t egress_port = 511; /* Non-existent port */
+ bit<8> ttl_dec = 0;
+ subvlan_id_t tmp_vid = 0;
+ subvlan_id_t src_subvid = 0;
+ subvlan_id_t dst_subvid = 0;
+ supervlan_id_t src_supervid = 0;
+ supervlan_id_t dst_supervid = 0;
+ supervlan_id_t tmp_supervid = 0;
+ bool same_flag = false;
+ bool l3_flag = false;
+ bit<48> switch_mac = 0;
+
+ action l2_switch(PortId_t port){
+ egress_port = port;
+ mac_da = hdr.ethernet.dst_addr;
+ mac_sa = hdr.ethernet.src_addr;
+ ttl_dec = 0;
+ }
+ action set_l3_flag(){
+ l3_flag = true;
+ }
+
+ table is_l2_switch {
+ key = {
+ hdr.ethernet.dst_addr : exact;
+ }
+ actions = {l2_switch; set_l3_flag;@defaultonly NoAction;}
+ size = 512;
+ const default_action = NoAction();
+ }
+
+
+ action set_trunk_port(PortId_t port){
+ egress_port = port;
+ mac_da = hdr.ethernet.dst_addr;
+ mac_sa = hdr.ethernet.src_addr;
+ ttl_dec = 0;
+ }
+ action drop() {
+ ig_dprsr_md.drop_ctl = 1;
+ }
+
+ table Trunk_switch{
+ key = {
+ hdr.ethernet.dst_addr : exact;
+ }
+ actions = {set_trunk_port; drop;}
+ size = 512;
+ default_action = drop();
+ }
+
+
+ action set_src_vid(subvlan_id_t subvid, supervlan_id_t supervid){
+ meta.src_subvid = subvid;
+ src_supervid = supervid;
+ }
+ table Port_to_srcvid {
+ key = {ig_intr_md.ingress_port : exact;}
+ actions = {set_src_vid; @defaultonly NoAction; }
+ size = VLAN_SIZE;
+ const default_action = NoAction();
+ }
+
+
+ action set_dst_vid(subvlan_id_t subvid, supervlan_id_t supervid){
+ dst_subvid = subvid;
+ dst_supervid = supervid;
+ }
+ table dstIP_to_dstvid {
+ key = {
+ meta.dst_ipv4 : exact;
+ }
+ actions = {set_dst_vid; @defaultonly NoAction; }
+ size = 512;
+ const default_action = NoAction();
+ }
+
+
+ action set_super_MAC(bit<48> new_mac_switch){
+ switch_mac = new_mac_switch;
+ }
+ table src_supervid_to_mac{
+ key = {
+ src_supervid : exact;
+ }
+ actions = {set_super_MAC; @defaultonly NoAction; }
+ size = 512;
+ const default_action = NoAction();
+ }
+
+/****************** IPv4 Lookup ********************/
+ action set_nexthop(nexthop_id_t nexthop) {
+ nexthop_id = nexthop;
+ }
+
+ table ipv4_host {
+ key = {
+ same_flag : exact;
+ meta.dst_ipv4 : exact;
+ }
+ actions = { set_nexthop; @defaultonly NoAction; }
+ size = IPV4_HOST_SIZE;
+ const default_action = NoAction();
+ }
+
+ table ipv4_lpm {
+ key = {
+ same_flag : exact;
+ meta.dst_ipv4 : lpm;
+ }
+ actions = { set_nexthop; }
+
+ default_action = set_nexthop(0);
+ size = IPV4_LPM_SIZE;
+ }
+
+ /****************** Nexthop ********************/
+ action send(PortId_t port) {
+ mac_da = hdr.ethernet.dst_addr;
+ mac_sa = hdr.ethernet.src_addr;
+ egress_port = port;
+ ttl_dec = 0;
+ }
+
+ action l3_switch(PortId_t port, bit<48> new_mac_da, bit<48> new_mac_sa) {
+ mac_da = new_mac_da;
+ mac_sa = new_mac_sa; /*目的ip对应的交换机MAC*/
+ egress_port = port;
+ ttl_dec = 1;
+ }
+
+ table nexthop {
+ key = { nexthop_id : exact; }
+ actions = { send; drop; l3_switch; }
+ size = NEXTHOP_SIZE;
+ default_action = drop();
+ }
+
+ /****************** Metadata Processing ********************/
+ action send_back() {
+ ig_tm_md.ucast_egress_port = ig_intr_md.ingress_port;
+ }
+
+ action forward_ipv4() {
+ hdr.ethernet.dst_addr = mac_da;
+ hdr.ethernet.src_addr = mac_sa;
+ hdr.ipv4.ttl = hdr.ipv4.ttl |-| ttl_dec;
+ ig_tm_md.ucast_egress_port = egress_port;
+ }
+
+ action send_arp_reply_in() {
+ hdr.ethernet.dst_addr = hdr.arp_ipv4.src_hw_addr;
+ hdr.ethernet.src_addr = mac_da; /*ARP请求同一个sub_vlan中的主机MAC,把主机的真实MAC作为源MAC回复*/
+
+ hdr.arp.opcode = arp_opcode_t.REPLY;
+ hdr.arp_ipv4.dst_hw_addr = hdr.arp_ipv4.src_hw_addr;
+ hdr.arp_ipv4.dst_proto_addr = hdr.arp_ipv4.src_proto_addr;
+ hdr.arp_ipv4.src_hw_addr = mac_da;
+ hdr.arp_ipv4.src_proto_addr = meta.dst_ipv4;
+
+ send_back();
+ }
+
+ action send_arp_reply_out() {
+ hdr.ethernet.dst_addr = hdr.arp_ipv4.src_hw_addr;
+ hdr.ethernet.src_addr = switch_mac; /*ARP请求不同sub_vlan中的主机MAC,把交换机的MAC作为源MAC回复*/
+
+ hdr.arp.opcode = arp_opcode_t.REPLY;
+ hdr.arp_ipv4.dst_hw_addr = hdr.arp_ipv4.src_hw_addr;
+ hdr.arp_ipv4.dst_proto_addr = hdr.arp_ipv4.src_proto_addr;
+ hdr.arp_ipv4.src_hw_addr = mac_sa;
+ hdr.arp_ipv4.src_proto_addr = meta.dst_ipv4;
+
+ send_back();
+ }
+
+ table forward_or_respond {
+ key = {
+ same_flag : exact;
+ hdr.arp.isValid() : exact;
+ hdr.arp_ipv4.isValid() : exact;
+ hdr.ipv4.isValid() : exact;
+ hdr.arp.opcode : ternary;
+ }
+ actions = {
+ forward_ipv4;
+ send_arp_reply_in;
+ send_arp_reply_out;
+ drop;
+ }
+ const entries = {
+ (true, false, false, true, _) :
+ forward_ipv4();
+ (false, false, false, true, _) :
+ forward_ipv4();
+ (true, true, true, false, arp_opcode_t.REQUEST) :
+ send_arp_reply_in();
+ (false, true, true, false, arp_opcode_t.REQUEST) :
+ send_arp_reply_out();
+ }
+ default_action = drop();
+ }
+
+ apply{
+ if(meta.ipv4_csum_err == 0){
+ if(!is_l2_switch.apply().hit){
+ Trunk_switch.apply();
+ }
+ if(!l3_flag){
+ same_flag = true;
+ }
+ if(!same_flag){
+ Port_to_srcvid.apply();
+ dstIP_to_dstvid.apply();
+ if((src_supervid == dst_supervid)&&(meta.src_subvid == dst_subvid)){
+ same_flag = true;
+ }
+ src_supervid_to_mac.apply();
+ if (!ipv4_host.apply().hit) {
+ ipv4_lpm.apply();
+ }
+ nexthop.apply();
+ }
+ forward_or_respond.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)
+{
+ Checksum() ipv4_checksum;
+
+ apply {
+ hdr.ipv4.hdr_checksum = ipv4_checksum.update({
+ hdr.ipv4.version,
+ hdr.ipv4.ihl,
+ hdr.ipv4.diffserv,
+ hdr.ipv4.total_len,
+ hdr.ipv4.identification,
+ hdr.ipv4.flags,
+ hdr.ipv4.frag_offset,
+ hdr.ipv4.ttl,
+ hdr.ipv4.protocol,
+ hdr.ipv4.src_addr,
+ hdr.ipv4.dst_addr
+ /* Adding hdr.ipv4_options.data results in an error */
+ });
+ 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 {
+}
+
+ /******** 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/pkt/subin_test.py b/pkt/subin_test.py
new file mode 100644
index 0000000..60c656e
--- /dev/null
+++ b/pkt/subin_test.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+
+import os
+import sys
+
+if os.getuid() !=0:
+ print """
+ERROR: This script requires root privileges.
+ Use 'sudo' to run it.
+"""
+ quit()
+
+from scapy.all import *
+
+try:
+ ip_dst = sys.argv[1]
+except:
+ ip_dst = "192.168.1.2"
+
+print "Sending IP packet to", ip_dst
+p = (Ether(dst="00:00:02:00:00:02", src="00:00:01:00:00:01")/
+ IP(src="10.11.12.13", dst=ip_dst)/
+ UDP(sport=7,dport=7)/
+ "This is a test")
+sendp(p, iface="veth1")
diff --git a/pkt/twosub_test.py b/pkt/twosub_test.py
new file mode 100644
index 0000000..bedb33c
--- /dev/null
+++ b/pkt/twosub_test.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+
+import os
+import sys
+
+if os.getuid() !=0:
+ print """
+ERROR: This script requires root privileges.
+ Use 'sudo' to run it.
+"""
+ quit()
+
+from scapy.all import *
+
+try:
+ ip_dst = sys.argv[1]
+except:
+ ip_dst = "192.168.1.2"
+
+print "Sending IP packet to", ip_dst
+p = (Ether(dst="FF:FF:FF:FF:FF:FF", src="00:00:01:00:00:01")/
+ ARP(psrc='192.168.1.13',pdst='192.168.1.1'))
+sendp(p, iface="veth3")
diff --git a/ptf/.DS_Store b/ptf/.DS_Store
new file mode 100644
index 0000000..cc5b8a9
--- /dev/null
+++ b/ptf/.DS_Store
Binary files differ
diff --git a/ptf/test0410.py b/ptf/test0410.py
new file mode 100644
index 0000000..abfec0a
--- /dev/null
+++ b/ptf/test0410.py
@@ -0,0 +1,836 @@
+
+"""
+Simple PTF test for super_vlan
+"""
+
+######### STANDARD MODULE IMPORTS ########
+import unittest
+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
+
+########## 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 = "super_vlan_test"
+ 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
+ self.is_l2_switch = self.bfrt_info.table_get("Ingress.is_l2_switch")
+ self.is_l2_switch.info.key_field_annotation_add(
+ "hdr.ethernet.dst_addr", "mac")
+
+ self.Trunk_switch = self.bfrt_info.table_get("Ingress.Trunk_switch")
+ self.Trunk_switch.info.key_field_annotation_add(
+ "hdr.ethernet.dst_addr", "mac")
+
+ self.Port_to_srcvid = self.bfrt_info.table_get("Ingress.Port_to_srcvid")
+ self.Port_to_srcvid.info.key_field_annotation_add(
+ "ig_intr_md.ingress_port", "int")
+
+ self.dstIP_to_dstvid = self.bfrt_info.table_get("Ingress.dstIP_to_dstvid")
+ self.dstIP_to_dstvid.info.key_field_annotation_add(
+ "meta.dst_ipv4", "ipv4")
+
+ self.src_supervid_to_mac = self.bfrt_info.table_get("Ingress.src_supervid_to_mac")
+ self.src_supervid_to_mac.info.data_field_annotation_add(
+ "new_mac_switch", "Ingress.set_super_MAC", "mac")
+
+ self.ipv4_host = self.bfrt_info.table_get("Ingress.ipv4_host")
+ self.ipv4_host.info.key_field_annotation_add(
+ "meta.dst_ipv4", "ipv4")
+
+ self.ipv4_lpm = self.bfrt_info.table_get("Ingress.ipv4_lpm")
+ self.ipv4_lpm.info.key_field_annotation_add(
+ "meta.dst_ipv4", "ipv4")
+
+ self.nexthop = self.bfrt_info.table_get("Ingress.nexthop")
+ self.nexthop.info.data_field_annotation_add(
+ "new_mac_da", "Ingress.l3_switch", "mac")
+ self.nexthop.info.data_field_annotation_add(
+ "new_mac_sa", "Ingress.l3_switch", "mac")
+
+ self.tables = [ self.is_l2_switch, self.Trunk_switch, self.Port_to_srcvid, self.dstIP_to_dstvid, self.src_supervid_to_mac, self.ipv4_host, self.ipv4_lpm, self.nexthop ]
+
+ # 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 HostSend(BaseProgramTest):
+ def runTest(self):
+ ingress_port = test_param_get("ingress_port", 0)
+ ipv4_dst = test_param_get("ipv4_dst", "192.168.1.2")
+ dst_addr = test_param_get("dst_addr", "00:00:02:00:00:02")
+ egress_port = test_param_get("egress_port", 4)
+ nexthop_id = test_param_get("nexthop_id", 100)
+ same_flag = test_param_get("same_flag", True)
+
+ print("\n")
+ print("Test Run")
+ print("========")
+
+ #
+ # Program an entry in nexthop: nexthop_id --> send(egress_port)
+ #
+ key_list = [
+ self.nexthop.make_key([
+ gc.KeyTuple('nexthop_id', nexthop_id)])
+ ]
+
+ data_list = [
+ self.nexthop.make_data([], "Ingress.send")
+ ]
+
+ self.nexthop.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to nexthop: {} --> send()".format(
+ nexthop_id))
+
+ #
+ # Program an entry in ipv4_host: ipv4_dst --> set_nexthop(nexthop_id)
+ #
+
+ key_list = [
+ self.ipv4_host.make_key([
+ gc.KeyTuple('same_flag', same_flag),
+ gc.KeyTuple('meta.dst_ipv4', ipv4_dst)])
+ ]
+
+ data_list = [
+ self.ipv4_host.make_data([
+ gc.DataTuple('nexthop', nexthop_id)], "Ingress.set_nexthop")
+ ]
+
+ self.ipv4_host.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to ipv4_host: {},{} --> set_nexthop({})".
+ format(same_flag, ipv4_dst, nexthop_id))
+
+ #
+ # Program an entry in is_l2_switch: dst_mac --> l2_switch
+ #
+ key_list = [
+ self.is_l2_switch.make_key([
+ gc.KeyTuple('hdr.ethernet.dst_addr', dst_addr)])
+ ]
+
+ data_list = [
+ self.is_l2_switch.make_data([
+ gc.DataTuple('port', egress_port)], "Ingress.l2_switch")
+ ]
+
+ self.is_l2_switch.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to is_l2_switch: {} --> l2_switch({})".
+ format(dst_addr, egress_port))
+
+ #
+ # Send a test packet
+ #
+ print(" Sending packet with IPv4 DST ADDR={} into port {}"
+ .format(ipv4_dst, ingress_port))
+ pkt = simple_tcp_packet(eth_dst=dst_addr,
+ eth_src='00:00:02:00:00:01',
+ ip_dst=ipv4_dst,
+ ip_id=101,
+ ip_ttl=64,
+ ip_ihl=5)
+ send_packet(self, ingress_port, pkt)
+
+ #
+ # Wait for the egress packet and verify it
+ #
+ print(" Expecting the packet to be forwarded to port {}"
+ .format(egress_port))
+ verify_packet(self, pkt, egress_port)
+ print(" Packet received of port {}".format(egress_port))
+
+
+class HostDrop(BaseProgramTest):
+ def runTest(self):
+ ingress_port = test_param_get("ingress_port", 0)
+ ipv4_dst = test_param_get("ipv4_dst", "192.168.1.3")
+ dst_addr = test_param_get("dst_addr", "00:00:02:00:00:03")
+ egress_port = test_param_get("egress_port", 5)
+ nexthop_id = test_param_get("nexthop_id", 102)
+ same_flag = test_param_get("same_flag", True)
+
+ print("\n")
+ print("Test Run")
+ print("========")
+
+ #
+ # Program an entry in nexthop: nexthop_id --> drop()
+ #
+ key_list = [
+ self.nexthop.make_key([
+ gc.KeyTuple('nexthop_id', nexthop_id)])
+ ]
+
+ data_list = [
+ self.nexthop.make_data([], "Ingress.drop")
+ ]
+
+ self.nexthop.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to nexthop: {} --> drop()".
+ format(nexthop_id))
+
+ #
+ # Program an entry in ipv4_host: ipv4_dst --> set_nexthop(nexthop_id)
+ #
+ key_list = [
+ self.ipv4_host.make_key([
+ gc.KeyTuple('same_flag', same_flag),
+ gc.KeyTuple('meta.dst_ipv4', ipv4_dst)])
+ ]
+
+ data_list = [
+ self.ipv4_host.make_data([
+ gc.DataTuple('nexthop', nexthop_id)], "Ingress.set_nexthop")
+ ]
+
+ self.ipv4_host.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to ipv4_host: {},{} --> set_nexthop({})".
+ format(same_flag, ipv4_dst, nexthop_id))
+
+ #
+ # Program an entry in is_l2_switch: dst_mac --> l2_switch
+ #
+ key_list = [
+ self.is_l2_switch.make_key([
+ gc.KeyTuple('hdr.ethernet.dst_addr', dst_addr)])
+ ]
+
+ data_list = [
+ self.is_l2_switch.make_data([
+ gc.DataTuple('port', egress_port)], "Ingress.l2_switch")
+ ]
+
+ self.is_l2_switch.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to is_l2_switch: {} --> l2_switch({})".
+ format(dst_addr, egress_port))
+
+
+ #
+ # Send a test packet
+ #
+ print(" Sending packet with IPv4 DST ADDR={} into port {}"
+ .format(ipv4_dst, ingress_port))
+ pkt = simple_tcp_packet(eth_dst=dst_addr,
+ eth_src='00:00:02:00:00:01',
+ ip_dst=ipv4_dst,
+ ip_id=101,
+ ip_ttl=64,
+ ip_ihl=5)
+ send_packet(self, ingress_port, pkt)
+ print(" Expecting No packets anywhere")
+
+ #
+ # Wait to make sure no packet egresses anywhere. self.swports is the
+ # list of all ports the test is using. It is set up in the setUp()
+ # method of the parent class
+ #
+ verify_no_packet_any(self, pkt, self.swports)
+ print(" No packets received")
+
+
+class HostL3Switch(BaseProgramTest):
+ def runTest(self):
+ ingress_port = test_param_get("ingress_port", 0)
+ ipv4_dst = test_param_get("ipv4_dst", "192.168.1.13")
+ dst_addr = test_param_get("dst_addr", "00:00:00:00:00:01")
+ new_mac_da = test_param_get("new_mac_da", "00:00:03:00:00:03")
+ new_mac_sa = test_param_get("new_mac_sa", "00:00:00:00:00:01")
+ egress_port = test_param_get("egress_port", 4)
+ nexthop_id = test_param_get("nexthop_id", 101)
+ same_flag = test_param_get("same_flag", False)
+ src_supervid = test_param_get("src_supervid", 10)
+ switch_mac = test_param_get("switch_mac", "00:00:00:00:00:01")
+ dst_subvid = 3
+ dst_supervid = 10
+ src_subvid = 2
+ src_supervid = 10
+
+ print("\n")
+ print("Test Run")
+ print("========")
+
+ #
+ # Program an entry in nexthop:
+ # nexthop_id --> l3_switch(egress_port. new_mac_da, new_mac_da)
+ #
+ key_list = [
+ self.nexthop.make_key([
+ gc.KeyTuple('nexthop_id', nexthop_id)])
+ ]
+
+ data_list = [
+ self.nexthop.make_data([gc.DataTuple('port', egress_port),
+ gc.DataTuple('new_mac_da', new_mac_da),
+ gc.DataTuple('new_mac_sa', new_mac_sa)],
+ "Ingress.l3_switch")
+ ]
+
+ self.nexthop.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to nexthop: {} --> send({})".
+ format(nexthop_id, egress_port))
+
+ #
+ # Program an entry in IPv4: ipv4_dst --> set_nexthop(nexthop_id)
+ #
+ key_list = [
+ self.ipv4_host.make_key([
+ gc.KeyTuple('same_flag', same_flag),
+ gc.KeyTuple('meta.dst_ipv4', ipv4_dst)])
+ ]
+
+ data_list = [
+ self.ipv4_host.make_data([
+ gc.DataTuple('nexthop', nexthop_id)], "Ingress.set_nexthop")
+ ]
+
+ self.ipv4_host.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to ipv4_host: {},{} --> set_nexthop({})".
+ format(same_flag, ipv4_dst, nexthop_id))
+
+ #
+ # Program an entry in src_supervid_to_mac: super_vid --> mac
+ #
+ key_list = [
+ self.src_supervid_to_mac.make_key([
+ gc.KeyTuple('src_supervid', src_supervid)])
+ ]
+
+ data_list = [
+ self.src_supervid_to_mac.make_data([
+ gc.DataTuple('new_mac_switch', switch_mac)], "Ingress.set_super_MAC")
+ ]
+
+ self.src_supervid_to_mac.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to src_supervid_to_mac: VLAN IF{} --> super_mac({})".
+ format(src_supervid, switch_mac))
+
+ #
+ # Program an entry in dstIP_to_dstvid: dst_ip --> dst_vid
+ #
+ key_list = [
+ self.dstIP_to_dstvid.make_key([
+ gc.KeyTuple('meta.dst_ipv4', ipv4_dst)])
+ ]
+
+ data_list = [
+ self.dstIP_to_dstvid.make_data([
+ gc.DataTuple('subvid', dst_subvid),
+ gc.DataTuple('supervid', dst_supervid)], "Ingress.set_dst_vid")
+ ]
+
+ self.dstIP_to_dstvid.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to dstIP_to_dstvid: dst_ip{} --> set_dst_vid({},{})".
+ format(ipv4_dst, dst_subvid, dst_supervid))
+
+ #
+ # Program an entry in Port_to_srcvid: dst_ip --> dst_vid
+ #
+ key_list = [
+ self.Port_to_srcvid.make_key([
+ gc.KeyTuple('ig_intr_md.ingress_port', ingress_port)])
+ ]
+
+ data_list = [
+ self.Port_to_srcvid.make_data([
+ gc.DataTuple('subvid', src_subvid),
+ gc.DataTuple('supervid', src_supervid)], "Ingress.set_src_vid")
+ ]
+
+ self.Port_to_srcvid.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to Port_to_srcvid: dst_ip{} --> set_src_vid({},{})".
+ format(ingress_port, src_subvid, src_supervid))
+
+ #
+ # Program an entry in is_l2_switch: dst_mac --> l2_switch
+ #
+ key_list = [
+ self.is_l2_switch.make_key([
+ gc.KeyTuple('hdr.ethernet.dst_addr', dst_addr)])
+ ]
+
+ data_list = [
+ self.is_l2_switch.make_data([], "Ingress.set_l3_flag")
+ ]
+
+ self.is_l2_switch.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to is_l2_switch: {} --> l3_switch()".
+ format(dst_addr))
+
+ #
+ # Prepare the test packet and the expected packet
+ send_pkt = simple_tcp_packet(eth_dst=dst_addr,
+ eth_src='00:00:02:00:00:01',
+ ip_dst=ipv4_dst,
+ ip_id=101,
+ ip_ttl=64,
+ ip_ihl=5)
+ exp_pkt = copy.deepcopy(send_pkt)
+ exp_pkt[Ether].dst = new_mac_da
+ exp_pkt[Ether].src = new_mac_sa
+ exp_pkt[IP].ttl -= 1
+
+ #
+ # Send a test packet
+ #
+ print(" Sending packet with IPv4 DST ADDR={} into port {}"
+ .format(ipv4_dst, ingress_port))
+
+ send_packet(self, ingress_port, send_pkt)
+
+ #
+ # Wait for the egress packet and verify it
+ #
+ print(" Expecting the modified packet to be forwarded to port {}"
+ .format(egress_port))
+
+ verify_packet(self, exp_pkt, egress_port)
+ print(" Modified Packet received of port {}"
+ .format(egress_port))
+
+
+class TrunkForward(BaseProgramTest):
+ def runTest(self):
+ ingress_port = test_param_get("ingress_port", 0)
+ ipv4_dst = test_param_get("ipv4_dst", "192.168.2.1")
+ dst_addr = test_param_get("dst_addr", "01:00:02:00:00:01")
+ egress_port = test_param_get("egress_port", 5)
+
+ print("\n")
+ print("Test Run")
+ print("========")
+
+ #
+ # Program an entry in Trunk_switch: dst_mac --> set_trunk_port
+ #
+ key_list = [
+ self.Trunk_switch.make_key([
+ gc.KeyTuple('hdr.ethernet.dst_addr', dst_addr)])
+ ]
+
+ data_list = [
+ self.Trunk_switch.make_data([
+ gc.DataTuple('port', egress_port)], "Ingress.set_trunk_port")
+ ]
+
+ self.Trunk_switch.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to Trunk_switch: {} --> set_trunk_port({})".
+ format(dst_addr, egress_port))
+
+ #
+ # Send a test packet
+ #
+ print(" Sending packet with IPv4 DST ADDR={} into port {}"
+ .format(ipv4_dst, ingress_port))
+ pkt = simple_tcp_packet(eth_dst=dst_addr,
+ eth_src='00:00:02:00:00:01',
+ ip_dst=ipv4_dst,
+ ip_id=101,
+ ip_ttl=64,
+ ip_ihl=5)
+ send_packet(self, ingress_port, pkt)
+
+ #
+ # Wait for the egress packet and verify it
+ #
+ print(" Expecting the packet to be forwarded to port {}"
+ .format(egress_port))
+ verify_packet(self, pkt, egress_port)
+ print(" Packet received of port {}".format(egress_port))
+
+class HostArp(BaseProgramTest):
+ def runTest(self):
+ ingress_port = test_param_get("ingress_port", 0)
+ ipv4_dst = test_param_get("ipv4_dst", "192.168.1.13")
+ #dst_addr = test_param_get("dst_addr", "00:00:02:00:00:01")
+ dst_addr = test_param_get("dst_addr", "FF:FF:FF:FF:FF:FF")
+ new_mac_da = test_param_get("new_mac_da", "00:00:03:00:00:03")
+ new_mac_sa = test_param_get("new_mac_sa", "00:00:00:00:00:01")
+ egress_port = test_param_get("egress_port", 4)
+ nexthop_id = test_param_get("nexthop_id", 101)
+ same_flag = test_param_get("same_flag", False)
+ src_supervid = test_param_get("src_supervid", 10)
+ switch_mac = test_param_get("switch_mac", "00:00:00:00:00:01")
+ dst_subvid = 3
+ dst_supervid = 10
+ src_subvid = 2
+ src_supervid = 10
+ print("\n")
+ print("Test Run")
+ print("========")
+
+ #
+ # Program an entry in nexthop:
+ # nexthop_id --> l3_switch(egress_port. new_mac_da, new_mac_da)
+ #
+ key_list = [
+ self.nexthop.make_key([
+ gc.KeyTuple('nexthop_id', nexthop_id)])
+ ]
+
+ data_list = [
+ self.nexthop.make_data([gc.DataTuple('port', egress_port),
+ gc.DataTuple('new_mac_da', new_mac_da),
+ gc.DataTuple('new_mac_sa', new_mac_sa)],
+ "Ingress.l3_switch")
+ ]
+
+ self.nexthop.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to nexthop: {} --> send({})".
+ format(nexthop_id, egress_port))
+
+ #
+ # Program an entry in IPv4: ipv4_dst --> set_nexthop(nexthop_id)
+ #
+ key_list = [
+ self.ipv4_host.make_key([
+ gc.KeyTuple('same_flag', same_flag),
+ gc.KeyTuple('meta.dst_ipv4', ipv4_dst)])
+ ]
+
+ data_list = [
+ self.ipv4_host.make_data([
+ gc.DataTuple('nexthop', nexthop_id)], "Ingress.set_nexthop")
+ ]
+
+ self.ipv4_host.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to ipv4_host: {},{} --> set_nexthop({})".
+ format(same_flag, ipv4_dst, nexthop_id))
+
+ #
+ # Program an entry in src_supervid_to_mac: super_vid --> mac
+ #
+ key_list = [
+ self.src_supervid_to_mac.make_key([
+ gc.KeyTuple('src_supervid', src_supervid)])
+ ]
+
+ data_list = [
+ self.src_supervid_to_mac.make_data([
+ gc.DataTuple('new_mac_switch', switch_mac)], "Ingress.set_super_MAC")
+ ]
+
+ self.src_supervid_to_mac.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to src_supervid_to_mac: VLAN IF{} --> super_mac({})".
+ format(src_supervid, switch_mac))
+
+ #
+ # Program an entry in dstIP_to_dstvid: dst_ip --> dst_vid
+ #
+ key_list = [
+ self.dstIP_to_dstvid.make_key([
+ gc.KeyTuple('meta.dst_ipv4', ipv4_dst)])
+ ]
+
+ data_list = [
+ self.dstIP_to_dstvid.make_data([
+ gc.DataTuple('subvid', dst_subvid),
+ gc.DataTuple('supervid', dst_supervid)], "Ingress.set_dst_vid")
+ ]
+
+ self.dstIP_to_dstvid.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to dstIP_to_dstvid: dst_ip{} --> set_dst_vid({},{})".
+ format(ipv4_dst, dst_subvid, dst_supervid))
+
+ #
+ # Program an entry in Port_to_srcvid: ingress_port --> src_vid
+ #
+ key_list = [
+ self.Port_to_srcvid.make_key([
+ gc.KeyTuple('ig_intr_md.ingress_port', ingress_port)])
+ ]
+
+ data_list = [
+ self.Port_to_srcvid.make_data([
+ gc.DataTuple('subvid', src_subvid),
+ gc.DataTuple('supervid', src_supervid)], "Ingress.set_src_vid")
+ ]
+
+ self.Port_to_srcvid.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to Port_to_srcvid: dst_ip{} --> set_src_vid({},{})".
+ format(ingress_port, src_subvid, src_supervid))
+
+ #
+ # Program an entry in is_l2_switch: dst_mac --> l2_switch
+ #
+ key_list = [
+ self.is_l2_switch.make_key([
+ gc.KeyTuple('hdr.ethernet.dst_addr', dst_addr)])
+ ]
+
+ data_list = [
+ self.is_l2_switch.make_data([], "Ingress.set_l3_flag")
+ ]
+
+ self.is_l2_switch.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to is_l2_switch: {} --> l3_switch()".
+ format(dst_addr))
+
+ # Prepare the test packet and the expected packet
+
+ pkt = simple_arp_packet(ip_tgt=ipv4_dst, pktlen=100)
+ send_packet(self, ingress_port, pkt)
+
+ arp_mac = "00:00:00:00:00:01"
+ exp_pkt = copy.deepcopy(pkt)
+ exp_pkt[Ether].dst = pkt[ARP].hwsrc
+ exp_pkt[Ether].src = arp_mac
+ exp_pkt[ARP].op = 2
+ exp_pkt[ARP].hwsrc = arp_mac
+ exp_pkt[ARP].psrc = ipv4_dst
+ exp_pkt[ARP].hwdst = pkt[ARP].hwsrc
+ exp_pkt[ARP].pdst = pkt[ARP].psrc
+ print("Expecting ARP Reply for {} at port {}".
+ format(ipv4_dst, ingress_port))
+ verify_packet(self, exp_pkt, ingress_port)
+
+ print("IP address {} is at {}".
+ format(ipv4_dst, arp_mac))
+
+
+class LpmARP(BaseProgramTest):
+ def runTest(self):
+ ingress_port = test_param_get("ingress_port", 0)
+ lpm_addr = test_param_get("lpm_addr", "192.168.1.0/24")
+ ipv4_dst = test_param_get("ipv4_dst", "192.168.1.13")
+ #dst_addr = test_param_get("dst_addr", "00:00:02:00:00:01")
+ dst_addr = test_param_get("dst_addr", "FF:FF:FF:FF:FF:FF")
+ new_mac_da = test_param_get("new_mac_da", "00:00:03:00:00:03")
+ new_mac_sa = test_param_get("new_mac_sa", "00:00:00:00:00:01")
+ egress_port = test_param_get("egress_port", 4)
+ nexthop_id = test_param_get("nexthop_id", 101)
+ same_flag = test_param_get("same_flag", False)
+ src_supervid = test_param_get("src_supervid", 10)
+ switch_mac = test_param_get("switch_mac", "00:00:00:00:00:01")
+ dst_subvid = 3
+ dst_supervid = 10
+ src_subvid = 2
+ src_supervid = 10
+ arp_mac = "00:00:00:00:00:01"
+ (lpm_ipv4, lpm_p_len) = lpm_addr.split("/")
+
+ print("\n")
+ print("Test Run")
+ print("========")
+
+ #
+ # Program an entry in nexthop:
+ # nexthop_id --> l3_switch(egress_port. new_mac_da, new_mac_da)
+ #
+ key_list = [
+ self.nexthop.make_key([
+ gc.KeyTuple('nexthop_id', nexthop_id)])
+ ]
+
+ data_list = [
+ self.nexthop.make_data([gc.DataTuple('port', egress_port),
+ gc.DataTuple('new_mac_da', new_mac_da),
+ gc.DataTuple('new_mac_sa', new_mac_sa)],
+ "Ingress.l3_switch")
+ ]
+
+ self.nexthop.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to nexthop: {} --> send({})".
+ format(nexthop_id, egress_port))
+
+ #
+ # Program an entry in ipv4_lpm:
+ # lpm_addr/prefix --> set_nexthop(nexthop_id)
+ # Note the extra named argument (prefix_len) to gc.KeyTuple().
+ #
+ key_list = [
+ self.ipv4_lpm.make_key([
+ gc.KeyTuple('same_flag', same_flag),
+ gc.KeyTuple('meta.dst_ipv4',
+ value=lpm_ipv4, prefix_len=int(lpm_p_len))])
+ ]
+
+ data_list = [
+ self.ipv4_lpm.make_data([
+ gc.DataTuple('nexthop', nexthop_id)], "Ingress.set_nexthop")
+ ]
+
+ self.ipv4_lpm.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to ipv4_lpm: {}/{} --> set_nexthop({})".format(
+ lpm_ipv4, lpm_p_len, nexthop_id))
+
+
+ #
+ # Program an entry in src_supervid_to_mac: super_vid --> mac
+ #
+ key_list = [
+ self.src_supervid_to_mac.make_key([
+ gc.KeyTuple('src_supervid', src_supervid)])
+ ]
+
+ data_list = [
+ self.src_supervid_to_mac.make_data([
+ gc.DataTuple('new_mac_switch', switch_mac)], "Ingress.set_super_MAC")
+ ]
+
+ self.src_supervid_to_mac.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to src_supervid_to_mac: VLAN IF{} --> super_mac({})".
+ format(src_supervid, switch_mac))
+
+ #
+ # Program an entry in dstIP_to_dstvid: dst_ip --> dst_vid
+ #
+ key_list = [
+ self.dstIP_to_dstvid.make_key([
+ gc.KeyTuple('meta.dst_ipv4', ipv4_dst)])
+ ]
+
+ data_list = [
+ self.dstIP_to_dstvid.make_data([
+ gc.DataTuple('subvid', dst_subvid),
+ gc.DataTuple('supervid', dst_supervid)], "Ingress.set_dst_vid")
+ ]
+
+ self.dstIP_to_dstvid.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to dstIP_to_dstvid: dst_ip{} --> set_dst_vid({},{})".
+ format(ipv4_dst, dst_subvid, dst_supervid))
+
+ #
+ # Program an entry in Port_to_srcvid: ingress_port --> src_vid
+ #
+ key_list = [
+ self.Port_to_srcvid.make_key([
+ gc.KeyTuple('ig_intr_md.ingress_port', ingress_port)])
+ ]
+
+ data_list = [
+ self.Port_to_srcvid.make_data([
+ gc.DataTuple('subvid', src_subvid),
+ gc.DataTuple('supervid', src_supervid)], "Ingress.set_src_vid")
+ ]
+
+ self.Port_to_srcvid.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to Port_to_srcvid: dst_ip{} --> set_src_vid({},{})".
+ format(ingress_port, src_subvid, src_supervid))
+
+ #
+ # Program an entry in is_l2_switch: dst_mac --> l2_switch
+ #
+ key_list = [
+ self.is_l2_switch.make_key([
+ gc.KeyTuple('hdr.ethernet.dst_addr', dst_addr)])
+ ]
+
+ data_list = [
+ self.is_l2_switch.make_data([], "Ingress.set_l3_flag")
+ ]
+
+ self.is_l2_switch.entry_add(self.dev_tgt, key_list, data_list);
+ print(" Added an entry to is_l2_switch: {} --> l3_switch()".
+ format(dst_addr))
+
+ # Prepare the test packet and the expected packet
+
+ pkt = simple_arp_packet(ip_tgt=ipv4_dst, pktlen=100)
+ send_packet(self, ingress_port, pkt)
+
+ exp_pkt = copy.deepcopy(pkt)
+ exp_pkt[Ether].dst = pkt[ARP].hwsrc
+ exp_pkt[Ether].src = arp_mac
+ exp_pkt[ARP].op = 2
+ exp_pkt[ARP].hwsrc = arp_mac
+ exp_pkt[ARP].psrc = ipv4_dst
+ exp_pkt[ARP].hwdst = pkt[ARP].hwsrc
+ exp_pkt[ARP].pdst = pkt[ARP].psrc
+ print("Expecting ARP Reply for {} at port {}".
+ format(ipv4_dst, ingress_port))
+ verify_packet(self, exp_pkt, ingress_port)
+
+ print("IP address {} is at {}".
+ format(ipv4_dst, arp_mac)) \ No newline at end of file