diff options
| -rw-r--r-- | .DS_Store | bin | 0 -> 8196 bytes | |||
| -rw-r--r-- | README.md | 9 | ||||
| -rw-r--r-- | bfrt_python/setup.py | 113 | ||||
| -rw-r--r-- | p4src/.DS_Store | bin | 0 -> 6148 bytes | |||
| -rw-r--r-- | p4src/super_vlan_0409.p4 | 566 | ||||
| -rw-r--r-- | p4src/super_vlan_0410.p4 | 566 | ||||
| -rw-r--r-- | pkt/subin_test.py | 25 | ||||
| -rw-r--r-- | pkt/twosub_test.py | 23 | ||||
| -rw-r--r-- | ptf/.DS_Store | bin | 0 -> 6148 bytes | |||
| -rw-r--r-- | ptf/test0410.py | 836 |
10 files changed, 2138 insertions, 0 deletions
diff --git a/.DS_Store b/.DS_Store Binary files differnew file mode 100644 index 0000000..24bee69 --- /dev/null +++ b/.DS_Store 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 Binary files differnew file mode 100644 index 0000000..12edfb5 --- /dev/null +++ b/p4src/.DS_Store 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 Binary files differnew file mode 100644 index 0000000..cc5b8a9 --- /dev/null +++ b/ptf/.DS_Store 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 |
