summaryrefslogtreecommitdiffstats
path: root/test/test_vlib.py
blob: 3c6288c8eb162ed1f627c7f93050cdc637b01d6c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#!/usr/bin/env python3

import unittest

from framework import VppTestCase, VppTestRunner, running_extended_tests
from framework import running_gcov_tests
from vpp_ip_route import VppIpTable, VppIpRoute, VppRoutePath


class TestVlib(VppTestCase):
    """ Vlib Unit Test Cases """
    worker_config = "workers 1"

    @classmethod
    def setUpClass(cls):
        super(TestVlib, cls).setUpClass()

    @classmethod
    def tearDownClass(cls):
        super(TestVlib, cls).tearDownClass()

    def setUp(self):
        super(TestVlib, self).setUp()

    def tearDown(self):
        super(TestVlib, self).tearDown()

    @unittest.skipUnless(running_gcov_tests, "part of code coverage tests")
    def test_vlib_main_unittest(self):
        """ Vlib main.c Code Coverage Test """

        cmds = ["loopback create",
                "packet-generator new {\n"
                " name vlib\n"
                " limit 15\n"
                " size 128-128\n"
                " interface loop0\n"
                " node ethernet-input\n"
                " data {\n"
                "   IP6: 00:d0:2d:5e:86:85 -> 00:0d:ea:d0:00:00\n"
                "   ICMP: db00::1 -> db00::2\n"
                "   incrementing 30\n"
                "   }\n"
                "}\n",
                "elog trace dispatch",
                "event-logger stop",
                "event-logger clear",
                "event-logger resize 102400",
                "event-logger restart",
                "pcap dispatch trace on max 100 buffer-trace pg-input 15",
                "set pmc instructions-per-clock",
                "pa en",
                "show event-log 100 all",
                "event-log save",
                "event-log save foo",
                "pcap dispatch trace",
                "pcap dispatch trace status",
                "pcap dispatch trace off",
                "show vlib frame-allocation",
                ]

        for cmd in cmds:
            r = self.vapi.cli_return_response(cmd)
            if r.retval != 0:
                if hasattr(r, 'reply'):
                    self.logger.info(cmd + " FAIL reply " + r.reply)
                else:
                    self.logger.info(cmd + " FAIL retval " + str(r.retval))

    @unittest.skipUnless(running_gcov_tests, "part of code coverage tests")
    def test_vlib_node_cli_unittest(self):
        """ Vlib node_cli.c Code Coverage Test """

        cmds = ["loopback create",
                "packet-generator new {\n"
                " name vlib\n"
                " limit 15\n"
                " size 128-128\n"
                " interface loop0\n"
                " node ethernet-input\n"
                " data {\n"
                "   IP6: 00:d0:2d:5e:86:85 -> 00:0d:ea:d0:00:00\n"
                "   ICMP: db00::1 -> db00::2\n"
                "   incrementing 30\n"
                "   }\n"
                "}\n",
                "show vlib graph",
                "show vlib graph ethernet-input",
                "show vlib graphviz",
                "show vlib graphviz graphviz.dot",
                "pa en",
                "show runtime ethernet-input",
                "show runtime brief verbose max summary",
                "clear runtime",
                "show node index 1",
                "show node ethernet-input",
                "show node pg-input",
                "set node function",
                "set node function no-such-node",
                "set node function cdp-input default",
                "set node function ethernet-input default",
                "set node function ethernet-input bozo",
                "set node function ethernet-input",
                "show \t",
                ]

        for cmd in cmds:
            r = self.vapi.cli_return_response(cmd)
            if r.retval != 0:
                if hasattr(r, 'reply'):
                    self.logger.info(cmd + " FAIL reply " + r.reply)
                else:
                    self.logger.info(cmd + " FAIL retval " + str(r.retval))

    @unittest.skipUnless(running_gcov_tests, "part of code coverage tests")
    def test_vlib_buffer_c_unittest(self):
        """ Vlib buffer.c Code Coverage Test """

        cmds = ["loopback create",
                "packet-generator new {\n"
                " name vlib\n"
                " limit 15\n"
                " size 128-128\n"
                " interface loop0\n"
                " node ethernet-input\n"
                " data {\n"
                "   IP6: 00:d0:2d:5e:86:85 -> 00:0d:ea:d0:00:00\n"
                "   ICMP: db00::1 -> db00::2\n"
                "   incrementing 30\n"
                "   }\n"
                "}\n",
                "elog trace",
                "elog trace enable",
                "elog trace api cli barrier",
                "pa en",
                "show interface bogus",
                "elog trace disable api cli barrier",
                "elog trace circuit-node ethernet-input",
                "elog trace circuit-node ethernet-input disable",
                "clear interfaces",
                "test vlib",
                "test vlib2",
                "show memory api-segment stats-segment main-heap verbose",
                "leak-check { show memory }",
                "show cpu",
                "memory-trace main-heap",
                "memory-trace main-heap api-segment stats-segment",
                "leak-check { show version }",
                "show version ?",
                "comment { show version }",
                "uncomment { show version }",
                "show memory main-heap",
                "show memory bogus",
                "choices",
                "test heap-validate",
                "memory-trace main-heap disable",
                "show buffers",
                "show eve",
                "show help",
                "show ip ",
                ]

        for cmd in cmds:
            r = self.vapi.cli_return_response(cmd)
            if r.retval != 0:
                if hasattr(r, 'reply'):
                    self.logger.info(cmd + " FAIL reply " + r.reply)
                else:
                    self.logger.info(cmd + " FAIL retval " + str(r.retval))

    @unittest.skipUnless(running_gcov_tests, "part of code coverage tests")
    def test_vlib_format_unittest(self):
        """ Vlib format.c Code Coverage Test """

        cmds = ["loopback create",
                "classify filter pcap mask l2 proto match l2 proto 0x86dd",
                "classify filter pcap del",
                "test format-vlib",
                ]

        for cmd in cmds:
            r = self.vapi.cli_return_response(cmd)
            if r.retval != 0:
                if hasattr(r, 'reply'):
                    self.logger.info(cmd + " FAIL reply " + r.reply)
                else:
                    self.logger.info(cmd + " FAIL retval " + str(r.retval))

if __name__ == '__main__':
    unittest.main(testRunner=VppTestRunner)
lass="n">vpp_dead: for bd_id in self.n_brs: self.logger.info(self.vapi.ppcli("show bridge-domain %s detail" % bd_id)) def show_commands_at_teardown(self): self.logger.info(self.vapi.ppcli("show l2fib verbose")) def create_hosts(self, n_hosts_per_if, subnet): """ Create required number of host MAC addresses and distribute them among interfaces. Create host IPv4 address for every host MAC address. :param int n_hosts_per_if: Number of per interface hosts to create MAC/IPv4 addresses for. """ hosts = dict() for pg_if in self.pg_interfaces: swif = pg_if.sw_if_index def mac(j): return "00:00:%02x:ff:%02x:%02x" % (subnet, swif, j) def ip(j): return "172.%02u.1%02x.%u" % (subnet, swif, j) def h(j): return Host(mac(j), ip(j)) hosts[swif] = [h(j) for j in range(n_hosts_per_if)] return hosts def split_hosts(self, hosts, n): splits = dict() for pg_if in self.pg_interfaces: swif = pg_if.sw_if_index splits[swif] = hosts[swif][:n] hosts[swif] = hosts[swif][n:] return splits def learn_hosts(self, bd_id, hosts): """ Create and send per interface L2 MAC broadcast packet stream to let the bridge domain learn these MAC addresses. :param int bd_id: BD to teach :param dict hosts: dict of hosts per interface """ self.vapi.bridge_flags(bd_id=bd_id, is_set=1, flags=1) ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)] for pg_if in ifs: swif = pg_if.sw_if_index packets = [Ether(dst="ff:ff:ff:ff:ff:ff", src=host.mac) for host in hosts[swif]] pg_if.add_stream(packets) self.logger.info("Sending broadcast eth frames for MAC learning") self.pg_start() def config_l2_fib_entries(self, bd_id, hosts): """ Config required number of L2 FIB entries. :param int bd_id: BD's id :param int count: Number of L2 FIB entries to be created. :param int start: Starting index of the host list. (Default value = 0) """ ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)] for pg_if in ifs: swif = pg_if.sw_if_index for host in hosts[swif]: self.vapi.l2fib_add_del( mac_pton(host.mac), bd_id, swif, static_mac=1) def delete_l2_fib_entry(self, bd_id, hosts): """ Delete required number of L2 FIB entries. :param int count: Number of L2 FIB entries to be created. """ ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)] for pg_if in ifs: swif = pg_if.sw_if_index for host in hosts[swif]: self.vapi.l2fib_add_del( mac_pton(host.mac), bd_id, swif, is_add=0) def flush_int(self, swif, learned_hosts): """ Flush swif L2 FIB entries. :param int swif: sw if index. """ flushed = dict() self.vapi.l2fib_flush_int(swif) flushed[swif] = learned_hosts[swif] learned_hosts[swif] = [] return flushed def flush_bd(self, bd_id, learned_hosts): """ Flush bd_id L2 FIB entries. :param int bd_id: Bridge Domain id. """ self.vapi.l2fib_flush_bd(bd_id) flushed = dict() ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)] for pg_if in ifs: swif = pg_if.sw_if_index flushed[swif] = learned_hosts[swif] learned_hosts[swif] = [] return flushed def flush_all(self): """ Flush All L2 FIB entries. """ self.vapi.l2fib_flush_all() def create_stream(self, src_if, packet_sizes, if_src_hosts, if_dst_hosts): """ Create input packet stream for defined interface using hosts or deleted_hosts list. :param object src_if: Interface to create packet stream for. :param list packet_sizes: List of required packet sizes. :param boolean deleted: Set to True if deleted_hosts list required. :return: Stream of packets. """ src_hosts = if_src_hosts[src_if.sw_if_index] if not src_hosts: return [] pkts = [] for dst_if in self.flows[src_if]: dst_swif = dst_if.sw_if_index if dst_swif not in if_dst_hosts: continue dst_hosts = if_dst_hosts[dst_swif] for dst_host in dst_hosts: src_host = random.choice(src_hosts) pkt_info = self.create_packet_info(src_if, dst_if) payload = self.info_to_payload(pkt_info) p = (Ether(dst=dst_host.mac, src=src_host.mac) / IP(src=src_host.ip4, dst=dst_host.ip4) / UDP(sport=1234, dport=1234) / Raw(payload)) pkt_info.data = p.copy() size = random.choice(packet_sizes) self.extend_packet(p, size) pkts.append(p) return pkts def verify_capture(self, pg_if, capture): """ Verify captured input packet stream for defined interface. :param object pg_if: Interface to verify captured packet stream for. :param list capture: Captured packet stream. """ last_info = dict() for i in self.pg_interfaces: last_info[i.sw_if_index] = None dst_sw_if_index = pg_if.sw_if_index for packet in capture: payload_info = self.payload_to_info(packet[Raw]) try: ip = packet[IP] udp = packet[UDP] packet_index = payload_info.index self.assertEqual(payload_info.dst, dst_sw_if_index) self.logger.debug("Got packet on port %s: src=%u (id=%u)" % (pg_if.name, payload_info.src, packet_index)) next_info = self.get_next_packet_info_for_interface2( payload_info.src, dst_sw_if_index, last_info[payload_info.src]) last_info[payload_info.src] = next_info self.assertTrue(next_info is not None) self.assertEqual(packet_index, next_info.index) saved_packet = next_info.data # Check standard fields self.assertEqual(ip.src, saved_packet[IP].src) self.assertEqual(ip.dst, saved_packet[IP].dst) self.assertEqual(udp.sport, saved_packet[UDP].sport) self.assertEqual(udp.dport, saved_packet[UDP].dport) except BaseException: self.logger.error(ppp("Unexpected or invalid packet:", packet)) raise for i in self.pg_interfaces: remaining_packet = self.get_next_packet_info_for_interface2( i, dst_sw_if_index, last_info[i.sw_if_index]) self.assertTrue( remaining_packet is None, "Port %u: Packet expected from source %u didn't arrive" % (dst_sw_if_index, i.sw_if_index)) def run_verify_test(self, bd_id, src_hosts, dst_hosts): # Test # Create incoming packet streams for packet-generator interfaces self.reset_packet_infos() ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)] for i in ifs: pkts = self.create_stream( i, self.pg_if_packet_sizes, if_src_hosts=src_hosts, if_dst_hosts=dst_hosts) if pkts: i.add_stream(pkts) self.vapi.bridge_flags(bd_id=bd_id, is_set=0, flags=1) # Enable packet capture and start packet sending self.pg_enable_capture(ifs) self.pg_start() # Verify # Verify outgoing packet streams per packet-generator interface for i in ifs: if not dst_hosts[i.sw_if_index]: continue capture = i.get_capture() self.logger.info("Verifying capture on interface %s" % i.name) self.verify_capture(i, capture) def run_verify_negat_test(self, bd_id, src_hosts, dst_hosts): # Test # Create incoming packet streams for packet-generator interfaces for # deleted MAC addresses self.reset_packet_infos() ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)] for i in ifs: pkts = self.create_stream( i, self.pg_if_packet_sizes, if_src_hosts=src_hosts, if_dst_hosts=dst_hosts) if pkts: i.add_stream(pkts) self.vapi.bridge_flags(bd_id=bd_id, is_set=0, flags=1) # Enable packet capture and start packet sending self.pg_enable_capture(ifs) self.pg_start() # Verify # Verify outgoing packet streams per packet-generator interface timeout = 1 for i in ifs: i.get_capture(0, timeout=timeout) i.assert_nothing_captured(remark="outgoing interface") timeout = 0.1 def test_l2_fib_program100(self): """ L2 FIB - program 100 MACs """ bd_id = 1 hosts = self.create_hosts(100, subnet=17) self.config_l2_fib_entries(bd_id, hosts) self.run_verify_test(bd_id, hosts, hosts) def test_l2_fib_program100_delete12(self): """ L2 FIB - program 100, delete 12 MACs """ bd_id = 1 hosts = self.create_hosts(100, subnet=17) self.config_l2_fib_entries(bd_id, hosts) del_hosts = self.split_hosts(hosts, 12) self.delete_l2_fib_entry(bd_id, del_hosts) self.run_verify_test(bd_id, hosts, hosts) self.run_verify_negat_test(bd_id, hosts, del_hosts) def test_l2_fib_program100_add100(self): """ L2 FIB - program 100, add 100 MACs """ bd_id = 1 hosts = self.create_hosts(100, subnet=17) self.config_l2_fib_entries(bd_id, hosts) hosts2 = self.create_hosts(100, subnet=22) self.config_l2_fib_entries(bd_id, hosts2) self.run_verify_test(bd_id, hosts, hosts2) def test_l2_fib_program10_learn10(self): """ L2 FIB - program 10 MACs, learn 10 """ hosts = self.create_hosts(20, subnet=35) lhosts = self.split_hosts(hosts, 10) bd1 = 1 bd2 = 2 self.learn_hosts(bd1, lhosts) self.learn_hosts(bd2, lhosts) self.config_l2_fib_entries(bd1, hosts) self.config_l2_fib_entries(bd2, hosts) self.run_verify_test(bd1, lhosts, hosts) self.run_verify_test(bd2, lhosts, hosts) def test_l2_fib_flush_int(self): """ L2 FIB - flush interface """ hosts = self.create_hosts(20, subnet=36) lhosts = self.split_hosts(hosts, 10) bd1 = 1 self.learn_hosts(bd1, lhosts) self.config_l2_fib_entries(bd1, hosts) self.run_verify_test(bd1, lhosts, hosts) flushed = self.flush_int(self.pg_interfaces[0].sw_if_index, lhosts) self.run_verify_test(bd1, hosts, lhosts) self.run_verify_negat_test(bd1, hosts, flushed) def test_l2_fib_flush_bd(self): """ L2 FIB - flush BD """ hosts = self.create_hosts(20, subnet=37) lhosts = self.split_hosts(hosts, 10) bd1 = 1 self.learn_hosts(bd1, lhosts) self.config_l2_fib_entries(bd1, hosts) self.run_verify_test(bd1, lhosts, hosts) flushed = self.flush_bd(bd1, lhosts) self.run_verify_negat_test(bd1, hosts, flushed) def test_l2_fib_flush_all(self): """ L2 FIB - flush all """ hosts = self.create_hosts(20, subnet=38) lhosts = self.split_hosts(hosts, 10) bd1 = 1 bd2 = 2 self.learn_hosts(bd1, lhosts) self.learn_hosts(bd2, lhosts) self.config_l2_fib_entries(bd1, hosts) self.config_l2_fib_entries(bd2, hosts) self.run_verify_test(bd1, hosts, lhosts) self.run_verify_test(bd2, hosts, lhosts) self.flush_all() self.run_verify_negat_test(bd1, hosts, lhosts) self.run_verify_negat_test(bd2, hosts, lhosts) def test_l2_fib_mac_learn_evs(self): """ L2 FIB - mac learning events """ bd1 = 1 hosts = self.create_hosts(10, subnet=39) self.vapi.want_l2_macs_events() self.learn_hosts(bd1, hosts) self.sleep(1) self.logger.info(self.vapi.ppcli("show l2fib")) evs = self.vapi.collect_events() action = VppEnum.vl_api_mac_event_action_t.MAC_EVENT_ACTION_API_ADD learned_macs = { e.mac[i].mac_addr.packed for e in evs for i in range(e.n_macs) if e.mac[i].action == action} macs = {h.bin_mac for swif in self.bd_ifs(bd1) for h in hosts[self.pg_interfaces[swif].sw_if_index]} self.vapi.want_l2_macs_events(enable_disable=0) self.assertEqual(len(learned_macs ^ macs), 0) def test_l2_fib_macs_learn_max(self): """ L2 FIB - mac learning max macs in event """ bd1 = 1 hosts = self.create_hosts(10, subnet=40) ev_macs = 1 self.vapi.want_l2_macs_events(max_macs_in_event=ev_macs) self.learn_hosts(bd1, hosts) self.sleep(1) self.logger.info(self.vapi.ppcli("show l2fib")) evs = self.vapi.collect_events() self.vapi.want_l2_macs_events(enable_disable=0) self.assertGreater(len(evs), 0) action = VppEnum.vl_api_mac_event_action_t.MAC_EVENT_ACTION_API_ADD learned_macs = { e.mac[i].mac_addr.packed for e in evs for i in range(e.n_macs) if e.mac[i].action == action} macs = {h.bin_mac for swif in self.bd_ifs(bd1) for h in hosts[self.pg_interfaces[swif].sw_if_index]} for e in evs: self.assertLess(len(e), ev_macs * 10) self.assertEqual(len(learned_macs ^ macs), 0) if __name__ == '__main__': unittest.main(testRunner=VppTestRunner)