diff --git a/dash-pipeline/bmv2/dash_headers.p4 b/dash-pipeline/bmv2/dash_headers.p4 index 1b3b6085e..02c0a9001 100644 --- a/dash-pipeline/bmv2/dash_headers.p4 +++ b/dash-pipeline/bmv2/dash_headers.p4 @@ -254,7 +254,6 @@ header dash_packet_meta_t { const bit<16> PACKET_META_HDR_SIZE=dash_packet_meta_t.minSizeInBytes(); #define DASH_ETHTYPE 0x876d -#define DPAPP_MAC 0x02fe23f0e413 /* FIXME temp hardcode */ struct headers_t { /* packet metadata headers */ diff --git a/dash-pipeline/bmv2/dash_metadata.p4 b/dash-pipeline/bmv2/dash_metadata.p4 index e7415f59d..bcbbe8ba6 100644 --- a/dash-pipeline/bmv2/dash_metadata.p4 +++ b/dash-pipeline/bmv2/dash_metadata.p4 @@ -243,6 +243,7 @@ struct metadata_t { bit<16> dash_tunnel_next_hop_id; bit<32> meter_class; bit<8> local_region_id; + EthernetAddress cpu_mac; } #endif /* _SIRIUS_METADATA_P4_ */ diff --git a/dash-pipeline/bmv2/stages/conntrack_lookup.p4 b/dash-pipeline/bmv2/stages/conntrack_lookup.p4 index 90ec911a2..a8e9dfdc9 100644 --- a/dash-pipeline/bmv2/stages/conntrack_lookup.p4 +++ b/dash-pipeline/bmv2/stages/conntrack_lookup.p4 @@ -127,7 +127,7 @@ control conntrack_build_dash_header(inout headers_t hdr, in metadata_t meta, hdr.packet_meta.length = length + PACKET_META_HDR_SIZE; hdr.dp_ethernet.setValid(); - hdr.dp_ethernet.dst_addr = DPAPP_MAC; + hdr.dp_ethernet.dst_addr = meta.cpu_mac; hdr.dp_ethernet.src_addr = meta.u0_encap_data.underlay_smac; hdr.dp_ethernet.ether_type = DASH_ETHTYPE; } diff --git a/dash-pipeline/bmv2/stages/pre_pipeline.p4 b/dash-pipeline/bmv2/stages/pre_pipeline.p4 index 55728abcd..a3b6f3610 100644 --- a/dash-pipeline/bmv2/stages/pre_pipeline.p4 +++ b/dash-pipeline/bmv2/stages/pre_pipeline.p4 @@ -27,9 +27,11 @@ control pre_pipeline_stage(inout headers_t hdr, action set_internal_config(EthernetAddress neighbor_mac, EthernetAddress mac, + EthernetAddress cpu_mac, bit<1> flow_enabled) { meta.u0_encap_data.underlay_dmac = neighbor_mac; meta.u0_encap_data.underlay_smac = mac; + meta.cpu_mac = cpu_mac; meta.flow_enabled = (bool)flow_enabled; } diff --git a/dash-pipeline/dockerfiles/Dockerfile.saithrift-client-bldr b/dash-pipeline/dockerfiles/Dockerfile.saithrift-client-bldr index faceb0f0b..df46d12ff 100644 --- a/dash-pipeline/dockerfiles/Dockerfile.saithrift-client-bldr +++ b/dash-pipeline/dockerfiles/Dockerfile.saithrift-client-bldr @@ -15,7 +15,7 @@ ADD requirements.txt /tests/ RUN apt update && apt install -y python3 python3-pip sudo && \ sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.8 1 && \ sudo python3 -m pip install -r /tests/requirements.txt && \ - sudo pip3 install scapy pysubnettree + sudo pip3 install scapy pysubnettree p4runtime WORKDIR / diff --git a/test/test-cases/functional/ptf/p4_dash_utils.py b/test/test-cases/functional/ptf/p4_dash_utils.py new file mode 100644 index 000000000..bc93b7c79 --- /dev/null +++ b/test/test-cases/functional/ptf/p4_dash_utils.py @@ -0,0 +1,177 @@ +import grpc +from p4.v1 import p4runtime_pb2 +from p4.v1 import p4runtime_pb2_grpc + + +def get_mac(interface): + try: + mac = open('/sys/class/net/'+interface+'/address').readline().strip() + except: + mac = "00:00:00:00:00:00" + return mac + + +def mac_in_bytes(mac): + return bytes(int(b, 16) for b in mac.split(":")) + + +class P4info(): + def __init__(self, stub): + self.config = P4info.get_pipeline_config(stub) + + @staticmethod + def get_pipeline_config(stub): + try: + req = p4runtime_pb2.GetForwardingPipelineConfigRequest() + req.device_id = 0 + req.response_type = p4runtime_pb2.GetForwardingPipelineConfigRequest.ResponseType.P4INFO_AND_COOKIE + return stub.GetForwardingPipelineConfig(req).config.p4info + except Exception as e: + print(f'gRPC error: str({e})') + return None + + def get_table(self, name): + for table in self.config.tables: + if table.preamble.name == name: + return table + + return None + + def get_action(self, name): + for action in self.config.actions: + if action.preamble.name == name: + return action + + return None + + +def set_internal_config(neighbor_mac :bytes = None, + mac :bytes = None, + cpu_mac :bytes = None, + flow_enabled :bytes = None): + ''' + Set dash pipeline internal config by updating table entry of internal_config. + + if one argument is not specifed, the action param is not changed in the + existing table entry, otherwise set default value in new table entry. + ''' + channel = grpc.insecure_channel('localhost:9559') + stub = p4runtime_pb2_grpc.P4RuntimeStub(channel) + + p4info = P4info(stub) + internal_config = p4info.get_table("dash_ingress.dash_lookup_stage.pre_pipeline_stage.internal_config") + + entry = p4runtime_pb2.TableEntry() + entry.table_id = internal_config.preamble.id + entry.priority = 1 + + match = entry.match.add() + match.field_id = 1 + match.ternary.value = b'\x00' + match.ternary.mask = b'\xff' + + req = p4runtime_pb2.ReadRequest() + req.device_id = 0 + entity = req.entities.add() + entity.table_entry.CopyFrom(entry) + for response in stub.Read(req): + if not response.entities: + continue + entry = response.entities[0].table_entry + changed = 0 + + param = entry.action.action.params[0] + if neighbor_mac and neighbor_mac != param.value: + param.value = neighbor_mac + changed += 1 + + param = entry.action.action.params[1] + if mac and mac != param.value: + param.value = mac + changed += 1 + + param = entry.action.action.params[2] + if cpu_mac and cpu_mac != param.value: + param.value = cpu_mac + changed += 1 + + param = entry.action.action.params[3] + if flow_enabled and flow_enabled != param.value: + param.value = flow_enabled + changed += 1 + + if not changed: + return # none of change + + req = p4runtime_pb2.WriteRequest() + req.device_id = 0 + update = req.updates.add() + update.type = p4runtime_pb2.Update.MODIFY + update.entity.table_entry.CopyFrom(entry) + stub.Write(req) + return + + # Add one entry + set_internal_config = p4info.get_action("dash_ingress.dash_lookup_stage.pre_pipeline_stage.set_internal_config") + entry.action.action.action_id = set_internal_config.preamble.id + action = entry.action.action + + param = action.params.add() + param.param_id = 1 + if neighbor_mac: + param.value = neighbor_mac + else: # default value + param.value = b'\x00\x00\x00\x00\x00\x00' + + param = action.params.add() + param.param_id = 2 + if mac: + param.value = mac + else: # default value + param.value = b'\x00\x00\x00\x00\x00\x00' + + param = action.params.add() + param.param_id = 3 + if cpu_mac: + param.value = cpu_mac + else: # default value + param.value = b'\x00\x00\x00\x00\x00\x00' + + param = action.params.add() + param.param_id = 4 + if flow_enabled: + param.value = flow_enabled + else: # default value + param.value = b'\x00' + + req = p4runtime_pb2.WriteRequest() + req.device_id = 0 + update = req.updates.add() + update.type = p4runtime_pb2.Update.INSERT + update.entity.table_entry.CopyFrom(entry) + stub.Write(req) + + +def use_flow(cls): + _setUp = getattr(cls, "setUp", None) + _tearDown = getattr(cls, "tearDown", None) + + def setUp(self, *args, **kwargs): + if _setUp is not None: + _setUp(self, *args, **kwargs) + print(f'*** Enable Flow lookup') + set_internal_config(cpu_mac = mac_in_bytes(get_mac("veth5")), + flow_enabled = b'\x01') + return + + def tearDown(self, *args, **kwargs): + print(f'*** Disable Flow lookup') + set_internal_config(flow_enabled = b'\x00') + if _tearDown is not None: + _tearDown(self, *args, **kwargs) + return + + setattr(cls, "setUp", setUp) + setattr(cls, "tearDown", tearDown) + return cls + diff --git a/test/test-cases/functional/ptf/saidashvnet_sanity.py b/test/test-cases/functional/ptf/saidashvnet_sanity.py index 045eb0d85..5080b5baa 100644 --- a/test/test-cases/functional/ptf/saidashvnet_sanity.py +++ b/test/test-cases/functional/ptf/saidashvnet_sanity.py @@ -1,5 +1,6 @@ from sai_thrift.sai_headers import * from sai_base_test import * +from p4_dash_utils import * class SaiThriftVnetOutboundUdpPktTest(SaiHelperSimplified): """ Test saithrift vnet outbound""" @@ -10,7 +11,6 @@ def setUp(self): self.outbound_vni = 60 self.vnet_vni = 100 self.eni_mac = "00:cc:cc:cc:cc:cc" - self.our_mac = "00:00:02:03:04:05" self.dst_ca_mac = "00:dd:dd:dd:dd:dd" self.vip = "172.16.1.100" self.outbound_vni = 100 @@ -25,6 +25,11 @@ def setUp(self): # SAI address family self.sai_ip_addr_family = SAI_IP_ADDR_FAMILY_IPV4 + self.dut_mac = get_mac("veth0") + self.neighbor_mac = get_mac("veth1") + set_internal_config(neighbor_mac = mac_in_bytes(self.neighbor_mac), + mac = mac_in_bytes(self.dut_mac)) + # Flag to indicate whether configureVnet were successful or not. self.configured = False @@ -157,7 +162,6 @@ def configureVnet(self): def trafficTest(self): src_vm_ip = "10.1.1.10" - outer_smac = "00:00:05:06:06:06" # check VIP drop wrong_vip = "172.16.100.100" @@ -165,8 +169,8 @@ def trafficTest(self): eth_src=self.eni_mac, ip_dst=self.dst_ca_ip, ip_src=src_vm_ip) - vxlan_pkt = simple_vxlan_packet(eth_dst=self.our_mac, - eth_src=outer_smac, + vxlan_pkt = simple_vxlan_packet(eth_dst=self.dut_mac, + eth_src=self.neighbor_mac, ip_dst=wrong_vip, ip_src=self.src_vm_pa_ip, udp_sport=11638, @@ -184,8 +188,8 @@ def trafficTest(self): eth_src=self.eni_mac, ip_dst=wrong_dst_ca, ip_src=src_vm_ip) - vxlan_pkt = simple_vxlan_packet(eth_dst=self.our_mac, - eth_src=outer_smac, + vxlan_pkt = simple_vxlan_packet(eth_dst=self.dut_mac, + eth_src=self.neighbor_mac, ip_dst=self.vip, ip_src=self.src_vm_pa_ip, udp_sport=11638, @@ -203,8 +207,8 @@ def trafficTest(self): eth_src=self.eni_mac, ip_dst=wrong_dst_ca, ip_src=src_vm_ip) - vxlan_pkt = simple_vxlan_packet(eth_dst=self.our_mac, - eth_src=outer_smac, + vxlan_pkt = simple_vxlan_packet(eth_dst=self.dut_mac, + eth_src=self.neighbor_mac, ip_dst=self.vip, ip_src=self.src_vm_pa_ip, udp_sport=11638, @@ -221,8 +225,8 @@ def trafficTest(self): eth_src=self.eni_mac, ip_dst=self.dst_ca_ip, ip_src=src_vm_ip) - vxlan_pkt = simple_vxlan_packet(eth_dst=self.our_mac, - eth_src=outer_smac, + vxlan_pkt = simple_vxlan_packet(eth_dst=self.dut_mac, + eth_src=self.neighbor_mac, ip_dst=self.vip, ip_src=self.src_vm_pa_ip, udp_sport=11638, @@ -234,8 +238,8 @@ def trafficTest(self): eth_src=self.eni_mac, ip_dst=self.dst_ca_ip, ip_src=src_vm_ip) - vxlan_exp_pkt = simple_vxlan_packet(eth_dst="00:00:00:00:00:00", - eth_src="00:00:00:00:00:00", + vxlan_exp_pkt = simple_vxlan_packet(eth_dst=self.neighbor_mac, + eth_src=self.dut_mac, ip_dst=self.dst_pa_ip, ip_src=self.vip, udp_sport=0, # TODO: Fix sport in pipeline @@ -283,6 +287,10 @@ def tearDown(self): # Run standard PTF teardown super(SaiThriftVnetOutboundUdpPktTest, self).tearDown() + # restore default internal_config + set_internal_config(neighbor_mac = b'\x00\x00\x00\x00\x00\x00', + mac = b'\x00\x00\x00\x00\x00\x00') + class SaiThriftVnetOutboundUdpV6PktTest(SaiThriftVnetOutboundUdpPktTest): """ Test saithrift vnet outbound ipv6""" @@ -293,7 +301,6 @@ def setUp(self): self.outbound_vni = 60 self.vnet_vni = 50 self.eni_mac = "00:aa:aa:aa:aa:aa" - self.our_mac = "00:00:06:07:08:09" self.dst_ca_mac = "00:bb:bb:bb:bb:bb" self.vip = "172.16.1.200" self.outbound_vni = 50 @@ -311,7 +318,6 @@ def setUp(self): def trafficTest(self): src_vm_ip = "2000:aaaa::10a" - outer_smac = "00:00:03:06:06:06" # check VIP drop wrong_vip = "172.16.100.100" @@ -319,8 +325,8 @@ def trafficTest(self): eth_src=self.eni_mac, ipv6_dst=self.dst_ca_ip, ipv6_src=src_vm_ip) - vxlan_pkt = simple_vxlan_packet(eth_dst=self.our_mac, - eth_src=outer_smac, + vxlan_pkt = simple_vxlan_packet(eth_dst=self.dut_mac, + eth_src=self.neighbor_mac, ip_dst=wrong_vip, ip_src=self.src_vm_pa_ip, udp_sport=11638, @@ -338,8 +344,8 @@ def trafficTest(self): eth_src=self.eni_mac, ipv6_dst=wrong_dst_ca, ipv6_src=src_vm_ip) - vxlan_pkt = simple_vxlan_packet(eth_dst=self.our_mac, - eth_src=outer_smac, + vxlan_pkt = simple_vxlan_packet(eth_dst=self.dut_mac, + eth_src=self.neighbor_mac, ip_dst=self.vip, ip_src=self.src_vm_pa_ip, udp_sport=11638, @@ -357,8 +363,8 @@ def trafficTest(self): eth_src=self.eni_mac, ipv6_dst=wrong_dst_ca, ipv6_src=src_vm_ip) - vxlan_pkt = simple_vxlan_packet(eth_dst=self.our_mac, - eth_src=outer_smac, + vxlan_pkt = simple_vxlan_packet(eth_dst=self.dut_mac, + eth_src=self.neighbor_mac, ip_dst=self.vip, ip_src=self.src_vm_pa_ip, udp_sport=11638, @@ -375,8 +381,8 @@ def trafficTest(self): eth_src=self.eni_mac, ipv6_dst=self.dst_ca_ip, ipv6_src=src_vm_ip) - vxlan_pkt = simple_vxlan_packet(eth_dst=self.our_mac, - eth_src=outer_smac, + vxlan_pkt = simple_vxlan_packet(eth_dst=self.dut_mac, + eth_src=self.neighbor_mac, ip_dst=self.vip, ip_src=self.src_vm_pa_ip, udp_sport=11638, @@ -388,8 +394,8 @@ def trafficTest(self): eth_src=self.eni_mac, ipv6_dst=self.dst_ca_ip, ipv6_src=src_vm_ip) - vxlan_exp_pkt = simple_vxlan_packet(eth_dst="00:00:00:00:00:00", - eth_src="00:00:00:00:00:00", + vxlan_exp_pkt = simple_vxlan_packet(eth_dst=self.neighbor_mac, + eth_src=self.dut_mac, ip_dst=self.dst_pa_ip, ip_src=self.vip, udp_sport=0, # TODO: Fix sport in pipeline