ip: ipfix-export API update
[vpp.git] / src / plugins / flowprobe / test / test_flowprobe.py
1 #!/usr/bin/env python
2 from __future__ import print_function
3 import binascii
4 import random
5 import socket
6 import unittest
7 import time
8 import re
9
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether
12 from scapy.layers.inet import IP, TCP, UDP
13 from scapy.layers.inet6 import IPv6
14
15 from framework import VppTestCase, VppTestRunner, running_extended_tests
16 from vpp_object import VppObject
17 from vpp_pg_interface import CaptureTimeoutError
18 from util import ppp
19 from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder
20 from vpp_ip_route import VppIpRoute, VppRoutePath
21 from vpp_papi.macaddress import mac_ntop
22 from socket import inet_ntop
23
24
25 class VppCFLOW(VppObject):
26     """CFLOW object for IPFIX exporter and Flowprobe feature"""
27
28     def __init__(self, test, intf='pg2', active=0, passive=0, timeout=100,
29                  mtu=1024, datapath='l2', layer='l2 l3 l4'):
30         self._test = test
31         self._intf = intf
32         self._active = active
33         if passive == 0 or passive < active:
34             self._passive = active+1
35         else:
36             self._passive = passive
37         self._datapath = datapath           # l2 ip4 ip6
38         self._collect = layer               # l2 l3 l4
39         self._timeout = timeout
40         self._mtu = mtu
41         self._configured = False
42
43     def add_vpp_config(self):
44         self.enable_exporter()
45         self._test.vapi.flowprobe_params(
46             record_l2=1 if 'l2' in self._collect.lower() else 0,
47             record_l3=1 if 'l3' in self._collect.lower() else 0,
48             record_l4=1 if 'l4' in self._collect.lower() else 0,
49             active_timer=self._active, passive_timer=self._passive)
50         self.enable_flowprobe_feature()
51         self._test.vapi.cli("ipfix flush")
52         self._configured = True
53
54     def remove_vpp_config(self):
55         self.disable_exporter()
56         self.disable_flowprobe_feature()
57         self._test.vapi.cli("ipfix flush")
58         self._configured = False
59
60     def enable_exporter(self):
61         self._test.vapi.set_ipfix_exporter(
62             collector_address=self._test.pg0.remote_ip4,
63             src_address=self._test.pg0.local_ip4,
64             path_mtu=self._mtu,
65             template_interval=self._timeout)
66
67     def enable_flowprobe_feature(self):
68         self._test.vapi.ppcli("flowprobe feature add-del %s %s" %
69                               (self._intf, self._datapath))
70
71     def disable_exporter(self):
72         self._test.vapi.cli("set ipfix exporter collector 0.0.0.0")
73
74     def disable_flowprobe_feature(self):
75         self._test.vapi.cli("flowprobe feature add-del %s %s disable" %
76                             (self._intf, self._datapath))
77
78     def object_id(self):
79         return "ipfix-collector-%s-%s" % (self._src, self.dst)
80
81     def query_vpp_config(self):
82         return self._configured
83
84     def verify_templates(self, decoder=None, timeout=1, count=3):
85         templates = []
86         p = self._test.wait_for_cflow_packet(self._test.collector, 2, timeout)
87         self._test.assertTrue(p.haslayer(IPFIX))
88         if decoder is not None and p.haslayer(Template):
89             templates.append(p[Template].templateID)
90             decoder.add_template(p.getlayer(Template))
91         if count > 1:
92             p = self._test.wait_for_cflow_packet(self._test.collector, 2)
93             self._test.assertTrue(p.haslayer(IPFIX))
94             if decoder is not None and p.haslayer(Template):
95                 templates.append(p[Template].templateID)
96                 decoder.add_template(p.getlayer(Template))
97         if count > 2:
98             p = self._test.wait_for_cflow_packet(self._test.collector, 2)
99             self._test.assertTrue(p.haslayer(IPFIX))
100             if decoder is not None and p.haslayer(Template):
101                 templates.append(p[Template].templateID)
102                 decoder.add_template(p.getlayer(Template))
103         return templates
104
105
106 class MethodHolder(VppTestCase):
107     """ Flow-per-packet plugin: test L2, IP4, IP6 reporting """
108
109     # Test variables
110     debug_print = False
111     max_number_of_packets = 10
112     pkts = []
113
114     @classmethod
115     def setUpClass(cls):
116         """
117         Perform standard class setup (defined by class method setUpClass in
118         class VppTestCase) before running the test case, set test case related
119         variables and configure VPP.
120         """
121         super(MethodHolder, cls).setUpClass()
122         try:
123             # Create pg interfaces
124             cls.create_pg_interfaces(range(9))
125
126             # Packet sizes
127             cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
128
129             # Create BD with MAC learning and unknown unicast flooding disabled
130             # and put interfaces to this BD
131             cls.vapi.bridge_domain_add_del(bd_id=1, uu_flood=1, learn=1)
132             cls.vapi.sw_interface_set_l2_bridge(
133                 rx_sw_if_index=cls.pg1._sw_if_index, bd_id=1)
134             cls.vapi.sw_interface_set_l2_bridge(
135                 rx_sw_if_index=cls.pg2._sw_if_index, bd_id=1)
136
137             # Set up all interfaces
138             for i in cls.pg_interfaces:
139                 i.admin_up()
140
141             cls.pg0.config_ip4()
142             cls.pg0.configure_ipv4_neighbors()
143             cls.collector = cls.pg0
144
145             cls.pg1.config_ip4()
146             cls.pg1.resolve_arp()
147             cls.pg2.config_ip4()
148             cls.pg2.resolve_arp()
149             cls.pg3.config_ip4()
150             cls.pg3.resolve_arp()
151             cls.pg4.config_ip4()
152             cls.pg4.resolve_arp()
153             cls.pg7.config_ip4()
154             cls.pg8.config_ip4()
155             cls.pg8.configure_ipv4_neighbors()
156
157             cls.pg5.config_ip6()
158             cls.pg5.resolve_ndp()
159             cls.pg5.disable_ipv6_ra()
160             cls.pg6.config_ip6()
161             cls.pg6.resolve_ndp()
162             cls.pg6.disable_ipv6_ra()
163         except Exception:
164             super(MethodHolder, cls).tearDownClass()
165             raise
166
167     @classmethod
168     def tearDownClass(cls):
169         super(MethodHolder, cls).tearDownClass()
170
171     def create_stream(self, src_if=None, dst_if=None, packets=None,
172                       size=None, ip_ver='v4'):
173         """Create a packet stream to tickle the plugin
174
175         :param VppInterface src_if: Source interface for packet stream
176         :param VppInterface src_if: Dst interface for packet stream
177         """
178         if src_if is None:
179             src_if = self.pg1
180         if dst_if is None:
181             dst_if = self.pg2
182         self.pkts = []
183         if packets is None:
184             packets = random.randint(1, self.max_number_of_packets)
185         pkt_size = size
186         for p in range(0, packets):
187             if size is None:
188                 pkt_size = random.choice(self.pg_if_packet_sizes)
189             info = self.create_packet_info(src_if, dst_if)
190             payload = self.info_to_payload(info)
191             p = Ether(src=src_if.remote_mac, dst=src_if.local_mac)
192             if ip_ver == 'v4':
193                 p /= IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4)
194             else:
195                 p /= IPv6(src=src_if.remote_ip6, dst=dst_if.remote_ip6)
196             p /= UDP(sport=1234, dport=4321)
197             p /= Raw(payload)
198             info.data = p.copy()
199             self.extend_packet(p, pkt_size)
200             self.pkts.append(p)
201
202     def verify_cflow_data(self, decoder, capture, cflow):
203         octets = 0
204         packets = 0
205         for p in capture:
206             octets += p[IP].len
207             packets += 1
208         if cflow.haslayer(Data):
209             data = decoder.decode_data_set(cflow.getlayer(Set))
210             for record in data:
211                 self.assertEqual(int(binascii.hexlify(record[1]), 16), octets)
212                 self.assertEqual(int(binascii.hexlify(record[2]), 16), packets)
213
214     def send_packets(self, src_if=None, dst_if=None):
215         if src_if is None:
216             src_if = self.pg1
217         if dst_if is None:
218             dst_if = self.pg2
219         self.pg_enable_capture([dst_if])
220         src_if.add_stream(self.pkts)
221         self.pg_start()
222         return dst_if.get_capture(len(self.pkts))
223
224     def verify_cflow_data_detail(self, decoder, capture, cflow,
225                                  data_set={1: 'octets', 2: 'packets'},
226                                  ip_ver='v4'):
227         if self.debug_print:
228             print(capture[0].show())
229         if cflow.haslayer(Data):
230             data = decoder.decode_data_set(cflow.getlayer(Set))
231             if self.debug_print:
232                 print(data)
233             if ip_ver == 'v4':
234                 ip_layer = capture[0][IP]
235             else:
236                 ip_layer = capture[0][IPv6]
237             if data_set is not None:
238                 for record in data:
239                     # skip flow if ingress/egress interface is 0
240                     if int(binascii.hexlify(record[10]), 16) == 0:
241                         continue
242                     if int(binascii.hexlify(record[14]), 16) == 0:
243                         continue
244
245                     for field in data_set:
246                         if field not in record.keys():
247                             continue
248                         value = data_set[field]
249                         if value == 'octets':
250                             value = ip_layer.len
251                             if ip_ver == 'v6':
252                                 value += 40        # ??? is this correct
253                         elif value == 'packets':
254                             value = 1
255                         elif value == 'src_ip':
256                             if ip_ver == 'v4':
257                                 ip = socket.inet_pton(socket.AF_INET,
258                                                       ip_layer.src)
259                             else:
260                                 ip = socket.inet_pton(socket.AF_INET6,
261                                                       ip_layer.src)
262                             value = int(binascii.hexlify(ip), 16)
263                         elif value == 'dst_ip':
264                             if ip_ver == 'v4':
265                                 ip = socket.inet_pton(socket.AF_INET,
266                                                       ip_layer.dst)
267                             else:
268                                 ip = socket.inet_pton(socket.AF_INET6,
269                                                       ip_layer.dst)
270                             value = int(binascii.hexlify(ip), 16)
271                         elif value == 'sport':
272                             value = int(capture[0][UDP].sport)
273                         elif value == 'dport':
274                             value = int(capture[0][UDP].dport)
275                         self.assertEqual(int(binascii.hexlify(
276                             record[field]), 16),
277                                          value)
278
279     def verify_cflow_data_notimer(self, decoder, capture, cflows):
280         idx = 0
281         for cflow in cflows:
282             if cflow.haslayer(Data):
283                 data = decoder.decode_data_set(cflow.getlayer(Set))
284             else:
285                 raise Exception("No CFLOW data")
286
287             for rec in data:
288                 p = capture[idx]
289                 idx += 1
290                 self.assertEqual(p[IP].len, int(
291                     binascii.hexlify(rec[1]), 16))
292                 self.assertEqual(1, int(
293                     binascii.hexlify(rec[2]), 16))
294         self.assertEqual(len(capture), idx)
295
296     def wait_for_cflow_packet(self, collector_intf, set_id=2, timeout=1,
297                               expected=True):
298         """ wait for CFLOW packet and verify its correctness
299
300         :param timeout: how long to wait
301
302         :returns: tuple (packet, time spent waiting for packet)
303         """
304         self.logger.info("IPFIX: Waiting for CFLOW packet")
305         deadline = time.time() + timeout
306         counter = 0
307         # self.logger.debug(self.vapi.ppcli("show flow table"))
308         while True:
309             counter += 1
310             # sanity check
311             self.assert_in_range(counter, 0, 100, "number of packets ignored")
312             time_left = deadline - time.time()
313             try:
314                 if time_left < 0 and expected:
315                     # self.logger.debug(self.vapi.ppcli("show flow table"))
316                     raise CaptureTimeoutError(
317                           "Packet did not arrive within timeout")
318                 p = collector_intf.wait_for_packet(timeout=time_left)
319             except CaptureTimeoutError:
320                 if expected:
321                     # self.logger.debug(self.vapi.ppcli("show flow table"))
322                     raise CaptureTimeoutError(
323                           "Packet did not arrive within timeout")
324                 else:
325                     return
326             if not expected:
327                 raise CaptureTimeoutError("Packet arrived even not expected")
328             self.assertEqual(p[Set].setID, set_id)
329             # self.logger.debug(self.vapi.ppcli("show flow table"))
330             self.logger.debug(ppp("IPFIX: Got packet:", p))
331             break
332         return p
333
334
335 class Flowprobe(MethodHolder):
336     """Template verification, timer tests"""
337
338     @classmethod
339     def setUpClass(cls):
340         super(Flowprobe, cls).setUpClass()
341
342     @classmethod
343     def tearDownClass(cls):
344         super(Flowprobe, cls).tearDownClass()
345
346     def test_0001(self):
347         """ timer less than template timeout"""
348         self.logger.info("FFP_TEST_START_0001")
349         self.pg_enable_capture(self.pg_interfaces)
350         self.pkts = []
351
352         ipfix = VppCFLOW(test=self, active=2)
353         ipfix.add_vpp_config()
354
355         ipfix_decoder = IPFIXDecoder()
356         # template packet should arrive immediately
357         templates = ipfix.verify_templates(ipfix_decoder)
358
359         self.create_stream(packets=1)
360         self.send_packets()
361         capture = self.pg2.get_capture(1)
362
363         # make sure the one packet we expect actually showed up
364         cflow = self.wait_for_cflow_packet(self.collector, templates[1], 15)
365         self.verify_cflow_data(ipfix_decoder, capture, cflow)
366
367         ipfix.remove_vpp_config()
368         self.logger.info("FFP_TEST_FINISH_0001")
369
370     def test_0002(self):
371         """ timer greater than template timeout"""
372         self.logger.info("FFP_TEST_START_0002")
373         self.pg_enable_capture(self.pg_interfaces)
374         self.pkts = []
375
376         ipfix = VppCFLOW(test=self, timeout=3, active=4)
377         ipfix.add_vpp_config()
378
379         ipfix_decoder = IPFIXDecoder()
380         # template packet should arrive immediately
381         ipfix.verify_templates()
382
383         self.create_stream(packets=2)
384         self.send_packets()
385         capture = self.pg2.get_capture(2)
386
387         # next set of template packet should arrive after 20 seconds
388         # template packet should arrive within 20 s
389         templates = ipfix.verify_templates(ipfix_decoder, timeout=5)
390
391         # make sure the one packet we expect actually showed up
392         cflow = self.wait_for_cflow_packet(self.collector, templates[1], 15)
393         self.verify_cflow_data(ipfix_decoder, capture, cflow)
394
395         ipfix.remove_vpp_config()
396         self.logger.info("FFP_TEST_FINISH_0002")
397
398     def test_cflow_packet(self):
399         """verify cflow packet fields"""
400         self.logger.info("FFP_TEST_START_0000")
401         self.pg_enable_capture(self.pg_interfaces)
402         self.pkts = []
403
404         ipfix = VppCFLOW(test=self, intf='pg8', datapath="ip4",
405                          layer='l2 l3 l4', active=2)
406         ipfix.add_vpp_config()
407
408         route_9001 = VppIpRoute(self, "9.0.0.0", 24,
409                                 [VppRoutePath(self.pg8._remote_hosts[0].ip4,
410                                               self.pg8.sw_if_index)])
411         route_9001.add_vpp_config()
412
413         ipfix_decoder = IPFIXDecoder()
414         templates = ipfix.verify_templates(ipfix_decoder, count=1)
415
416         self.pkts = [(Ether(dst=self.pg7.local_mac,
417                             src=self.pg7.remote_mac) /
418                       IP(src=self.pg7.remote_ip4, dst="9.0.0.100") /
419                       TCP(sport=1234, dport=4321, flags=80) /
420                       Raw('\xa5' * 100))]
421
422         nowUTC = int(time.time())
423         nowUNIX = nowUTC+2208988800
424         self.send_packets(src_if=self.pg7, dst_if=self.pg8)
425
426         cflow = self.wait_for_cflow_packet(self.collector, templates[0], 10)
427         self.collector.get_capture(2)
428
429         if cflow[0].haslayer(IPFIX):
430             self.assertEqual(cflow[IPFIX].version, 10)
431             self.assertEqual(cflow[IPFIX].observationDomainID, 1)
432             self.assertEqual(cflow[IPFIX].sequenceNumber, 0)
433             self.assertAlmostEqual(cflow[IPFIX].exportTime, nowUTC, delta=5)
434         if cflow.haslayer(Data):
435             record = ipfix_decoder.decode_data_set(cflow[0].getlayer(Set))[0]
436             # ingress interface
437             self.assertEqual(int(binascii.hexlify(record[10]), 16), 8)
438             # egress interface
439             self.assertEqual(int(binascii.hexlify(record[14]), 16), 9)
440             # packets
441             self.assertEqual(int(binascii.hexlify(record[2]), 16), 1)
442             # src mac
443             self.assertEqual(mac_ntop(record[56]), self.pg8.local_mac)
444             # dst mac
445             self.assertEqual(mac_ntop(record[80]), self.pg8.remote_mac)
446             flowTimestamp = int(binascii.hexlify(record[156]), 16) >> 32
447             # flow start timestamp
448             self.assertAlmostEqual(flowTimestamp, nowUNIX, delta=1)
449             flowTimestamp = int(binascii.hexlify(record[157]), 16) >> 32
450             # flow end timestamp
451             self.assertAlmostEqual(flowTimestamp, nowUNIX, delta=1)
452             # ethernet type
453             self.assertEqual(int(binascii.hexlify(record[256]), 16), 8)
454             # src ip
455             self.assertEqual(inet_ntop(socket.AF_INET, record[8]),
456                              self.pg7.remote_ip4)
457             # dst ip
458             self.assertEqual(inet_ntop(socket.AF_INET, record[12]),
459                              "9.0.0.100")
460             # protocol (TCP)
461             self.assertEqual(int(binascii.hexlify(record[4]), 16), 6)
462             # src port
463             self.assertEqual(int(binascii.hexlify(record[7]), 16), 1234)
464             # dst port
465             self.assertEqual(int(binascii.hexlify(record[11]), 16), 4321)
466             # tcp flags
467             self.assertEqual(int(binascii.hexlify(record[6]), 16), 80)
468
469         ipfix.remove_vpp_config()
470         self.logger.info("FFP_TEST_FINISH_0000")
471
472
473 class Datapath(MethodHolder):
474     """collect information on Ethernet, IP4 and IP6 datapath (no timers)"""
475
476     @classmethod
477     def setUpClass(cls):
478         super(Datapath, cls).setUpClass()
479
480     @classmethod
481     def tearDownClass(cls):
482         super(Datapath, cls).tearDownClass()
483
484     def test_templatesL2(self):
485         """ verify template on L2 datapath"""
486         self.logger.info("FFP_TEST_START_0000")
487         self.pg_enable_capture(self.pg_interfaces)
488
489         ipfix = VppCFLOW(test=self, layer='l2')
490         ipfix.add_vpp_config()
491
492         # template packet should arrive immediately
493         self.vapi.ipfix_flush()
494         ipfix.verify_templates(timeout=3, count=1)
495         self.collector.get_capture(1)
496
497         ipfix.remove_vpp_config()
498         self.logger.info("FFP_TEST_FINISH_0000")
499
500     def test_L2onL2(self):
501         """ L2 data on L2 datapath"""
502         self.logger.info("FFP_TEST_START_0001")
503         self.pg_enable_capture(self.pg_interfaces)
504         self.pkts = []
505
506         ipfix = VppCFLOW(test=self, layer='l2')
507         ipfix.add_vpp_config()
508
509         ipfix_decoder = IPFIXDecoder()
510         # template packet should arrive immediately
511         templates = ipfix.verify_templates(ipfix_decoder, count=1)
512
513         self.create_stream(packets=1)
514         capture = self.send_packets()
515
516         # make sure the one packet we expect actually showed up
517         self.vapi.ipfix_flush()
518         cflow = self.wait_for_cflow_packet(self.collector, templates[0])
519         self.verify_cflow_data_detail(ipfix_decoder, capture, cflow,
520                                       {2: 'packets', 256: 8})
521         self.collector.get_capture(2)
522
523         ipfix.remove_vpp_config()
524         self.logger.info("FFP_TEST_FINISH_0001")
525
526     def test_L3onL2(self):
527         """ L3 data on L2 datapath"""
528         self.logger.info("FFP_TEST_START_0002")
529         self.pg_enable_capture(self.pg_interfaces)
530         self.pkts = []
531
532         ipfix = VppCFLOW(test=self, layer='l3')
533         ipfix.add_vpp_config()
534
535         ipfix_decoder = IPFIXDecoder()
536         # template packet should arrive immediately
537         templates = ipfix.verify_templates(ipfix_decoder, count=2)
538
539         self.create_stream(packets=1)
540         capture = self.send_packets()
541
542         # make sure the one packet we expect actually showed up
543         self.vapi.ipfix_flush()
544         cflow = self.wait_for_cflow_packet(self.collector, templates[0])
545         self.verify_cflow_data_detail(ipfix_decoder, capture, cflow,
546                                       {2: 'packets', 4: 17,
547                                        8: 'src_ip', 12: 'dst_ip'})
548
549         self.collector.get_capture(3)
550
551         ipfix.remove_vpp_config()
552         self.logger.info("FFP_TEST_FINISH_0002")
553
554     def test_L4onL2(self):
555         """ L4 data on L2 datapath"""
556         self.logger.info("FFP_TEST_START_0003")
557         self.pg_enable_capture(self.pg_interfaces)
558         self.pkts = []
559
560         ipfix = VppCFLOW(test=self, layer='l4')
561         ipfix.add_vpp_config()
562
563         ipfix_decoder = IPFIXDecoder()
564         # template packet should arrive immediately
565         templates = ipfix.verify_templates(ipfix_decoder, count=2)
566
567         self.create_stream(packets=1)
568         capture = self.send_packets()
569
570         # make sure the one packet we expect actually showed up
571         self.vapi.ipfix_flush()
572         cflow = self.wait_for_cflow_packet(self.collector, templates[0])
573         self.verify_cflow_data_detail(ipfix_decoder, capture, cflow,
574                                       {2: 'packets', 7: 'sport', 11: 'dport'})
575
576         self.collector.get_capture(3)
577
578         ipfix.remove_vpp_config()
579         self.logger.info("FFP_TEST_FINISH_0003")
580
581     def test_templatesIp4(self):
582         """ verify templates on IP4 datapath"""
583         self.logger.info("FFP_TEST_START_0000")
584
585         self.pg_enable_capture(self.pg_interfaces)
586
587         ipfix = VppCFLOW(test=self, datapath='ip4')
588         ipfix.add_vpp_config()
589
590         # template packet should arrive immediately
591         self.vapi.ipfix_flush()
592         ipfix.verify_templates(timeout=3, count=1)
593         self.collector.get_capture(1)
594
595         ipfix.remove_vpp_config()
596
597         self.logger.info("FFP_TEST_FINISH_0000")
598
599     def test_L2onIP4(self):
600         """ L2 data on IP4 datapath"""
601         self.logger.info("FFP_TEST_START_0001")
602         self.pg_enable_capture(self.pg_interfaces)
603         self.pkts = []
604
605         ipfix = VppCFLOW(test=self, intf='pg4', layer='l2', datapath='ip4')
606         ipfix.add_vpp_config()
607
608         ipfix_decoder = IPFIXDecoder()
609         # template packet should arrive immediately
610         templates = ipfix.verify_templates(ipfix_decoder, count=1)
611
612         self.create_stream(src_if=self.pg3, dst_if=self.pg4, packets=1)
613         capture = self.send_packets(src_if=self.pg3, dst_if=self.pg4)
614
615         # make sure the one packet we expect actually showed up
616         self.vapi.ipfix_flush()
617         cflow = self.wait_for_cflow_packet(self.collector, templates[0])
618         self.verify_cflow_data_detail(ipfix_decoder, capture, cflow,
619                                       {2: 'packets', 256: 8})
620
621         # expected two templates and one cflow packet
622         self.collector.get_capture(2)
623
624         ipfix.remove_vpp_config()
625         self.logger.info("FFP_TEST_FINISH_0001")
626
627     def test_L3onIP4(self):
628         """ L3 data on IP4 datapath"""
629         self.logger.info("FFP_TEST_START_0002")
630         self.pg_enable_capture(self.pg_interfaces)
631         self.pkts = []
632
633         ipfix = VppCFLOW(test=self, intf='pg4', layer='l3', datapath='ip4')
634         ipfix.add_vpp_config()
635
636         ipfix_decoder = IPFIXDecoder()
637         # template packet should arrive immediately
638         templates = ipfix.verify_templates(ipfix_decoder, count=1)
639
640         self.create_stream(src_if=self.pg3, dst_if=self.pg4, packets=1)
641         capture = self.send_packets(src_if=self.pg3, dst_if=self.pg4)
642
643         # make sure the one packet we expect actually showed up
644         self.vapi.ipfix_flush()
645         cflow = self.wait_for_cflow_packet(self.collector, templates[0])
646         self.verify_cflow_data_detail(ipfix_decoder, capture, cflow,
647                                       {1: 'octets', 2: 'packets',
648                                        8: 'src_ip', 12: 'dst_ip'})
649
650         # expected two templates and one cflow packet
651         self.collector.get_capture(2)
652
653         ipfix.remove_vpp_config()
654         self.logger.info("FFP_TEST_FINISH_0002")
655
656     def test_L4onIP4(self):
657         """ L4 data on IP4 datapath"""
658         self.logger.info("FFP_TEST_START_0003")
659         self.pg_enable_capture(self.pg_interfaces)
660         self.pkts = []
661
662         ipfix = VppCFLOW(test=self, intf='pg4', layer='l4', datapath='ip4')
663         ipfix.add_vpp_config()
664
665         ipfix_decoder = IPFIXDecoder()
666         # template packet should arrive immediately
667         templates = ipfix.verify_templates(ipfix_decoder, count=1)
668
669         self.create_stream(src_if=self.pg3, dst_if=self.pg4, packets=1)
670         capture = self.send_packets(src_if=self.pg3, dst_if=self.pg4)
671
672         # make sure the one packet we expect actually showed up
673         self.vapi.ipfix_flush()
674         cflow = self.wait_for_cflow_packet(self.collector, templates[0])
675         self.verify_cflow_data_detail(ipfix_decoder, capture, cflow,
676                                       {2: 'packets', 7: 'sport', 11: 'dport'})
677
678         # expected two templates and one cflow packet
679         self.collector.get_capture(2)
680
681         ipfix.remove_vpp_config()
682         self.logger.info("FFP_TEST_FINISH_0003")
683
684     def test_templatesIP6(self):
685         """ verify templates on IP6 datapath"""
686         self.logger.info("FFP_TEST_START_0000")
687         self.pg_enable_capture(self.pg_interfaces)
688
689         ipfix = VppCFLOW(test=self, datapath='ip6')
690         ipfix.add_vpp_config()
691
692         # template packet should arrive immediately
693         ipfix.verify_templates(count=1)
694         self.collector.get_capture(1)
695
696         ipfix.remove_vpp_config()
697
698         self.logger.info("FFP_TEST_FINISH_0000")
699
700     def test_L2onIP6(self):
701         """ L2 data on IP6 datapath"""
702         self.logger.info("FFP_TEST_START_0001")
703         self.pg_enable_capture(self.pg_interfaces)
704         self.pkts = []
705
706         ipfix = VppCFLOW(test=self, intf='pg6', layer='l2', datapath='ip6')
707         ipfix.add_vpp_config()
708
709         ipfix_decoder = IPFIXDecoder()
710         # template packet should arrive immediately
711         templates = ipfix.verify_templates(ipfix_decoder, count=1)
712
713         self.create_stream(src_if=self.pg5, dst_if=self.pg6, packets=1,
714                            ip_ver='IPv6')
715         capture = self.send_packets(src_if=self.pg5, dst_if=self.pg6)
716
717         # make sure the one packet we expect actually showed up
718         self.vapi.ipfix_flush()
719         cflow = self.wait_for_cflow_packet(self.collector, templates[0])
720         self.verify_cflow_data_detail(ipfix_decoder, capture, cflow,
721                                       {2: 'packets', 256: 56710},
722                                       ip_ver='v6')
723
724         # expected two templates and one cflow packet
725         self.collector.get_capture(2)
726
727         ipfix.remove_vpp_config()
728         self.logger.info("FFP_TEST_FINISH_0001")
729
730     def test_L3onIP6(self):
731         """ L3 data on IP6 datapath"""
732         self.logger.info("FFP_TEST_START_0002")
733         self.pg_enable_capture(self.pg_interfaces)
734         self.pkts = []
735
736         ipfix = VppCFLOW(test=self, intf='pg6', layer='l3', datapath='ip6')
737         ipfix.add_vpp_config()
738
739         ipfix_decoder = IPFIXDecoder()
740         # template packet should arrive immediately
741         templates = ipfix.verify_templates(ipfix_decoder, count=1)
742
743         self.create_stream(src_if=self.pg5, dst_if=self.pg6, packets=1,
744                            ip_ver='IPv6')
745         capture = self.send_packets(src_if=self.pg5, dst_if=self.pg6)
746
747         # make sure the one packet we expect actually showed up
748         self.vapi.ipfix_flush()
749         cflow = self.wait_for_cflow_packet(self.collector, templates[0])
750         self.verify_cflow_data_detail(ipfix_decoder, capture, cflow,
751                                       {2: 'packets',
752                                        27: 'src_ip', 28: 'dst_ip'},
753                                       ip_ver='v6')
754
755         # expected two templates and one cflow packet
756         self.collector.get_capture(2)
757
758         ipfix.remove_vpp_config()
759         self.logger.info("FFP_TEST_FINISH_0002")
760
761     def test_L4onIP6(self):
762         """ L4 data on IP6 datapath"""
763         self.logger.info("FFP_TEST_START_0003")
764         self.pg_enable_capture(self.pg_interfaces)
765         self.pkts = []
766
767         ipfix = VppCFLOW(test=self, intf='pg6', layer='l4', datapath='ip6')
768         ipfix.add_vpp_config()
769
770         ipfix_decoder = IPFIXDecoder()
771         # template packet should arrive immediately
772         templates = ipfix.verify_templates(ipfix_decoder, count=1)
773
774         self.create_stream(src_if=self.pg5, dst_if=self.pg6, packets=1,
775                            ip_ver='IPv6')
776         capture = self.send_packets(src_if=self.pg5, dst_if=self.pg6)
777
778         # make sure the one packet we expect actually showed up
779         self.vapi.ipfix_flush()
780         cflow = self.wait_for_cflow_packet(self.collector, templates[0])
781         self.verify_cflow_data_detail(ipfix_decoder, capture, cflow,
782                                       {2: 'packets', 7: 'sport', 11: 'dport'},
783                                       ip_ver='v6')
784
785         # expected two templates and one cflow packet
786         self.collector.get_capture(2)
787
788         ipfix.remove_vpp_config()
789         self.logger.info("FFP_TEST_FINISH_0003")
790
791     def test_0001(self):
792         """ no timers, one CFLOW packet, 9 Flows inside"""
793         self.logger.info("FFP_TEST_START_0001")
794         self.pg_enable_capture(self.pg_interfaces)
795         self.pkts = []
796
797         ipfix = VppCFLOW(test=self)
798         ipfix.add_vpp_config()
799
800         ipfix_decoder = IPFIXDecoder()
801         # template packet should arrive immediately
802         templates = ipfix.verify_templates(ipfix_decoder)
803
804         self.create_stream(packets=9)
805         capture = self.send_packets()
806
807         # make sure the one packet we expect actually showed up
808         self.vapi.ipfix_flush()
809         cflow = self.wait_for_cflow_packet(self.collector, templates[1])
810         self.verify_cflow_data_notimer(ipfix_decoder, capture, [cflow])
811         self.collector.get_capture(4)
812
813         ipfix.remove_vpp_config()
814         self.logger.info("FFP_TEST_FINISH_0001")
815
816     def test_0002(self):
817         """ no timers, two CFLOW packets (mtu=256), 3 Flows in each"""
818         self.logger.info("FFP_TEST_START_0002")
819         self.pg_enable_capture(self.pg_interfaces)
820         self.pkts = []
821
822         ipfix = VppCFLOW(test=self, mtu=256)
823         ipfix.add_vpp_config()
824
825         ipfix_decoder = IPFIXDecoder()
826         # template packet should arrive immediately
827         self.vapi.ipfix_flush()
828         templates = ipfix.verify_templates(ipfix_decoder)
829
830         self.create_stream(packets=6)
831         capture = self.send_packets()
832
833         # make sure the one packet we expect actually showed up
834         cflows = []
835         self.vapi.ipfix_flush()
836         cflows.append(self.wait_for_cflow_packet(self.collector,
837                                                  templates[1]))
838         cflows.append(self.wait_for_cflow_packet(self.collector,
839                                                  templates[1]))
840         self.verify_cflow_data_notimer(ipfix_decoder, capture, cflows)
841         self.collector.get_capture(5)
842
843         ipfix.remove_vpp_config()
844         self.logger.info("FFP_TEST_FINISH_0002")
845
846
847 @unittest.skipUnless(running_extended_tests, "part of extended tests")
848 class DisableIPFIX(MethodHolder):
849     """Disable IPFIX"""
850
851     @classmethod
852     def setUpClass(cls):
853         super(DisableIPFIX, cls).setUpClass()
854
855     @classmethod
856     def tearDownClass(cls):
857         super(DisableIPFIX, cls).tearDownClass()
858
859     def test_0001(self):
860         """ disable IPFIX after first packets"""
861         self.logger.info("FFP_TEST_START_0001")
862         self.pg_enable_capture(self.pg_interfaces)
863         self.pkts = []
864
865         ipfix = VppCFLOW(test=self)
866         ipfix.add_vpp_config()
867
868         ipfix_decoder = IPFIXDecoder()
869         # template packet should arrive immediately
870         templates = ipfix.verify_templates(ipfix_decoder)
871
872         self.create_stream()
873         self.send_packets()
874
875         # make sure the one packet we expect actually showed up
876         self.vapi.ipfix_flush()
877         self.wait_for_cflow_packet(self.collector, templates[1])
878         self.collector.get_capture(4)
879
880         # disable IPFIX
881         ipfix.disable_exporter()
882         self.pg_enable_capture([self.collector])
883
884         self.send_packets()
885
886         # make sure no one packet arrived in 1 minute
887         self.vapi.ipfix_flush()
888         self.wait_for_cflow_packet(self.collector, templates[1],
889                                    expected=False)
890         self.collector.get_capture(0)
891
892         ipfix.remove_vpp_config()
893         self.logger.info("FFP_TEST_FINISH_0001")
894
895
896 @unittest.skipUnless(running_extended_tests, "part of extended tests")
897 class ReenableIPFIX(MethodHolder):
898     """Re-enable IPFIX"""
899
900     @classmethod
901     def setUpClass(cls):
902         super(ReenableIPFIX, cls).setUpClass()
903
904     @classmethod
905     def tearDownClass(cls):
906         super(ReenableIPFIX, cls).tearDownClass()
907
908     def test_0011(self):
909         """ disable IPFIX after first packets and re-enable after few packets
910         """
911         self.logger.info("FFP_TEST_START_0001")
912         self.pg_enable_capture(self.pg_interfaces)
913         self.pkts = []
914
915         ipfix = VppCFLOW(test=self)
916         ipfix.add_vpp_config()
917
918         ipfix_decoder = IPFIXDecoder()
919         # template packet should arrive immediately
920         templates = ipfix.verify_templates(ipfix_decoder)
921
922         self.create_stream(packets=5)
923         self.send_packets()
924
925         # make sure the one packet we expect actually showed up
926         self.vapi.ipfix_flush()
927         self.wait_for_cflow_packet(self.collector, templates[1])
928         self.collector.get_capture(4)
929
930         # disable IPFIX
931         ipfix.disable_exporter()
932         self.vapi.ipfix_flush()
933         self.pg_enable_capture([self.collector])
934
935         self.send_packets()
936
937         # make sure no one packet arrived in active timer span
938         self.vapi.ipfix_flush()
939         self.wait_for_cflow_packet(self.collector, templates[1],
940                                    expected=False)
941         self.collector.get_capture(0)
942         self.pg2.get_capture(5)
943
944         # enable IPFIX
945         ipfix.enable_exporter()
946
947         capture = self.collector.get_capture(4)
948         nr_templates = 0
949         nr_data = 0
950         for p in capture:
951             self.assertTrue(p.haslayer(IPFIX))
952             if p.haslayer(Template):
953                 nr_templates += 1
954         self.assertTrue(nr_templates, 3)
955         for p in capture:
956             self.assertTrue(p.haslayer(IPFIX))
957             if p.haslayer(Data):
958                 nr_data += 1
959         self.assertTrue(nr_templates, 1)
960
961         ipfix.remove_vpp_config()
962         self.logger.info("FFP_TEST_FINISH_0001")
963
964
965 @unittest.skipUnless(running_extended_tests, "part of extended tests")
966 class DisableFP(MethodHolder):
967     """Disable Flowprobe feature"""
968
969     @classmethod
970     def setUpClass(cls):
971         super(DisableFP, cls).setUpClass()
972
973     @classmethod
974     def tearDownClass(cls):
975         super(DisableFP, cls).tearDownClass()
976
977     def test_0001(self):
978         """ disable flowprobe feature after first packets"""
979         self.logger.info("FFP_TEST_START_0001")
980         self.pg_enable_capture(self.pg_interfaces)
981         self.pkts = []
982         ipfix = VppCFLOW(test=self)
983         ipfix.add_vpp_config()
984
985         ipfix_decoder = IPFIXDecoder()
986         # template packet should arrive immediately
987         templates = ipfix.verify_templates(ipfix_decoder)
988
989         self.create_stream()
990         self.send_packets()
991
992         # make sure the one packet we expect actually showed up
993         self.vapi.ipfix_flush()
994         self.wait_for_cflow_packet(self.collector, templates[1])
995         self.collector.get_capture(4)
996
997         # disable IPFIX
998         ipfix.disable_flowprobe_feature()
999         self.pg_enable_capture([self.collector])
1000
1001         self.send_packets()
1002
1003         # make sure no one packet arrived in active timer span
1004         self.vapi.ipfix_flush()
1005         self.wait_for_cflow_packet(self.collector, templates[1],
1006                                    expected=False)
1007         self.collector.get_capture(0)
1008
1009         ipfix.remove_vpp_config()
1010         self.logger.info("FFP_TEST_FINISH_0001")
1011
1012
1013 @unittest.skipUnless(running_extended_tests, "part of extended tests")
1014 class ReenableFP(MethodHolder):
1015     """Re-enable Flowprobe feature"""
1016
1017     @classmethod
1018     def setUpClass(cls):
1019         super(ReenableFP, cls).setUpClass()
1020
1021     @classmethod
1022     def tearDownClass(cls):
1023         super(ReenableFP, cls).tearDownClass()
1024
1025     def test_0001(self):
1026         """ disable flowprobe feature after first packets and re-enable
1027         after few packets """
1028         self.logger.info("FFP_TEST_START_0001")
1029         self.pg_enable_capture(self.pg_interfaces)
1030         self.pkts = []
1031
1032         ipfix = VppCFLOW(test=self)
1033         ipfix.add_vpp_config()
1034
1035         ipfix_decoder = IPFIXDecoder()
1036         # template packet should arrive immediately
1037         self.vapi.ipfix_flush()
1038         templates = ipfix.verify_templates(ipfix_decoder, timeout=3)
1039
1040         self.create_stream()
1041         self.send_packets()
1042
1043         # make sure the one packet we expect actually showed up
1044         self.vapi.ipfix_flush()
1045         self.wait_for_cflow_packet(self.collector, templates[1], 5)
1046         self.collector.get_capture(4)
1047
1048         # disable FPP feature
1049         ipfix.disable_flowprobe_feature()
1050         self.pg_enable_capture([self.collector])
1051
1052         self.send_packets()
1053
1054         # make sure no one packet arrived in active timer span
1055         self.vapi.ipfix_flush()
1056         self.wait_for_cflow_packet(self.collector, templates[1], 5,
1057                                    expected=False)
1058         self.collector.get_capture(0)
1059
1060         # enable FPP feature
1061         ipfix.enable_flowprobe_feature()
1062         self.vapi.ipfix_flush()
1063         templates = ipfix.verify_templates(ipfix_decoder, timeout=3)
1064
1065         self.send_packets()
1066
1067         # make sure the next packets (templates and data) we expect actually
1068         # showed up
1069         self.vapi.ipfix_flush()
1070         self.wait_for_cflow_packet(self.collector, templates[1], 5)
1071         self.collector.get_capture(4)
1072
1073         ipfix.remove_vpp_config()
1074         self.logger.info("FFP_TEST_FINISH_0001")
1075
1076
1077 if __name__ == '__main__':
1078     unittest.main(testRunner=VppTestRunner)