class TestEtag(TestCase): supported_vf_driver = ['pci-stub', 'vfio-pci'] def set_up_all(self): self.dut_ports = self.dut.get_ports(self.nic) self.verify(self.nic in ['sagepond', 'sageville'], '802.1BR only support by sagepond and sageville') self.verify(len(self.dut_ports) >= 1, 'Insufficient ports') self.src_intf = self.tester.get_interface( self.tester.get_local_port(0)) self.src_mac = self.tester.get_mac(self.tester.get_local_port(0)) self.dst_mac = self.dut.get_mac_address(0) self.vm0 = None self.printFlag = self._enable_debug self.dut.send_expect('ls', '#') self.setup_vm_env_flag = 0 self.preset_host_cmds = list() def set_up(self): pass def setup_vm_env(self, driver='default'): ''' setup qemu virtual environment ''' if self.setup_vm_env_flag == 1: return self.used_dut_port_0 = self.dut_ports[0] self.dut.generate_sriov_vfs_by_port(self.used_dut_port_0, 2, driver=driver) self.sriov_vfs_port_0 = self.dut.ports_info[ self.used_dut_port_0]['vfs_port'] # set vf assign method and vf driver self.vf_driver = self.get_suite_cfg()['vf_driver'] if self.vf_driver is None: self.vf_driver = 'pci-stub' self.verify(self.vf_driver in self.supported_vf_driver, "Unspported vf driver") if self.vf_driver == 'pci-stub': self.vf_assign_method = 'pci-assign' else: self.vf_assign_method = 'vfio-pci' self.dut.send_expect('modprobe vfio-pci', '#') try: for port in self.sriov_vfs_port_0: port.bind_driver(self.vf_driver) time.sleep(1) vf0_prop = {'opt_host': self.sriov_vfs_port_0[0].pci} vf1_prop = {'opt_host': self.sriov_vfs_port_0[1].pci} # start testpmd without the two VFs on the host self.host_testpmd = PmdOutput(self.dut) eal_param = '-b %(vf0)s -b %(vf1)s' % { 'vf0': self.sriov_vfs_port_0[0].pci, 'vf1': self.sriov_vfs_port_0[1].pci } self.preset_host_testpmd(VM_CORES_MASK, eal_param) # set up VM0 ENV self.vm0 = QEMUKvm(self.dut, 'vm0', 'vf_etag') self.vm0.set_vm_device(driver=self.vf_assign_method, **vf0_prop) self.vm0.set_vm_device(driver=self.vf_assign_method, **vf1_prop) self.vm_dut_0 = self.vm0.start() if self.vm_dut_0 is None: raise Exception('Set up VM0 ENV failed!') except Exception as e: print e self.destroy_vm_env() raise Exception(e) def destroy_vm_env(self): #destroy testpmd in vm0 if getattr(self, 'vm0_testpmd', None) and self.vm0_testpmd: self.vm0_testpmd.execute_cmd('stop') self.vm0_testpmd.execute_cmd('quit', '# ') self.vm0_testpmd = None #destroy vm0 if getattr(self, 'vm0', None) and self.vm0: self.vm0_dut_ports = None self.vm0.stop() self.vm0 = None #destroy host testpmd if getattr(self, 'host_testpmd', None): self.host_testpmd.execute_cmd('quit', '# ') self.host_testpmd = None # reset used port's sriov if getattr(self, 'used_dut_port_0', None): self.dut.destroy_sriov_vfs_by_port(self.used_dut_port_0) port = self.dut.ports_info[self.used_dut_port_0]['port'] port.bind_driver() self.used_dut_port_0 = None # bind used ports with default driver for port_id in self.dut_ports: port = self.dut.ports_info[port_id]['port'] port.bind_driver() self.setup_vm_env_flag = 0 def check_packet_transmission(self, pkt_types): time.sleep(1) for pkt_type in pkt_types.keys(): intf = self.src_intf pkt = Packet(pkt_type=pkt_type) # set packet every layer's input parameters if 'layer_configs' in pkt_types[pkt_type].keys(): pkt_configs = pkt_types[pkt_type]['layer_configs'] if pkt_configs: for layer in pkt_configs.keys(): pkt.config_layer(layer, pkt_configs[layer]) pkt.send_pkt(tx_port=self.src_intf) # check vm testpmd packet received information if 'vm' in pkt_types[pkt_type].keys(): out = self.vm0_testpmd.get_output(timeout=2) if self.printFlag: # debug output print out for pkt_attribute in pkt_types[pkt_type]['vm']: if self.printFlag: # debug output print pkt_attribute if pkt_attribute not in out: print utils.RED('Fail to detect %s' % pkt_attribute) if not self.printFlag: # print out all info in debug mode raise VerifyFailure('Failed to detect %s' % pkt_attribute) print utils.GREEN('VM detected %s successfully' % pkt_type) # check dut testpmd packet received information if 'dut' in pkt_types[pkt_type].keys(): out = self.host_testpmd.get_output(timeout=2) if self.printFlag: # debug output print out for pkt_attribute in pkt_types[pkt_type]['dut']: if self.printFlag: # debug output print pkt_attribute if pkt_attribute not in out: print utils.RED('Fail to detect %s' % pkt_attribute) if not self.printFlag: # print out all info in debug mode raise VerifyFailure('Failed to detect %s' % pkt_attribute) print utils.GREEN('DUT detected %s successfully' % pkt_type) time.sleep(1) def preset_host_testpmd(self, core_mask, eal_param): if self.setup_vm_env_flag == 0: self.host_testpmd.start_testpmd(core_mask, param='--port-topology=loop', eal_param=eal_param) self.execute_host_testpmd_cmd(self.preset_host_cmds) self.preset_host_cmds = list() time.sleep(2) def execute_host_testpmd_cmd(self, cmds): if len(cmds) == 0: return for item in cmds: if len(item) == 2: self.host_testpmd.execute_cmd(item[0], int(item[1])) else: self.host_testpmd.execute_cmd(item[0]) time.sleep(2) def preset_guest_testpmd(self): if self.setup_vm_env_flag == 0: self.vm0_testpmd = PmdOutput(self.vm_dut_0) self.vm0_testpmd.start_testpmd(VM_CORES_MASK, param='--port-topology=loop') time.sleep(1) elif self.vm0_testpmd: self.vm0_testpmd.quit() self.vm0_testpmd.start_testpmd(VM_CORES_MASK, param='--port-topology=loop') time.sleep(1) def execute_guest_testpmd_cmd(self, cmds): if len(cmds) == 0: return for item in cmds: if len(item) == 2: self.vm0_testpmd.execute_cmd(item[0], int(item[1])) else: self.vm0_testpmd.execute_cmd(item[0]) def preset_test_enviroment(self): self.setup_vm_env(driver='igb_uio') self.preset_guest_testpmd() self.setup_vm_env_flag = 1 time.sleep(2) def test_l2_tunnel_filter(self): ''' Enable E-tag l2 tunnel support means enabling ability of parsing E-tag packet. This ability should be enabled before we enable filtering, forwarding, offloading for this specific type of tunnel. ''' host_cmds = [['port config 0 l2-tunnel E-tag enable'], ['set fwd rxonly'], ['set verbose 1'], ['start']] guest_cmds = [['set fwd rxonly'], ['set verbose 1'], ['start']] config_layers = { 'ether': { 'src': self.src_mac }, 'etag': { 'ECIDbase': 1000 } } pkt_types = { 'ETAG_UDP': { 'dut': ['type=0x893f'], 'vm': ['type=0x893f'], 'layer_configs': config_layers } } self.preset_test_enviroment() self.execute_host_testpmd_cmd(host_cmds) self.execute_guest_testpmd_cmd(guest_cmds) self.check_packet_transmission(pkt_types) def test_etag_filter(self): ''' when E-tag packet forwarding and add E-tag on VF0 ''' test_types = ['etag_pf', 'etag_remove', 'etag_vf_0', 'etag_vf_1'] host_cmds = [['port config 0 l2-tunnel E-tag enable'], ['E-tag set forwarding on port 0']] self.preset_test_enviroment() self.execute_host_testpmd_cmd(host_cmds) for test_type in test_types: host_cmds = list() guest_cmds = [['set fwd rxonly'], ['set verbose 1'], ['start']] if test_type == 'etag_pf': # Same E-tag forwarding to PF0, Send 802.1BR packet with broadcast mac and # check packet only received on PF host_cmds = [[ 'E-tag set filter add e-tag-id 1000 dst-pool 2 port 0' ], ['set fwd mac'], ['set verbose 1'], ['start']] # set packet type and its expecting result config_layers = { 'ether': { 'src': self.src_mac, 'dst': self.dst_mac }, 'etag': { 'ECIDbase': 1000 } } pkt_types = { 'ETAG_UDP': { 'dut': ['type=0x893f'], 'layer_configs': config_layers } } elif test_type == 'etag_remove': # Remove E-tag, Send 802.1BR packet with broadcast mac and check packet not # received host_cmds = [['E-tag set filter del e-tag-id 1000 port 0'], ['set fwd rxonly'], ['set verbose 1'], ['start']] config_layers = { 'ether': { 'src': self.src_mac }, 'etag': { 'ECIDbase': 1000 } } pkt_types = { 'ETAG_UDP': { 'vm': [''], 'dut': [''], 'layer_configs': config_layers } } else: # Same E-tag forwarding to VF0, Send 802.1BR packet with broadcast mac and # check packet only received on VF0 or VF1 host_cmds = [[ 'E-tag set filter add e-tag-id 1000 dst-pool %d port 0' % int(test_type[-1:]) ], ['set fwd rxonly'], ['set verbose 1'], ['start']] config_layers = { 'ether': { 'src': self.src_mac }, 'etag': { 'ECIDbase': 1000 } } pkt_types = { 'ETAG_UDP': { 'vm': ['type=0x893f'], 'layer_configs': config_layers } } self.execute_host_testpmd_cmd(host_cmds) self.execute_guest_testpmd_cmd(guest_cmds) self.check_packet_transmission(pkt_types) self.host_testpmd.execute_cmd('E-tag set forwarding off port 0') def test_etag_insertion(self): ''' When E-tag insertion enable in VF0 ''' host_cmds = [['port config 0 l2-tunnel E-tag enable'], ['E-tag set insertion on port-tag-id 1000 port 0 vf 0'], ['set fwd mac'], ['set verbose 1'], ['start']] guest_cmds = [['set fwd mac'], ['set verbose 1'], ['start']] self.preset_test_enviroment() self.execute_host_testpmd_cmd(host_cmds) self.execute_guest_testpmd_cmd(guest_cmds) self.vm0_dut_ports = self.vm_dut_0.get_ports('any') config_layers = {'ether': {'src': self.src_mac}} pkt_types = {'IP_RAW': {'layer_configs': config_layers}} intf = self.src_intf inst = self.tester.tcpdump_sniff_packets(intf) self.check_packet_transmission(pkt_types) time.sleep(1) pkts = self.tester.load_tcpdump_sniff_packets(inst) self.host_testpmd.execute_cmd( 'E-tag set insertion off port-tag-id 1000 port 0 vf 0') # load sniff pcap file, check received packet's content packetContentFile = "/tmp/packetContent.log" pcap_file = "/tmp/sniff_%s.pcap" % intf fp = open(packetContentFile, 'w') backup_out = sys.stdout sys.stdout = fp pkts = rdpcap(pcap_file) pkts.show() fp.close() sys.stdout = backup_out fp = open(packetContentFile, 'r') out = fp.read() fp.close() if self.printFlag: # debug output print out self.verify("Dot1BR" in out, "tester %s hasn't receiver etag packet" % intf) def test_etag_strip(self): ''' When E-tag strip enable on PF ''' host_cmds = [['port config 0 l2-tunnel E-tag enable'], ['set fwd rxonly'], ['set verbose 1'], ['start']] guest_cmds = [['set fwd rxonly'], ['set verbose 1'], ['start']] config_layers = { 'ether': { 'src': self.src_mac }, 'etag': { 'ECIDbase': 1000 } } pkt_types_on = { 'ETAG_UDP': { 'vm': ['type=0x0800', 'type=0x893f'], 'layer_configs': config_layers } } pkt_types_off = { 'ETAG_UDP': { 'vm': ['type=0x893f', 'type=0x893f'], 'layer_configs': config_layers } } self.preset_test_enviroment() self.execute_host_testpmd_cmd(host_cmds) self.execute_guest_testpmd_cmd(guest_cmds) # Enable E-tag strip on PF, Send 802.1BR packet to VF and check forwarded packet without E-tag self.host_testpmd.execute_cmd('E-tag set stripping on port 0') self.check_packet_transmission(pkt_types_on) # Disable E-tag strip on PF, Send 802.1BR packet and check forwarded packet with E-tag self.host_testpmd.execute_cmd('E-tag set stripping off port 0') self.check_packet_transmission(pkt_types_off) def tear_down(self): pass def tear_down_all(self): if self.setup_vm_env_flag == 1: self.destroy_vm_env() if getattr(self, 'vm0', None): self.vm0.stop() for port_id in self.dut_ports: self.dut.destroy_sriov_vfs_by_port(port_id) self.tester.send_expect( "kill -9 $(ps aux | grep -i qemu | grep -v grep | awk {'print $2'})", '# ', 5)
class TestCloudFilter(TestCase): def set_up_all(self): """ vxlan Prerequisites """ # this feature only enable in FVL now self.verify( self.nic in [ "fortville_eagle", "fortville_spirit", "fortville_spirit_single" ], "Cloud filter only supported by Fortville") # Based on h/w type, choose how many ports to use self.dut_ports = self.dut.get_ports() # Verify that enough ports are available self.verify(len(self.dut_ports) >= 1, "Insufficient ports for testing") # required setting test environment self.env_done = False self.vf_queues = 4 def setup_vf_env(self): """ Create testing environment with 2VFs generated from PF """ if self.env_done: return # get PF interface name and opposite tester interface name self.pf_port = self.dut_ports[0] self.bind_nics_driver([self.pf_port], driver="i40e") self.pf_intf = self.dut.ports_info[self.pf_port]['intf'] tester_port = self.tester.get_local_port(self.pf_port) self.tester_intf = self.tester.get_interface(tester_port) self.tester_mac = self.tester.get_mac(tester_port) pf_numa = self.dut.get_numa_id(self.pf_port) self.dut.generate_sriov_vfs_by_port(self.pf_port, 2, driver="default") # enable vxlan on PF self.dut.send_expect( "ip li add vxlan0 type vxlan id 1 group " + "239.1.1.1 local 127.0.0.1 dev %s" % self.pf_intf, "# ") self.dut.send_expect("ifconfig vxlan0 up", "# ") self.vf_port0 = self.dut.ports_info[self.pf_port]['vfs_port'][0] self.vf_port1 = self.dut.ports_info[self.pf_port]['vfs_port'][1] # bind one vf device to dpdk self.vf_port0.bind_driver(driver='igb_uio') self.vf_port1.bind_driver(driver='i40evf') self.vf_intf = self.vf_port1.intf_name # bind vf0 to igb_uio and start testpmd core_num = self.vf_queues + 1 cores = "1S/%dC/1T" % core_num self.pmdout = PmdOutput(self.dut) self.pmdout.start_testpmd( cores, "--rxq=%d --txq=%d --portmask=0x1 --enable-rx-cksum" % (self.vf_queues, self.vf_queues), socket=pf_numa) # rxonly and verbose enabled self.pmdout.execute_cmd("set nbcore %d" % self.vf_queues) self.pmdout.execute_cmd("set fwd rxonly") self.pmdout.execute_cmd("set verbose 1") self.pmdout.execute_cmd("start") self.env_done = True def destroy_vf_env(self): if getattr(self, 'pmd_output', None): self.dut.kill_all() if getattr(self, 'pf_port', None): self.dut.destroy_sriov_vfs_by_port(self.pf_port) self.bind_nics_driver([self.pf_port], driver="igb_uio") self.env_done = False def bind_nics_driver(self, ports, driver=""): # modprobe vfio driver if driver == "vfio-pci": for port in ports: netdev = self.dut.ports_info[port]['port'] driver = netdev.get_nic_driver() if driver != 'vfio-pci': netdev.bind_driver(driver='vfio-pci') elif driver == "igb_uio": # igb_uio should insmod as default, no need to check for port in ports: netdev = self.dut.ports_info[port]['port'] driver = netdev.get_nic_driver() if driver != 'igb_uio': netdev.bind_driver(driver='igb_uio') else: for port in ports: netdev = self.dut.ports_info[port]['port'] driver_now = netdev.get_nic_driver() if driver == "": driver = netdev.default_driver if driver != driver_now: netdev.bind_driver(driver=driver) def send_and_verify(self, cloud_cfg=None, dpdk=True): """ Send packet match cloud filter rule and verify packet received """ self.logger.info("Verifying vxlan %s filter" % cloud_cfg.cf_rule['type']) if dpdk: cloud_cfg.transmit_packet() out = self.pmdout.get_output() print out queue = cloud_cfg.cf_rule['queue'] self.verify("queue %d" % queue in out, "Vxlan not received in queue %d" % queue) self.verify("VXLAN packet" in out, "Vxlan packet not detected") self.verify("Inner L4 type: TCP" in out, "Vxlan inner L4 type not detected") if 'vni' in cloud_cfg.cf_rule.keys(): vni = cloud_cfg.cf_rule['vni'] self.verify("VNI = %d" % vni in out, "Vxlan vni value not correct") if 'ivlan' in cloud_cfg.cf_rule.keys(): self.verify("Inner L2 type: ETHER_VLAN" in out, "Vxlan inner vlan not detected") else: # packet received on dut VF device tmp_file = '/tmp/cloud_filter_%s.pcap' % self.vf_intf sniff_cmd = ('tcpdump -w ' + tmp_file + ' -i {0} 2>tcpdump_{0}.out &').format(self.vf_intf) rm_cmd = 'rm -f ' + tmp_file self.dut.send_expect(rm_cmd, '#', alt_session=True) self.dut.send_expect(sniff_cmd, '#', alt_session=True) # wait for interface promisc enable time.sleep(2) cloud_cfg.transmit_packet() self.dut.send_expect('killall tcpdump', '#', alt_session=True) # wait for pcap file saved time.sleep(2) # copy pcap to tester and then analyze self.dut.session.copy_file_from(tmp_file) pkts = load_pcapfile(filename="cloud_filter_%s.pcap" % self.vf_intf) self.verify( len(pkts) == 1, "%d packet recevied on kernel VF" % len(pkts)) cap_pkt = pkts[0].pktgen.pkt try: dport = cap_pkt[UDP].dport self.verify(dport == CLOUD_PORT, "Captured packet is not vxlan packet") inner_ip = cap_pkt[Vxlan][IP].dst self.verify(inner_ip == cloud_cfg.cf_rule['iip'], "Inner ip not matched") except: print "Kernel VF captured packet not match rule" raise self.logger.info("Verified vxlan %s filter pass" % cloud_cfg.cf_rule['type']) def test_cloud_filter(self): """ Verify dpdk work with linux driver added cloud filter rule """ # setting for cloud filter rule queue = self.vf_queues - 1 vni = 1 vlan = 1 # add cloud filter rule rules = [ { 'type': 'iip', 'iip': '192.168.1.1', 'vf': 0, 'queue': queue, 'loc': 1 }, { 'type': 'imac', 'imac': '00:00:00:00:09:00', 'vf': 0, 'queue': queue, 'loc': 1 }, { 'type': 'omac+imac+vni', 'omac': '00:00:00:00:10:00', 'imac': '00:00:00:00:09:00', 'vni': vni, 'vf': 0, 'queue': queue, 'loc': 1 }, { 'type': 'imac+ivlan+vni', 'imac': '00:00:00:00:09:00', 'ivlan': vlan, 'vni': vni, 'vf': 0, 'queue': queue, 'loc': 1 }, { 'type': 'imac+ivlan', 'imac': '00:00:00:00:09:00', 'ivlan': vlan, 'vf': 0, 'queue': queue, 'loc': 1 }, ] cf_cfg = CloudFilterConfig(self, self.pf_intf) for rule in rules: cf_cfg.config_rule(**rule) cf_cfg.ethtool_add() self.send_and_verify(cf_cfg) cf_cfg.ethtool_delete() def test_bifurcated_driver(self): """ Verify bifurcated driver work with dpdk VF and kernel VF """ rules = [{ 'type': 'iip', 'iip': '192.168.1.1', 'vf': 0, 'queue': self.vf_queues - 1, 'loc': 1 }, { 'type': 'iip', 'iip': '192.168.2.1', 'vf': 1, 'queue': 0, 'loc': 2 }] dpdk_cfg = CloudFilterConfig(self, self.pf_intf) # fdir rule for dpdk VF dpdk_cfg.config_rule(**rules[0]) dpdk_cfg.ethtool_add() self.send_and_verify(dpdk_cfg) # fdir rule for kernel VF kernel_cfg = CloudFilterConfig(self, self.pf_intf) kernel_cfg.config_rule(**rules[1]) kernel_cfg.ethtool_add() self.send_and_verify(kernel_cfg, dpdk=False) pass def set_up(self): """ Run before each test case. """ self.setup_vf_env() pass def tear_down(self): """ Run after each test case. """ pass def tear_down_all(self): """ Run after each test suite. """ self.destroy_vf_env() pass