X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=test%2Ftest_flowprobe.py;h=e3ff2245ad1c5d9cde8bab8284192b7df6f76995;hb=6531cf5d1cffab8690c42847eef4f00f3018bb70;hp=6b271790f7654fe1b58244577464fdce6339287b;hpb=d9b0c6fbf7aa5bd9af84264105b39c82028a4a29;p=vpp.git diff --git a/test/test_flowprobe.py b/test/test_flowprobe.py index 6b271790f76..e3ff2245ad1 100644 --- a/test/test_flowprobe.py +++ b/test/test_flowprobe.py @@ -13,7 +13,8 @@ from scapy.layers.inet import IP, TCP, UDP from scapy.layers.inet6 import IPv6 from config import config -from framework import tag_fixme_vpp_workers +from framework import tag_fixme_vpp_workers, tag_fixme_ubuntu2204, tag_fixme_debian11 +from framework import is_distro_ubuntu2204, is_distro_debian11 from framework import VppTestCase, VppTestRunner from framework import tag_run_solo from vpp_object import VppObject @@ -39,9 +40,11 @@ class VppCFLOW(VppObject): mtu=1024, datapath="l2", layer="l2 l3 l4", + direction="tx", ): self._test = test self._intf = intf + self._intf_obj = getattr(self._test, intf) self._active = active if passive == 0 or passive < active: self._passive = active + 1 @@ -49,6 +52,7 @@ class VppCFLOW(VppObject): self._passive = passive self._datapath = datapath # l2 ip4 ip6 self._collect = layer # l2 l3 l4 + self._direction = direction # rx tx both self._timeout = timeout self._mtu = mtu self._configured = False @@ -64,7 +68,7 @@ class VppCFLOW(VppObject): l3_flag = VppEnum.vl_api_flowprobe_record_flags_t.FLOWPROBE_RECORD_FLAG_L3 if "l4" in self._collect.lower(): l4_flag = VppEnum.vl_api_flowprobe_record_flags_t.FLOWPROBE_RECORD_FLAG_L4 - self._test.vapi.flowprobe_params( + self._test.vapi.flowprobe_set_params( record_flags=(l2_flag | l3_flag | l4_flag), active_timer=self._active, passive_timer=self._passive, @@ -87,18 +91,32 @@ class VppCFLOW(VppObject): template_interval=self._timeout, ) - def enable_flowprobe_feature(self): - self._test.vapi.ppcli( - "flowprobe feature add-del %s %s" % (self._intf, self._datapath) + def _enable_disable_flowprobe_feature(self, is_add): + which_map = { + "l2": VppEnum.vl_api_flowprobe_which_t.FLOWPROBE_WHICH_L2, + "ip4": VppEnum.vl_api_flowprobe_which_t.FLOWPROBE_WHICH_IP4, + "ip6": VppEnum.vl_api_flowprobe_which_t.FLOWPROBE_WHICH_IP6, + } + direction_map = { + "rx": VppEnum.vl_api_flowprobe_direction_t.FLOWPROBE_DIRECTION_RX, + "tx": VppEnum.vl_api_flowprobe_direction_t.FLOWPROBE_DIRECTION_TX, + "both": VppEnum.vl_api_flowprobe_direction_t.FLOWPROBE_DIRECTION_BOTH, + } + self._test.vapi.flowprobe_interface_add_del( + is_add=is_add, + which=which_map[self._datapath], + direction=direction_map[self._direction], + sw_if_index=self._intf_obj.sw_if_index, ) + def enable_flowprobe_feature(self): + self._enable_disable_flowprobe_feature(is_add=True) + def disable_exporter(self): self._test.vapi.cli("set ipfix exporter collector 0.0.0.0") def disable_flowprobe_feature(self): - self._test.vapi.cli( - "flowprobe feature add-del %s %s disable" % (self._intf, self._datapath) - ) + self._enable_disable_flowprobe_feature(is_add=False) def object_id(self): return "ipfix-collector-%s-%s" % (self._src, self.dst) @@ -134,6 +152,10 @@ class MethodHolder(VppTestCase): variables and configure VPP. """ super(MethodHolder, cls).setUpClass() + if (is_distro_ubuntu2204 == True or is_distro_debian11 == True) and not hasattr( + cls, "vpp" + ): + return try: # Create pg interfaces cls.create_pg_interfaces(range(9)) @@ -261,8 +283,6 @@ class MethodHolder(VppTestCase): continue for field in data_set: - if field not in record.keys(): - continue value = data_set[field] if value == "octets": value = ip_layer.len @@ -322,6 +342,8 @@ class MethodHolder(VppTestCase): @tag_run_solo @tag_fixme_vpp_workers +@tag_fixme_ubuntu2204 +@tag_fixme_debian11 class Flowprobe(MethodHolder): """Template verification, timer tests""" @@ -434,6 +456,8 @@ class Flowprobe(MethodHolder): self.assertEqual(int(binascii.hexlify(record[10]), 16), 8) # egress interface self.assertEqual(int(binascii.hexlify(record[14]), 16), 9) + # direction + self.assertEqual(int(binascii.hexlify(record[61]), 16), 1) # packets self.assertEqual(int(binascii.hexlify(record[2]), 16), 1) # src mac @@ -464,25 +488,117 @@ class Flowprobe(MethodHolder): ipfix.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0000") + def test_interface_dump(self): + """Dump interfaces with IPFIX flow record generation enabled""" + self.logger.info("FFP_TEST_START_0003") -@tag_fixme_vpp_workers -class Datapath(MethodHolder): + # Enable feature for 3 interfaces + ipfix1 = VppCFLOW(test=self, intf="pg1", datapath="l2", direction="rx") + ipfix1.add_vpp_config() + + ipfix2 = VppCFLOW(test=self, intf="pg2", datapath="ip4", direction="tx") + ipfix2.enable_flowprobe_feature() + + ipfix3 = VppCFLOW(test=self, intf="pg3", datapath="ip6", direction="both") + ipfix3.enable_flowprobe_feature() + + # When request "all", dump should contain all enabled interfaces + dump = self.vapi.flowprobe_interface_dump() + self.assertEqual(len(dump), 3) + + # Verify 1st interface + self.assertEqual(dump[0].sw_if_index, self.pg1.sw_if_index) + self.assertEqual( + dump[0].which, VppEnum.vl_api_flowprobe_which_t.FLOWPROBE_WHICH_L2 + ) + self.assertEqual( + dump[0].direction, + VppEnum.vl_api_flowprobe_direction_t.FLOWPROBE_DIRECTION_RX, + ) + + # Verify 2nd interface + self.assertEqual(dump[1].sw_if_index, self.pg2.sw_if_index) + self.assertEqual( + dump[1].which, VppEnum.vl_api_flowprobe_which_t.FLOWPROBE_WHICH_IP4 + ) + self.assertEqual( + dump[1].direction, + VppEnum.vl_api_flowprobe_direction_t.FLOWPROBE_DIRECTION_TX, + ) + + # Verify 3rd interface + self.assertEqual(dump[2].sw_if_index, self.pg3.sw_if_index) + self.assertEqual( + dump[2].which, VppEnum.vl_api_flowprobe_which_t.FLOWPROBE_WHICH_IP6 + ) + self.assertEqual( + dump[2].direction, + VppEnum.vl_api_flowprobe_direction_t.FLOWPROBE_DIRECTION_BOTH, + ) + + # When request 2nd interface, dump should contain only the specified interface + dump = self.vapi.flowprobe_interface_dump(sw_if_index=self.pg2.sw_if_index) + self.assertEqual(len(dump), 1) + + # Verify 2nd interface + self.assertEqual(dump[0].sw_if_index, self.pg2.sw_if_index) + self.assertEqual( + dump[0].which, VppEnum.vl_api_flowprobe_which_t.FLOWPROBE_WHICH_IP4 + ) + self.assertEqual( + dump[0].direction, + VppEnum.vl_api_flowprobe_direction_t.FLOWPROBE_DIRECTION_TX, + ) + + # When request 99th interface, dump should be empty + dump = self.vapi.flowprobe_interface_dump(sw_if_index=99) + self.assertEqual(len(dump), 0) + + ipfix1.remove_vpp_config() + ipfix2.remove_vpp_config() + ipfix3.remove_vpp_config() + self.logger.info("FFP_TEST_FINISH_0003") + + def test_get_params(self): + """Get IPFIX flow record generation parameters""" + self.logger.info("FFP_TEST_START_0004") + + # Enable feature for an interface with custom parameters + ipfix = VppCFLOW(test=self, active=20, passive=40, layer="l2 l3 l4") + ipfix.add_vpp_config() + + # Get and verify parameters + params = self.vapi.flowprobe_get_params() + self.assertEqual(params.active_timer, 20) + self.assertEqual(params.passive_timer, 40) + record_flags = VppEnum.vl_api_flowprobe_record_flags_t.FLOWPROBE_RECORD_FLAG_L2 + record_flags |= VppEnum.vl_api_flowprobe_record_flags_t.FLOWPROBE_RECORD_FLAG_L3 + record_flags |= VppEnum.vl_api_flowprobe_record_flags_t.FLOWPROBE_RECORD_FLAG_L4 + self.assertEqual(params.record_flags, record_flags) + + ipfix.remove_vpp_config() + self.logger.info("FFP_TEST_FINISH_0004") + + +class DatapathTestsHolder(object): """collect information on Ethernet, IP4 and IP6 datapath (no timers)""" @classmethod def setUpClass(cls): - super(Datapath, cls).setUpClass() + super(DatapathTestsHolder, cls).setUpClass() @classmethod def tearDownClass(cls): - super(Datapath, cls).tearDownClass() + super(DatapathTestsHolder, cls).tearDownClass() def test_templatesL2(self): """verify template on L2 datapath""" self.logger.info("FFP_TEST_START_0000") self.pg_enable_capture(self.pg_interfaces) - ipfix = VppCFLOW(test=self, layer="l2") + ipfix = VppCFLOW( + test=self, intf=self.intf1, layer="l2", direction=self.direction + ) ipfix.add_vpp_config() # template packet should arrive immediately @@ -499,7 +615,9 @@ class Datapath(MethodHolder): self.pg_enable_capture(self.pg_interfaces) self.pkts = [] - ipfix = VppCFLOW(test=self, layer="l2") + ipfix = VppCFLOW( + test=self, intf=self.intf1, layer="l2", direction=self.direction + ) ipfix.add_vpp_config() ipfix_decoder = IPFIXDecoder() @@ -513,7 +631,10 @@ class Datapath(MethodHolder): self.vapi.ipfix_flush() cflow = self.wait_for_cflow_packet(self.collector, templates[0]) self.verify_cflow_data_detail( - ipfix_decoder, capture, cflow, {2: "packets", 256: 8} + ipfix_decoder, + capture, + cflow, + {2: "packets", 256: 8, 61: (self.direction == "tx")}, ) self.collector.get_capture(2) @@ -526,7 +647,9 @@ class Datapath(MethodHolder): self.pg_enable_capture(self.pg_interfaces) self.pkts = [] - ipfix = VppCFLOW(test=self, layer="l3") + ipfix = VppCFLOW( + test=self, intf=self.intf1, layer="l3", direction=self.direction + ) ipfix.add_vpp_config() ipfix_decoder = IPFIXDecoder() @@ -543,7 +666,13 @@ class Datapath(MethodHolder): ipfix_decoder, capture, cflow, - {2: "packets", 4: 17, 8: "src_ip", 12: "dst_ip"}, + { + 2: "packets", + 4: 17, + 8: "src_ip", + 12: "dst_ip", + 61: (self.direction == "tx"), + }, ) self.collector.get_capture(3) @@ -557,7 +686,9 @@ class Datapath(MethodHolder): self.pg_enable_capture(self.pg_interfaces) self.pkts = [] - ipfix = VppCFLOW(test=self, layer="l4") + ipfix = VppCFLOW( + test=self, intf=self.intf1, layer="l4", direction=self.direction + ) ipfix.add_vpp_config() ipfix_decoder = IPFIXDecoder() @@ -571,7 +702,10 @@ class Datapath(MethodHolder): self.vapi.ipfix_flush() cflow = self.wait_for_cflow_packet(self.collector, templates[0]) self.verify_cflow_data_detail( - ipfix_decoder, capture, cflow, {2: "packets", 7: "sport", 11: "dport"} + ipfix_decoder, + capture, + cflow, + {2: "packets", 7: "sport", 11: "dport", 61: (self.direction == "tx")}, ) self.collector.get_capture(3) @@ -585,7 +719,9 @@ class Datapath(MethodHolder): self.pg_enable_capture(self.pg_interfaces) - ipfix = VppCFLOW(test=self, datapath="ip4") + ipfix = VppCFLOW( + test=self, intf=self.intf1, datapath="ip4", direction=self.direction + ) ipfix.add_vpp_config() # template packet should arrive immediately @@ -603,7 +739,13 @@ class Datapath(MethodHolder): self.pg_enable_capture(self.pg_interfaces) self.pkts = [] - ipfix = VppCFLOW(test=self, intf="pg4", layer="l2", datapath="ip4") + ipfix = VppCFLOW( + test=self, + intf=self.intf2, + layer="l2", + datapath="ip4", + direction=self.direction, + ) ipfix.add_vpp_config() ipfix_decoder = IPFIXDecoder() @@ -617,7 +759,10 @@ class Datapath(MethodHolder): self.vapi.ipfix_flush() cflow = self.wait_for_cflow_packet(self.collector, templates[0]) self.verify_cflow_data_detail( - ipfix_decoder, capture, cflow, {2: "packets", 256: 8} + ipfix_decoder, + capture, + cflow, + {2: "packets", 256: 8, 61: (self.direction == "tx")}, ) # expected two templates and one cflow packet @@ -632,7 +777,13 @@ class Datapath(MethodHolder): self.pg_enable_capture(self.pg_interfaces) self.pkts = [] - ipfix = VppCFLOW(test=self, intf="pg4", layer="l3", datapath="ip4") + ipfix = VppCFLOW( + test=self, + intf=self.intf2, + layer="l3", + datapath="ip4", + direction=self.direction, + ) ipfix.add_vpp_config() ipfix_decoder = IPFIXDecoder() @@ -649,7 +800,13 @@ class Datapath(MethodHolder): ipfix_decoder, capture, cflow, - {1: "octets", 2: "packets", 8: "src_ip", 12: "dst_ip"}, + { + 1: "octets", + 2: "packets", + 8: "src_ip", + 12: "dst_ip", + 61: (self.direction == "tx"), + }, ) # expected two templates and one cflow packet @@ -664,7 +821,13 @@ class Datapath(MethodHolder): self.pg_enable_capture(self.pg_interfaces) self.pkts = [] - ipfix = VppCFLOW(test=self, intf="pg4", layer="l4", datapath="ip4") + ipfix = VppCFLOW( + test=self, + intf=self.intf2, + layer="l4", + datapath="ip4", + direction=self.direction, + ) ipfix.add_vpp_config() ipfix_decoder = IPFIXDecoder() @@ -678,7 +841,10 @@ class Datapath(MethodHolder): self.vapi.ipfix_flush() cflow = self.wait_for_cflow_packet(self.collector, templates[0]) self.verify_cflow_data_detail( - ipfix_decoder, capture, cflow, {2: "packets", 7: "sport", 11: "dport"} + ipfix_decoder, + capture, + cflow, + {2: "packets", 7: "sport", 11: "dport", 61: (self.direction == "tx")}, ) # expected two templates and one cflow packet @@ -692,7 +858,9 @@ class Datapath(MethodHolder): self.logger.info("FFP_TEST_START_0000") self.pg_enable_capture(self.pg_interfaces) - ipfix = VppCFLOW(test=self, datapath="ip6") + ipfix = VppCFLOW( + test=self, intf=self.intf1, datapath="ip6", direction=self.direction + ) ipfix.add_vpp_config() # template packet should arrive immediately @@ -709,7 +877,13 @@ class Datapath(MethodHolder): self.pg_enable_capture(self.pg_interfaces) self.pkts = [] - ipfix = VppCFLOW(test=self, intf="pg6", layer="l2", datapath="ip6") + ipfix = VppCFLOW( + test=self, + intf=self.intf3, + layer="l2", + datapath="ip6", + direction=self.direction, + ) ipfix.add_vpp_config() ipfix_decoder = IPFIXDecoder() @@ -723,7 +897,11 @@ class Datapath(MethodHolder): self.vapi.ipfix_flush() cflow = self.wait_for_cflow_packet(self.collector, templates[0]) self.verify_cflow_data_detail( - ipfix_decoder, capture, cflow, {2: "packets", 256: 56710}, ip_ver="v6" + ipfix_decoder, + capture, + cflow, + {2: "packets", 256: 56710, 61: (self.direction == "tx")}, + ip_ver="v6", ) # expected two templates and one cflow packet @@ -738,7 +916,13 @@ class Datapath(MethodHolder): self.pg_enable_capture(self.pg_interfaces) self.pkts = [] - ipfix = VppCFLOW(test=self, intf="pg6", layer="l3", datapath="ip6") + ipfix = VppCFLOW( + test=self, + intf=self.intf3, + layer="l3", + datapath="ip6", + direction=self.direction, + ) ipfix.add_vpp_config() ipfix_decoder = IPFIXDecoder() @@ -755,7 +939,7 @@ class Datapath(MethodHolder): ipfix_decoder, capture, cflow, - {2: "packets", 27: "src_ip", 28: "dst_ip"}, + {2: "packets", 27: "src_ip", 28: "dst_ip", 61: (self.direction == "tx")}, ip_ver="v6", ) @@ -771,7 +955,13 @@ class Datapath(MethodHolder): self.pg_enable_capture(self.pg_interfaces) self.pkts = [] - ipfix = VppCFLOW(test=self, intf="pg6", layer="l4", datapath="ip6") + ipfix = VppCFLOW( + test=self, + intf=self.intf3, + layer="l4", + datapath="ip6", + direction=self.direction, + ) ipfix.add_vpp_config() ipfix_decoder = IPFIXDecoder() @@ -788,7 +978,7 @@ class Datapath(MethodHolder): ipfix_decoder, capture, cflow, - {2: "packets", 7: "sport", 11: "dport"}, + {2: "packets", 7: "sport", 11: "dport", 61: (self.direction == "tx")}, ip_ver="v6", ) @@ -804,7 +994,7 @@ class Datapath(MethodHolder): self.pg_enable_capture(self.pg_interfaces) self.pkts = [] - ipfix = VppCFLOW(test=self) + ipfix = VppCFLOW(test=self, intf=self.intf1, direction=self.direction) ipfix.add_vpp_config() ipfix_decoder = IPFIXDecoder() @@ -824,12 +1014,12 @@ class Datapath(MethodHolder): self.logger.info("FFP_TEST_FINISH_0001") def test_0002(self): - """no timers, two CFLOW packets (mtu=256), 3 Flows in each""" + """no timers, two CFLOW packets (mtu=260), 3 Flows in each""" self.logger.info("FFP_TEST_START_0002") self.pg_enable_capture(self.pg_interfaces) self.pkts = [] - ipfix = VppCFLOW(test=self, mtu=256) + ipfix = VppCFLOW(test=self, intf=self.intf1, direction=self.direction, mtu=260) ipfix.add_vpp_config() ipfix_decoder = IPFIXDecoder() @@ -852,6 +1042,26 @@ class Datapath(MethodHolder): self.logger.info("FFP_TEST_FINISH_0002") +@tag_fixme_vpp_workers +class DatapathTx(MethodHolder, DatapathTestsHolder): + """Collect info on Ethernet, IP4 and IP6 datapath (TX) (no timers)""" + + intf1 = "pg2" + intf2 = "pg4" + intf3 = "pg6" + direction = "tx" + + +@tag_fixme_vpp_workers +class DatapathRx(MethodHolder, DatapathTestsHolder): + """Collect info on Ethernet, IP4 and IP6 datapath (RX) (no timers)""" + + intf1 = "pg1" + intf2 = "pg3" + intf3 = "pg5" + direction = "rx" + + @unittest.skipUnless(config.extended, "part of extended tests") class DisableIPFIX(MethodHolder): """Disable IPFIX"""