예제 #1
0
    def thru_host_stack_setup(self):
        self.vapi.session_enable_disable(is_enabled=1)
        self.create_loopback_interfaces(2)

        table_id = 1

        for i in self.lo_interfaces:
            i.admin_up()

            if table_id != 0:
                tbl = VppIpTable(self, table_id)
                tbl.add_vpp_config()

            i.set_table_ip4(table_id)
            i.config_ip4()
            table_id += 1

        # Configure namespaces
        self.vapi.app_namespace_add_del(namespace_id=b"1", secret=1234,
                                        sw_if_index=self.loop0.sw_if_index)
        self.vapi.app_namespace_add_del(namespace_id=b"2", secret=5678,
                                        sw_if_index=self.loop1.sw_if_index)

        # Add inter-table routes
        ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32,
                            [VppRoutePath("0.0.0.0",
                                          0xffffffff,
                                          nh_table_id=2)], table_id=1)
        ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32,
                            [VppRoutePath("0.0.0.0",
                                          0xffffffff,
                                          nh_table_id=1)], table_id=2)
        ip_t01.add_vpp_config()
        ip_t10.add_vpp_config()
        self.logger.debug(self.vapi.cli("show ip fib"))
예제 #2
0
파일: test_ipip.py 프로젝트: chrisy/vpp
    def test_ipip_vrf_create(self):
        """ ipip create / delete interface VRF test """

        t = VppIpTable(self, 20)
        t.add_vpp_config()
        rv = self.vapi.ipip_add_tunnel(
            src_address=inet_pton(AF_INET, '1.2.3.4'),
            dst_address=inet_pton(AF_INET, '2.3.4.5'), is_ipv6=0,
            table_id=20)
        sw_if_index = rv.sw_if_index
        self.vapi.ipip_del_tunnel(sw_if_index)
예제 #3
0
파일: test_udp.py 프로젝트: vpp-dev/vpp
    def setUp(self):
        super(TestUdpEncap, self).setUp()

        # create 2 pg interfaces
        self.create_pg_interfaces(range(4))

        # setup interfaces
        # assign them different tables.
        table_id = 0
        self.tables = []

        for i in self.pg_interfaces:
            i.admin_up()

            if table_id != 0:
                tbl = VppIpTable(self, table_id)
                tbl.add_vpp_config()
                self.tables.append(tbl)
                tbl = VppIpTable(self, table_id, is_ip6=1)
                tbl.add_vpp_config()
                self.tables.append(tbl)

            i.set_table_ip4(table_id)
            i.set_table_ip6(table_id)
            i.config_ip4()
            i.resolve_arp()
            i.config_ip6()
            i.resolve_ndp()
            table_id += 1
예제 #4
0
    def thru_host_stack_ipv4_setup(self):
        super(QUICTestCase, self).setUp()

        self.create_loopback_interfaces(2)
        self.uri = "quic://%s/1234" % self.loop0.local_ip4
        common_args = ["uri", self.uri, "fifo-size", "64"]
        self.server_echo_test_args = common_args + ["appns", "server"]
        self.client_echo_test_args = common_args + ["appns", "client",
                                                    "test-bytes"]
        table_id = 1
        for i in self.lo_interfaces:
            i.admin_up()

            if table_id != 0:
                tbl = VppIpTable(self, table_id)
                tbl.add_vpp_config()

            i.set_table_ip4(table_id)
            i.config_ip4()
            table_id += 1

        # Configure namespaces
        self.vapi.app_namespace_add_del(namespace_id=b"server",
                                        sw_if_index=self.loop0.sw_if_index)
        self.vapi.app_namespace_add_del(namespace_id=b"client",
                                        sw_if_index=self.loop1.sw_if_index)

        # Add inter-table routes
        self.ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32,
                                 [VppRoutePath("0.0.0.0",
                                               0xffffffff,
                                               nh_table_id=2)], table_id=1)
        self.ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32,
                                 [VppRoutePath("0.0.0.0",
                                               0xffffffff,
                                               nh_table_id=1)], table_id=2)
        self.ip_t01.add_vpp_config()
        self.ip_t10.add_vpp_config()
        self.logger.debug(self.vapi.cli("show ip fib"))
예제 #5
0
파일: test_quic.py 프로젝트: chrisy/vpp
    def setUp(self):
        super(TestQUIC, self).setUp()
        self.vapi.session_enable_disable(is_enabled=1)
        self.create_loopback_interfaces(2)

        table_id = 1

        for i in self.lo_interfaces:
            i.admin_up()

            if table_id != 0:
                tbl = VppIpTable(self, table_id)
                tbl.add_vpp_config()

            i.set_table_ip4(table_id)
            i.config_ip4()
            table_id += 1

        # Configure namespaces
        self.vapi.app_namespace_add_del(namespace_id=b"1",
                                        sw_if_index=self.loop0.sw_if_index)
        self.vapi.app_namespace_add_del(namespace_id=b"2",
                                        sw_if_index=self.loop1.sw_if_index)
예제 #6
0
    def thru_host_stack_ipv6_setup(self):
        self.vapi.session_enable_disable(is_enabled=1)
        self.create_loopback_interfaces(2)

        table_id = 1

        for i in self.lo_interfaces:
            i.admin_up()

            tbl = VppIpTable(self, table_id, is_ip6=1)
            tbl.add_vpp_config()

            i.set_table_ip6(table_id)
            i.config_ip6()
            table_id += 1

        # Configure namespaces
        self.vapi.app_namespace_add_del(namespace_id=b"1", secret=1234,
                                        sw_if_index=self.loop0.sw_if_index)
        self.vapi.app_namespace_add_del(namespace_id=b"2", secret=5678,
                                        sw_if_index=self.loop1.sw_if_index)

        # Add inter-table routes
        ip_t01 = VppIpRoute(self, self.loop1.local_ip6, 128,
                            [VppRoutePath("::0", 0xffffffff,
                                          nh_table_id=2,
                                          proto=DpoProto.DPO_PROTO_IP6)],
                            table_id=1, is_ip6=1)
        ip_t10 = VppIpRoute(self, self.loop0.local_ip6, 128,
                            [VppRoutePath("::0", 0xffffffff,
                                          nh_table_id=1,
                                          proto=DpoProto.DPO_PROTO_IP6)],
                            table_id=2, is_ip6=1)
        ip_t01.add_vpp_config()
        ip_t10.add_vpp_config()
        self.logger.debug(self.vapi.cli("show interface addr"))
        self.logger.debug(self.vapi.cli("show ip6 fib"))
예제 #7
0
파일: test_igmp.py 프로젝트: chrisy/vpp
    def setUp(self):
        super(TestIgmp, self).setUp()

        self.create_pg_interfaces(range(4))
        self.sg_list = []
        self.config_list = []

        self.ip_addr = []
        self.ip_table = VppIpTable(self, 1)
        self.ip_table.add_vpp_config()

        for pg in self.pg_interfaces[2:]:
            pg.set_table_ip4(1)
        for pg in self.pg_interfaces:
            pg.admin_up()
            pg.config_ip4()
            pg.resolve_arp()
예제 #8
0
파일: test_gre.py 프로젝트: chrisy/vpp
    def setUp(self):
        super(TestGRE, self).setUp()

        # create 3 pg interfaces - set one in a non-default table.
        self.create_pg_interfaces(range(3))

        self.tbl = VppIpTable(self, 1)
        self.tbl.add_vpp_config()
        self.pg1.set_table_ip4(1)

        for i in self.pg_interfaces:
            i.admin_up()

        self.pg0.config_ip4()
        self.pg0.resolve_arp()
        self.pg1.config_ip4()
        self.pg1.resolve_arp()
        self.pg2.config_ip6()
        self.pg2.resolve_ndp()
예제 #9
0
파일: test_sixrd.py 프로젝트: chrisy/vpp
    def setUp(self):
        super(Test6RD, self).setUp()
        t4 = VppIpTable(self, 10)
        t6 = VppIpTable(self, 20, True)

        t4.add_vpp_config()
        t6.add_vpp_config()

        for n in range(4):
            i = self.pg_interfaces[n]
            i.admin_up()
            if (n > 1):
                i.set_table_ip4(10)
                i.set_table_ip6(20)
            i.config_ip4()
            i.config_ip6()
            i.disable_ipv6_ra()
            i.resolve_arp()
            i.resolve_ndp()
예제 #10
0
파일: test_svs.py 프로젝트: vpp-dev/vpp
    def setUp(self):
        super(TestSVS, self).setUp()

        # create 2 pg interfaces
        self.create_pg_interfaces(range(4))

        table_id = 0

        for i in self.pg_interfaces:
            i.admin_up()

            if table_id != 0:
                tbl = VppIpTable(self, table_id)
                tbl.add_vpp_config()
                tbl = VppIpTable(self, table_id, is_ip6=1)
                tbl.add_vpp_config()

            i.set_table_ip4(table_id)
            i.set_table_ip6(table_id)
            i.config_ip4()
            i.resolve_arp()
            i.config_ip6()
            i.resolve_ndp()
            table_id += 1
예제 #11
0
파일: test_ip_mcast.py 프로젝트: chrisy/vpp
    def setUp(self):
        super(TestIPMcast, self).setUp()

        # create 8 pg interfaces
        self.create_pg_interfaces(range(9))

        # setup interfaces
        for i in self.pg_interfaces[:8]:
            i.admin_up()
            i.config_ip4()
            i.config_ip6()
            i.resolve_arp()
            i.resolve_ndp()

        # one more in a vrf
        tbl4 = VppIpTable(self, 10)
        tbl4.add_vpp_config()
        self.pg8.set_table_ip4(10)
        self.pg8.config_ip4()

        tbl6 = VppIpTable(self, 10, is_ip6=1)
        tbl6.add_vpp_config()
        self.pg8.set_table_ip6(10)
        self.pg8.config_ip6()
예제 #12
0
class TestGRE(VppTestCase):
    """ GRE Test Case """

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

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

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

        # create 3 pg interfaces - set one in a non-default table.
        self.create_pg_interfaces(range(5))

        self.tbl = VppIpTable(self, 1)
        self.tbl.add_vpp_config()
        self.pg1.set_table_ip4(1)

        for i in self.pg_interfaces:
            i.admin_up()

        self.pg0.config_ip4()
        self.pg0.resolve_arp()
        self.pg1.config_ip4()
        self.pg1.resolve_arp()
        self.pg2.config_ip6()
        self.pg2.resolve_ndp()
        self.pg3.config_ip4()
        self.pg3.resolve_arp()
        self.pg4.config_ip4()
        self.pg4.resolve_arp()

    def tearDown(self):
        for i in self.pg_interfaces:
            i.unconfig_ip4()
            i.unconfig_ip6()
            i.admin_down()
        self.pg1.set_table_ip4(0)
        super(TestGRE, self).tearDown()

    def create_stream_ip4(self, src_if, src_ip, dst_ip, dscp=0, ecn=0):
        pkts = []
        tos = (dscp << 2) | ecn
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=src_ip, dst=dst_ip, tos=tos) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_stream_ip6(self, src_if, src_ip, dst_ip, dscp=0, ecn=0):
        pkts = []
        tc = (dscp << 2) | ecn
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IPv6(src=src_ip, dst=dst_ip, tc=tc) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_4o4(self, src_if,
                                 tunnel_src, tunnel_dst,
                                 src_ip, dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=tunnel_src, dst=tunnel_dst) /
                 GRE() /
                 IP(src=src_ip, dst=dst_ip) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_6o4(self, src_if,
                                 tunnel_src, tunnel_dst,
                                 src_ip, dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=tunnel_src, dst=tunnel_dst) /
                 GRE() /
                 IPv6(src=src_ip, dst=dst_ip) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_6o6(self, src_if,
                                 tunnel_src, tunnel_dst,
                                 src_ip, dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IPv6(src=tunnel_src, dst=tunnel_dst) /
                 GRE() /
                 IPv6(src=src_ip, dst=dst_ip) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_l2o4(self, src_if,
                                  tunnel_src, tunnel_dst):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=tunnel_src, dst=tunnel_dst) /
                 GRE() /
                 Ether(dst=RandMAC('*:*:*:*:*:*'),
                       src=RandMAC('*:*:*:*:*:*')) /
                 IP(src=scapy.compat.raw(RandIP()),
                    dst=scapy.compat.raw(RandIP())) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_vlano4(self, src_if,
                                    tunnel_src, tunnel_dst, vlan):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=tunnel_src, dst=tunnel_dst) /
                 GRE() /
                 Ether(dst=RandMAC('*:*:*:*:*:*'),
                       src=RandMAC('*:*:*:*:*:*')) /
                 Dot1Q(vlan=vlan) /
                 IP(src=scapy.compat.raw(RandIP()),
                    dst=scapy.compat.raw(RandIP())) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def verify_tunneled_4o4(self, src_if, capture, sent,
                            tunnel_src, tunnel_dst,
                            dscp=0, ecn=0):

        self.assertEqual(len(capture), len(sent))
        tos = (dscp << 2) | ecn

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)
                self.assertEqual(rx_ip.tos, tos)
                self.assertEqual(rx_ip.len, len(rx_ip))

                rx_gre = rx[GRE]
                rx_ip = rx_gre[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # IP processing post pop has decremented the TTL
                self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_6o6(self, src_if, capture, sent,
                            tunnel_src, tunnel_dst,
                            dscp=0, ecn=0):

        self.assertEqual(len(capture), len(sent))
        tc = (dscp << 2) | ecn

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IPv6]
                rx_ip = rx[IPv6]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)
                self.assertEqual(rx_ip.tc, tc)

                rx_gre = GRE(scapy.compat.raw(rx_ip[IPv6].payload))

                self.assertEqual(rx_ip.plen, len(rx_gre))

                rx_ip = rx_gre[IPv6]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_4o6(self, src_if, capture, sent,
                            tunnel_src, tunnel_dst):

        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                rx_ip = rx[IPv6]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = GRE(scapy.compat.raw(rx_ip[IPv6].payload))

                self.assertEqual(rx_ip.plen, len(rx_gre))

                tx_ip = tx[IP]
                rx_ip = rx_gre[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_6o4(self, src_if, capture, sent,
                            tunnel_src, tunnel_dst):

        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                rx_ip = rx[IP]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)
                self.assertEqual(rx_ip.len, len(rx_ip))

                rx_gre = GRE(scapy.compat.raw(rx_ip[IP].payload))
                rx_ip = rx_gre[IPv6]
                tx_ip = tx[IPv6]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_l2o4(self, src_if, capture, sent,
                             tunnel_src, tunnel_dst):
        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)
                self.assertEqual(rx_ip.len, len(rx_ip))

                rx_gre = rx[GRE]
                rx_l2 = rx_gre[Ether]
                rx_ip = rx_l2[IP]
                tx_gre = tx[GRE]
                tx_l2 = tx_gre[Ether]
                tx_ip = tx_l2[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # bridged, not L3 forwarded, so no TTL decrement
                self.assertEqual(rx_ip.ttl, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_vlano4(self, src_if, capture, sent,
                               tunnel_src, tunnel_dst, vlan):
        try:
            self.assertEqual(len(capture), len(sent))
        except:
            ppc("Unexpected packets captured:", capture)
            raise

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = rx[GRE]
                rx_l2 = rx_gre[Ether]
                rx_vlan = rx_l2[Dot1Q]
                rx_ip = rx_l2[IP]

                self.assertEqual(rx_vlan.vlan, vlan)

                tx_gre = tx[GRE]
                tx_l2 = tx_gre[Ether]
                tx_ip = tx_l2[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # bridged, not L3 forwarded, so no TTL decrement
                self.assertEqual(rx_ip.ttl, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_decapped_4o4(self, src_if, capture, sent):
        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]
                tx_gre = tx[GRE]
                tx_ip = tx_gre[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # IP processing post pop has decremented the TTL
                self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_decapped_6o4(self, src_if, capture, sent):
        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IPv6]
                tx_gre = tx[GRE]
                tx_ip = tx_gre[IPv6]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_decapped_6o6(self, src_if, capture, sent):
        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IPv6]
                rx_ip = rx[IPv6]
                tx_gre = tx[GRE]
                tx_ip = tx_gre[IPv6]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def test_gre(self):
        """ GRE IPv4 tunnel Tests """

        #
        # Create an L3 GRE tunnel.
        #  - set it admin up
        #  - assign an IP Addres
        #  - Add a route via the tunnel
        #
        gre_if = VppGreInterface(self,
                                 self.pg0.local_ip4,
                                 "1.1.1.2")
        gre_if.add_vpp_config()

        #
        # The double create (create the same tunnel twice) should fail,
        # and we should still be able to use the original
        #
        try:
            gre_if.add_vpp_config()
        except Exception:
            pass
        else:
            self.fail("Double GRE tunnel add does not fail")

        gre_if.admin_up()
        gre_if.config_ip4()

        route_via_tun = VppIpRoute(self, "4.4.4.4", 32,
                                   [VppRoutePath("0.0.0.0",
                                                 gre_if.sw_if_index)])

        route_via_tun.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - they are all dropped since the tunnel's destintation IP
        #    is unresolved - or resolves via the default route - which
        #    which is a drop.
        #
        tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")

        self.send_and_assert_no_replies(self.pg0, tx)

        #
        # Add a route that resolves the tunnel's destination
        #
        route_tun_dst = VppIpRoute(self, "1.1.1.2", 32,
                                   [VppRoutePath(self.pg0.remote_ip4,
                                                 self.pg0.sw_if_index)])
        route_tun_dst.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - packets are GRE encapped
        #
        tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_tunneled_4o4(self.pg0, rx, tx,
                                 self.pg0.local_ip4, "1.1.1.2")

        #
        # Send tunneled packets that match the created tunnel and
        # are decapped and forwarded
        #
        tx = self.create_tunnel_stream_4o4(self.pg0,
                                           "1.1.1.2",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_decapped_4o4(self.pg0, rx, tx)

        #
        # Send tunneled packets that do not match the tunnel's src
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_4o4(self.pg0,
                                           "1.1.1.3",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        self.send_and_assert_no_replies(
            self.pg0, tx,
            remark="GRE packets forwarded despite no SRC address match")

        #
        # Configure IPv6 on the PG interface so we can route IPv6
        # packets
        #
        self.pg0.config_ip6()
        self.pg0.resolve_ndp()

        #
        # Send IPv6 tunnel encapslated packets
        #  - dropped since IPv6 is not enabled on the tunnel
        #
        tx = self.create_tunnel_stream_6o4(self.pg0,
                                           "1.1.1.2",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip6,
                                           self.pg0.remote_ip6)
        self.send_and_assert_no_replies(self.pg0, tx,
                                        "IPv6 GRE packets forwarded "
                                        "despite IPv6 not enabled on tunnel")

        #
        # Enable IPv6 on the tunnel
        #
        gre_if.config_ip6()

        #
        # Send IPv6 tunnel encapslated packets
        #  - forwarded since IPv6 is enabled on the tunnel
        #
        tx = self.create_tunnel_stream_6o4(self.pg0,
                                           "1.1.1.2",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip6,
                                           self.pg0.remote_ip6)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_decapped_6o4(self.pg0, rx, tx)

        #
        # Send v6 packets for v4 encap
        #
        route6_via_tun = VppIpRoute(
            self, "2001::1", 128,
            [VppRoutePath("::",
                          gre_if.sw_if_index,
                          proto=DpoProto.DPO_PROTO_IP6)])
        route6_via_tun.add_vpp_config()

        tx = self.create_stream_ip6(self.pg0, "2001::2", "2001::1")
        rx = self.send_and_expect(self.pg0, tx, self.pg0)

        self.verify_tunneled_6o4(self.pg0, rx, tx,
                                 self.pg0.local_ip4, "1.1.1.2")

        #
        # test case cleanup
        #
        route_tun_dst.remove_vpp_config()
        route_via_tun.remove_vpp_config()
        route6_via_tun.remove_vpp_config()
        gre_if.remove_vpp_config()

        self.pg0.unconfig_ip6()

    def test_gre6(self):
        """ GRE IPv6 tunnel Tests """

        self.pg1.config_ip6()
        self.pg1.resolve_ndp()

        #
        # Create an L3 GRE tunnel.
        #  - set it admin up
        #  - assign an IP Address
        #  - Add a route via the tunnel
        #
        gre_if = VppGreInterface(self,
                                 self.pg2.local_ip6,
                                 "1002::1")
        gre_if.add_vpp_config()
        gre_if.admin_up()
        gre_if.config_ip6()

        route_via_tun = VppIpRoute(self, "4004::1", 128,
                                   [VppRoutePath("0::0",
                                                 gre_if.sw_if_index)])

        route_via_tun.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - they are all dropped since the tunnel's destintation IP
        #    is unresolved - or resolves via the default route - which
        #    which is a drop.
        #
        tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
        self.send_and_assert_no_replies(
            self.pg2, tx,
            "GRE packets forwarded without DIP resolved")

        #
        # Add a route that resolves the tunnel's destination
        #
        route_tun_dst = VppIpRoute(self, "1002::1", 128,
                                   [VppRoutePath(self.pg2.remote_ip6,
                                                 self.pg2.sw_if_index)])
        route_tun_dst.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - packets are GRE encapped
        #
        tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
        rx = self.send_and_expect(self.pg2, tx, self.pg2)
        self.verify_tunneled_6o6(self.pg2, rx, tx,
                                 self.pg2.local_ip6, "1002::1")

        #
        # Test decap. decapped packets go out pg1
        #
        tx = self.create_tunnel_stream_6o6(self.pg2,
                                           "1002::1",
                                           self.pg2.local_ip6,
                                           "2001::1",
                                           self.pg1.remote_ip6)
        rx = self.send_and_expect(self.pg2, tx, self.pg1)

        #
        # RX'd packet is UDP over IPv6, test the GRE header is gone.
        #
        self.assertFalse(rx[0].haslayer(GRE))
        self.assertEqual(rx[0][IPv6].dst, self.pg1.remote_ip6)

        #
        # Send v4 over v6
        #
        route4_via_tun = VppIpRoute(self, "1.1.1.1", 32,
                                    [VppRoutePath("0.0.0.0",
                                                  gre_if.sw_if_index)])
        route4_via_tun.add_vpp_config()

        tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "1.1.1.1")
        rx = self.send_and_expect(self.pg0, tx, self.pg2)

        self.verify_tunneled_4o6(self.pg0, rx, tx,
                                 self.pg2.local_ip6, "1002::1")

        #
        # test case cleanup
        #
        route_tun_dst.remove_vpp_config()
        route_via_tun.remove_vpp_config()
        route4_via_tun.remove_vpp_config()
        gre_if.remove_vpp_config()

        self.pg2.unconfig_ip6()
        self.pg1.unconfig_ip6()

    def test_gre_vrf(self):
        """ GRE tunnel VRF Tests """

        e = VppEnum.vl_api_tunnel_encap_decap_flags_t

        #
        # Create an L3 GRE tunnel whose destination is in the non-default
        # table. The underlay is thus non-default - the overlay is still
        # the default.
        #  - set it admin up
        #  - assign an IP Addres
        #
        gre_if = VppGreInterface(
            self, self.pg1.local_ip4,
            "2.2.2.2",
            outer_table_id=1,
            flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP |
                   e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))

        gre_if.add_vpp_config()
        gre_if.admin_up()
        gre_if.config_ip4()

        #
        # Add a route via the tunnel - in the overlay
        #
        route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
                                   [VppRoutePath("0.0.0.0",
                                                 gre_if.sw_if_index)])
        route_via_tun.add_vpp_config()

        #
        # Add a route that resolves the tunnel's destination - in the
        # underlay table
        #
        route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
                                   paths=[VppRoutePath(self.pg1.remote_ip4,
                                                       self.pg1.sw_if_index)])
        route_tun_dst.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        # packets are sent in on pg0 which is in the default table
        #  - packets are GRE encapped
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9",
                                    dscp=5, ecn=3)
        rx = self.send_and_expect(self.pg0, tx, self.pg1)
        self.verify_tunneled_4o4(self.pg1, rx, tx,
                                 self.pg1.local_ip4, "2.2.2.2",
                                 dscp=5, ecn=3)

        #
        # Send tunneled packets that match the created tunnel and
        # are decapped and forwarded. This tests the decap lookup
        # does not happen in the encap table
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_4o4(self.pg1,
                                           "2.2.2.2",
                                           self.pg1.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        rx = self.send_and_expect(self.pg1, tx, self.pg0)
        self.verify_decapped_4o4(self.pg0, rx, tx)

        #
        # Send tunneled packets that match the created tunnel
        # but arrive on an interface that is not in the tunnel's
        # encap VRF, these are dropped.
        # IP enable the interface so they aren't dropped due to
        # IP not being enabled.
        #
        self.pg2.config_ip4()
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_4o4(self.pg2,
                                           "2.2.2.2",
                                           self.pg1.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        rx = self.send_and_assert_no_replies(
            self.pg2, tx,
            "GRE decap packets in wrong VRF")

        self.pg2.unconfig_ip4()

        #
        # test case cleanup
        #
        route_tun_dst.remove_vpp_config()
        route_via_tun.remove_vpp_config()
        gre_if.remove_vpp_config()

    def test_gre_l2(self):
        """ GRE tunnel L2 Tests """

        #
        # Add routes to resolve the tunnel destinations
        #
        route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
                                    [VppRoutePath(self.pg0.remote_ip4,
                                                  self.pg0.sw_if_index)])
        route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
                                    [VppRoutePath(self.pg0.remote_ip4,
                                                  self.pg0.sw_if_index)])

        route_tun1_dst.add_vpp_config()
        route_tun2_dst.add_vpp_config()

        #
        # Create 2 L2 GRE tunnels and x-connect them
        #
        gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
                                  "2.2.2.2",
                                  type=(VppEnum.vl_api_gre_tunnel_type_t.
                                        GRE_API_TUNNEL_TYPE_TEB))
        gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
                                  "2.2.2.3",
                                  type=(VppEnum.vl_api_gre_tunnel_type_t.
                                        GRE_API_TUNNEL_TYPE_TEB))
        gre_if1.add_vpp_config()
        gre_if2.add_vpp_config()

        gre_if1.admin_up()
        gre_if2.admin_up()

        self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
                                               gre_if2.sw_if_index,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
                                               gre_if1.sw_if_index,
                                               enable=1)

        #
        # Send in tunnel encapped L2. expect out tunnel encapped L2
        # in both directions
        #
        tx = self.create_tunnel_stream_l2o4(self.pg0,
                                            "2.2.2.2",
                                            self.pg0.local_ip4)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_tunneled_l2o4(self.pg0, rx, tx,
                                  self.pg0.local_ip4,
                                  "2.2.2.3")

        tx = self.create_tunnel_stream_l2o4(self.pg0,
                                            "2.2.2.3",
                                            self.pg0.local_ip4)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_tunneled_l2o4(self.pg0, rx, tx,
                                  self.pg0.local_ip4,
                                  "2.2.2.2")

        self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
                                               gre_if2.sw_if_index,
                                               enable=0)
        self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
                                               gre_if1.sw_if_index,
                                               enable=0)

        #
        # Create a VLAN sub-interfaces on the GRE TEB interfaces
        # then x-connect them
        #
        gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
        gre_if_12 = VppDot1QSubint(self, gre_if2, 12)

        # gre_if_11.add_vpp_config()
        # gre_if_12.add_vpp_config()

        gre_if_11.admin_up()
        gre_if_12.admin_up()

        self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
                                               gre_if_12.sw_if_index,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
                                               gre_if_11.sw_if_index,
                                               enable=1)

        #
        # Configure both to pop thier respective VLAN tags,
        # so that during the x-coonect they will subsequently push
        #
        self.vapi.l2_interface_vlan_tag_rewrite(
            sw_if_index=gre_if_12.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
            push_dot1q=12)
        self.vapi.l2_interface_vlan_tag_rewrite(
            sw_if_index=gre_if_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
            push_dot1q=11)

        #
        # Send traffic in both directiond - expect the VLAN tags to
        # be swapped.
        #
        tx = self.create_tunnel_stream_vlano4(self.pg0,
                                              "2.2.2.2",
                                              self.pg0.local_ip4,
                                              11)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_tunneled_vlano4(self.pg0, rx, tx,
                                    self.pg0.local_ip4,
                                    "2.2.2.3",
                                    12)

        tx = self.create_tunnel_stream_vlano4(self.pg0,
                                              "2.2.2.3",
                                              self.pg0.local_ip4,
                                              12)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_tunneled_vlano4(self.pg0, rx, tx,
                                    self.pg0.local_ip4,
                                    "2.2.2.2",
                                    11)

        #
        # Cleanup Test resources
        #
        gre_if_11.remove_vpp_config()
        gre_if_12.remove_vpp_config()
        gre_if1.remove_vpp_config()
        gre_if2.remove_vpp_config()
        route_tun1_dst.add_vpp_config()
        route_tun2_dst.add_vpp_config()

    def test_gre_loop(self):
        """ GRE tunnel loop Tests """

        #
        # Create an L3 GRE tunnel.
        #  - set it admin up
        #  - assign an IP Addres
        #
        gre_if = VppGreInterface(self,
                                 self.pg0.local_ip4,
                                 "1.1.1.2")
        gre_if.add_vpp_config()
        gre_if.admin_up()
        gre_if.config_ip4()

        #
        # add a route to the tunnel's destination that points
        # through the tunnel, hence forming a loop in the forwarding
        # graph
        #
        route_dst = VppIpRoute(self, "1.1.1.2", 32,
                               [VppRoutePath("0.0.0.0",
                                             gre_if.sw_if_index)])
        route_dst.add_vpp_config()

        #
        # packets to the tunnels destination should be dropped
        #
        tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "1.1.1.2")
        self.send_and_assert_no_replies(self.pg2, tx)

        self.logger.info(self.vapi.ppcli("sh adj 7"))

        #
        # break the loop
        #
        route_dst.modify([VppRoutePath(self.pg1.remote_ip4,
                                       self.pg1.sw_if_index)])
        route_dst.add_vpp_config()

        rx = self.send_and_expect(self.pg0, tx, self.pg1)

        #
        # a good route throught the tunnel to check it restacked
        #
        route_via_tun_2 = VppIpRoute(self, "2.2.2.2", 32,
                                     [VppRoutePath("0.0.0.0",
                                                   gre_if.sw_if_index)])
        route_via_tun_2.add_vpp_config()

        tx = self.create_stream_ip4(self.pg0, "2.2.2.3", "2.2.2.2")
        rx = self.send_and_expect(self.pg0, tx, self.pg1)
        self.verify_tunneled_4o4(self.pg1, rx, tx,
                                 self.pg0.local_ip4, "1.1.1.2")

        #
        # cleanup
        #
        route_via_tun_2.remove_vpp_config()
        gre_if.remove_vpp_config()

    def test_mgre(self):
        """ mGRE IPv4 tunnel Tests """

        for itf in self.pg_interfaces[3:]:
            #
            # one underlay nh for each overlay/tunnel peer
            #
            itf.generate_remote_hosts(4)
            itf.configure_ipv4_neighbors()

            #
            # Create an L3 GRE tunnel.
            #  - set it admin up
            #  - assign an IP Addres
            #  - Add a route via the tunnel
            #
            gre_if = VppGreInterface(self,
                                     itf.local_ip4,
                                     "0.0.0.0",
                                     mode=(VppEnum.vl_api_tunnel_mode_t.
                                           TUNNEL_API_MODE_MP))
            gre_if.add_vpp_config()
            gre_if.admin_up()
            gre_if.config_ip4()
            gre_if.generate_remote_hosts(4)

            self.logger.info(self.vapi.cli("sh adj"))
            self.logger.info(self.vapi.cli("sh ip fib"))

            #
            # ensure we don't match to the tunnel if the source address
            # is all zeros
            #
            tx = self.create_tunnel_stream_4o4(self.pg0,
                                               "0.0.0.0",
                                               itf.local_ip4,
                                               self.pg0.local_ip4,
                                               self.pg0.remote_ip4)
            self.send_and_assert_no_replies(self.pg0, tx)

            #
            # for-each peer
            #
            for ii in range(1, 4):
                route_addr = "4.4.4.%d" % ii

                #
                # route traffic via the peer
                #
                route_via_tun = VppIpRoute(
                    self, route_addr, 32,
                    [VppRoutePath(gre_if._remote_hosts[ii].ip4,
                                  gre_if.sw_if_index)])
                route_via_tun.add_vpp_config()

                #
                # Add a TEIB entry resolves the peer
                #
                teib = VppTeib(self, gre_if,
                               gre_if._remote_hosts[ii].ip4,
                               itf._remote_hosts[ii].ip4)
                teib.add_vpp_config()

                #
                # Send a packet stream that is routed into the tunnel
                #  - packets are GRE encapped
                #
                tx_e = self.create_stream_ip4(self.pg0, "5.5.5.5", route_addr)
                rx = self.send_and_expect(self.pg0, tx_e, itf)
                self.verify_tunneled_4o4(self.pg0, rx, tx_e,
                                         itf.local_ip4,
                                         itf._remote_hosts[ii].ip4)

                tx_i = self.create_tunnel_stream_4o4(self.pg0,
                                                     itf._remote_hosts[ii].ip4,
                                                     itf.local_ip4,
                                                     self.pg0.local_ip4,
                                                     self.pg0.remote_ip4)
                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
                self.verify_decapped_4o4(self.pg0, rx, tx_i)

                #
                # delete and re-add the TEIB
                #
                teib.remove_vpp_config()
                self.send_and_assert_no_replies(self.pg0, tx_e)
                self.send_and_assert_no_replies(self.pg0, tx_i)

                teib.add_vpp_config()
                rx = self.send_and_expect(self.pg0, tx_e, itf)
                self.verify_tunneled_4o4(self.pg0, rx, tx_e,
                                         itf.local_ip4,
                                         itf._remote_hosts[ii].ip4)
                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
                self.verify_decapped_4o4(self.pg0, rx, tx_i)

            gre_if.admin_down()
            gre_if.unconfig_ip4()

    def test_mgre6(self):
        """ mGRE IPv6 tunnel Tests """

        self.pg0.config_ip6()
        self.pg0.resolve_ndp()

        e = VppEnum.vl_api_tunnel_encap_decap_flags_t

        for itf in self.pg_interfaces[3:]:
            #
            # one underlay nh for each overlay/tunnel peer
            #
            itf.config_ip6()
            itf.generate_remote_hosts(4)
            itf.configure_ipv6_neighbors()

            #
            # Create an L3 GRE tunnel.
            #  - set it admin up
            #  - assign an IP Addres
            #  - Add a route via the tunnel
            #
            gre_if = VppGreInterface(
                self,
                itf.local_ip6,
                "::",
                mode=(VppEnum.vl_api_tunnel_mode_t.
                      TUNNEL_API_MODE_MP),
                flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)

            gre_if.add_vpp_config()
            gre_if.admin_up()
            gre_if.config_ip6()
            gre_if.generate_remote_hosts(4)

            #
            # for-each peer
            #
            for ii in range(1, 4):
                route_addr = "4::%d" % ii

                #
                # Add a TEIB entry resolves the peer
                #
                teib = VppTeib(self, gre_if,
                               gre_if._remote_hosts[ii].ip6,
                               itf._remote_hosts[ii].ip6)
                teib.add_vpp_config()

                #
                # route traffic via the peer
                #
                route_via_tun = VppIpRoute(
                    self, route_addr, 128,
                    [VppRoutePath(gre_if._remote_hosts[ii].ip6,
                                  gre_if.sw_if_index)])
                route_via_tun.add_vpp_config()

                #
                # Send a packet stream that is routed into the tunnel
                #  - packets are GRE encapped
                #
                tx_e = self.create_stream_ip6(self.pg0, "5::5", route_addr,
                                              dscp=2, ecn=1)
                rx = self.send_and_expect(self.pg0, tx_e, itf)
                self.verify_tunneled_6o6(self.pg0, rx, tx_e,
                                         itf.local_ip6,
                                         itf._remote_hosts[ii].ip6,
                                         dscp=2)
                tx_i = self.create_tunnel_stream_6o6(self.pg0,
                                                     itf._remote_hosts[ii].ip6,
                                                     itf.local_ip6,
                                                     self.pg0.local_ip6,
                                                     self.pg0.remote_ip6)
                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
                self.verify_decapped_6o6(self.pg0, rx, tx_i)

                #
                # delete and re-add the TEIB
                #
                teib.remove_vpp_config()
                self.send_and_assert_no_replies(self.pg0, tx_e)

                teib.add_vpp_config()
                rx = self.send_and_expect(self.pg0, tx_e, itf)
                self.verify_tunneled_6o6(self.pg0, rx, tx_e,
                                         itf.local_ip6,
                                         itf._remote_hosts[ii].ip6,
                                         dscp=2)
                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
                self.verify_decapped_6o6(self.pg0, rx, tx_i)

            gre_if.admin_down()
            gre_if.unconfig_ip4()
            itf.unconfig_ip6()
        self.pg0.unconfig_ip6()
예제 #13
0
    def test_abf4(self):
        """ IPv4 ACL Based Forwarding
        """

        #
        # We are not testing the various matching capabilities
        # of ACLs, that's done elsewhere. Here ware are testing
        # the application of ACLs to a forwarding path to achieve
        # ABF
        # So we construct just a few ACLs to ensure the ABF policies
        # are correctly constructed and used. And a few path types
        # to test the API path decoding.
        #

        #
        # Rule 1
        #
        rule_1 = ({
            'is_permit': 1,
            'is_ipv6': 0,
            'proto': 17,
            'srcport_or_icmptype_first': 1234,
            'srcport_or_icmptype_last': 1234,
            'src_ip_prefix_len': 32,
            'src_ip_addr': inet_pton(AF_INET, "1.1.1.1"),
            'dstport_or_icmpcode_first': 1234,
            'dstport_or_icmpcode_last': 1234,
            'dst_ip_prefix_len': 32,
            'dst_ip_addr': inet_pton(AF_INET, "1.1.1.2")
        })
        acl_1 = self.vapi.acl_add_replace(acl_index=4294967295, r=[rule_1])

        #
        # ABF policy for ACL 1 - path via interface 1
        #
        abf_1 = VppAbfPolicy(
            self, 10, acl_1,
            [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)])
        abf_1.add_vpp_config()

        #
        # Attach the policy to input interface Pg0
        #
        attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 50)
        attach_1.add_vpp_config()

        #
        # fire in packet matching the ACL src,dst. If it's forwarded
        # then the ABF was successful, since default routing will drop it
        #
        p_1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
               IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) /
               Raw('\xa5' * 100))
        self.send_and_expect(self.pg0, p_1 * 65, self.pg1)

        #
        # Attach a 'better' priority policy to the same interface
        #
        abf_2 = VppAbfPolicy(
            self, 11, acl_1,
            [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)])
        abf_2.add_vpp_config()
        attach_2 = VppAbfAttach(self, 11, self.pg0.sw_if_index, 40)
        attach_2.add_vpp_config()

        self.send_and_expect(self.pg0, p_1 * 65, self.pg2)

        #
        # Attach a policy with priority in the middle
        #
        abf_3 = VppAbfPolicy(
            self, 12, acl_1,
            [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)])
        abf_3.add_vpp_config()
        attach_3 = VppAbfAttach(self, 12, self.pg0.sw_if_index, 45)
        attach_3.add_vpp_config()

        self.send_and_expect(self.pg0, p_1 * 65, self.pg2)

        #
        # remove the best priority
        #
        attach_2.remove_vpp_config()
        self.send_and_expect(self.pg0, p_1 * 65, self.pg3)

        #
        # Attach one of the same policies to Pg1
        #
        attach_4 = VppAbfAttach(self, 12, self.pg1.sw_if_index, 45)
        attach_4.add_vpp_config()

        p_2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
               IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) /
               Raw('\xa5' * 100))
        self.send_and_expect(self.pg1, p_2 * 65, self.pg3)

        #
        # detach the policy from PG1, now expect traffic to be dropped
        #
        attach_4.remove_vpp_config()

        self.send_and_assert_no_replies(self.pg1, p_2 * 65, "Detached")

        #
        # Swap to route via a next-hop in the non-default table
        #
        table_20 = VppIpTable(self, 20)
        table_20.add_vpp_config()

        self.pg4.set_table_ip4(table_20.table_id)
        self.pg4.admin_up()
        self.pg4.config_ip4()
        self.pg4.resolve_arp()

        abf_13 = VppAbfPolicy(self, 13, acl_1, [
            VppRoutePath(
                self.pg4.remote_ip4, 0xffffffff, nh_table_id=table_20.table_id)
        ])
        abf_13.add_vpp_config()
        attach_5 = VppAbfAttach(self, 13, self.pg0.sw_if_index, 30)
        attach_5.add_vpp_config()

        self.send_and_expect(self.pg0, p_1 * 65, self.pg4)

        self.pg4.unconfig_ip4()
        self.pg4.set_table_ip4(0)
예제 #14
0
class TestIgmp(VppTestCase):
    """ IGMP Test Case """
    def setUp(self):
        super(TestIgmp, self).setUp()

        self.create_pg_interfaces(range(4))
        self.sg_list = []
        self.config_list = []

        self.ip_addr = []
        self.ip_table = VppIpTable(self, 1)
        self.ip_table.add_vpp_config()

        for pg in self.pg_interfaces[2:]:
            pg.set_table_ip4(1)
        for pg in self.pg_interfaces:
            pg.admin_up()
            pg.config_ip4()
            pg.resolve_arp()

    def tearDown(self):
        for pg in self.pg_interfaces:
            self.vapi.igmp_clear_interface(pg.sw_if_index)
            pg.unconfig_ip4()
            pg.set_table_ip4(0)
            pg.admin_down()
        super(TestIgmp, self).tearDown()

    def send(self, ti, pkts):
        ti.add_stream(pkts)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

    def test_igmp_flush(self):
        """ IGMP Link Up/down and Flush """

        #
        # FIX THIS. Link down.
        #

    def test_igmp_enable(self):
        """ IGMP enable/disable on an interface

        check for the addition/removal of the IGMP mroutes """

        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 1, IGMP_MODE.HOST)

        self.assertTrue(find_mroute(self, "224.0.0.1", "0.0.0.0", 32))
        self.assertTrue(find_mroute(self, "224.0.0.22", "0.0.0.0", 32))

        self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 1, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg3.sw_if_index, 1, IGMP_MODE.HOST)

        self.assertTrue(
            find_mroute(self, "224.0.0.1", "0.0.0.0", 32, table_id=1))
        self.assertTrue(
            find_mroute(self, "224.0.0.22", "0.0.0.0", 32, table_id=1))
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 0, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 0, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg3.sw_if_index, 0, IGMP_MODE.HOST)

        self.assertFalse(find_mroute(self, "224.0.0.1", "0.0.0.0", 32))
        self.assertFalse(find_mroute(self, "224.0.0.22", "0.0.0.0", 32))
        self.assertFalse(
            find_mroute(self, "224.0.0.1", "0.0.0.0", 32, table_id=1))
        self.assertFalse(
            find_mroute(self, "224.0.0.22", "0.0.0.0", 32, table_id=1))

    def verify_general_query(self, p):
        ip = p[IP]
        self.assertEqual(len(ip.options), 1)
        self.assertEqual(ip.options[0].option, 20)
        self.assertEqual(ip.dst, "224.0.0.1")
        self.assertEqual(ip.proto, 2)
        igmp = p[IGMPv3]
        self.assertEqual(igmp.type, 0x11)
        self.assertEqual(igmp.gaddr, "0.0.0.0")

    def verify_group_query(self, p, grp, srcs):
        ip = p[IP]
        self.assertEqual(ip.dst, grp)
        self.assertEqual(ip.proto, 2)
        self.assertEqual(len(ip.options), 1)
        self.assertEqual(ip.options[0].option, 20)
        self.assertEqual(ip.proto, 2)
        igmp = p[IGMPv3]
        self.assertEqual(igmp.type, 0x11)
        self.assertEqual(igmp.gaddr, grp)

    def verify_report(self, rx, records):
        ip = rx[IP]
        self.assertEqual(rx[IP].dst, "224.0.0.22")
        self.assertEqual(len(ip.options), 1)
        self.assertEqual(ip.options[0].option, 20)
        self.assertEqual(ip.proto, 2)
        self.assertEqual(IGMPv3.igmpv3types[rx[IGMPv3].type],
                         "Version 3 Membership Report")
        self.assertEqual(rx[IGMPv3mr].numgrp, len(records))

        received = rx[IGMPv3mr].records

        for ii in range(len(records)):
            gr = received[ii]
            r = records[ii]
            self.assertEqual(IGMPv3gr.igmpv3grtypes[gr.rtype], r.type)
            self.assertEqual(gr.numsrc, len(r.sg.saddrs))
            self.assertEqual(gr.maddr, r.sg.gaddr)
            self.assertEqual(len(gr.srcaddrs), len(r.sg.saddrs))

            self.assertEqual(sorted(gr.srcaddrs), sorted(r.sg.saddrs))

    def add_group(self, itf, sg, n_pkts=2):
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        hs = VppHostState(self, IGMP_FILTER.INCLUDE, itf.sw_if_index, sg)
        hs.add_vpp_config()

        capture = itf.get_capture(n_pkts, timeout=10)

        # reports are transmitted twice due to default rebostness value=2
        self.verify_report(capture[0], [IgmpRecord(sg, "Allow New Sources")]),
        self.verify_report(capture[1], [IgmpRecord(sg, "Allow New Sources")]),

        return hs

    def remove_group(self, hs):
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        hs.remove_vpp_config()

        capture = self.pg0.get_capture(1, timeout=10)

        self.verify_report(capture[0],
                           [IgmpRecord(hs.sg, "Block Old Sources")])

    def test_igmp_host(self):
        """ IGMP Host functions """

        #
        # Enable interface for host functions
        #
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST)

        #
        # Add one S,G of state and expect a state-change event report
        # indicating the addition of the S,G
        #
        h1 = self.add_group(self.pg0, IgmpSG("239.1.1.1", ["1.1.1.1"]))

        # search for the corresponding state created in VPP
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 1)
        self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.1",
                                        "1.1.1.1"))

        #
        # Send a general query (to the all router's address)
        # expect VPP to respond with a membership report
        #
        p_g = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
               IP(src=self.pg0.remote_ip4, dst='224.0.0.1', tos=0xc0) /
               IGMPv3(type="Membership Query", mrcode=100) /
               IGMPv3mq(gaddr="0.0.0.0"))

        self.send(self.pg0, p_g)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])

        #
        # Group specific query
        #
        p_gs = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4,
               dst='239.1.1.1',
               tos=0xc0,
               options=[
                   IPOption(
                       copy_flag=1, optclass="control", option="router_alert")
               ]) / IGMPv3(type="Membership Query", mrcode=100) /
            IGMPv3mq(gaddr="239.1.1.1"))

        self.send(self.pg0, p_gs)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])

        #
        # A group and source specific query, with the source matching
        # the source VPP has
        #
        p_gs1 = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4,
               dst='239.1.1.1',
               tos=0xc0,
               options=[
                   IPOption(
                       copy_flag=1, optclass="control", option="router_alert")
               ]) / IGMPv3(type="Membership Query", mrcode=100) /
            IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.1"]))

        self.send(self.pg0, p_gs1)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])

        #
        # A group and source specific query, with the source NOT matching
        # the source VPP has. There should be no response.
        #
        p_gs2 = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4,
               dst='239.1.1.1',
               tos=0xc0,
               options=[
                   IPOption(
                       copy_flag=1, optclass="control", option="router_alert")
               ]) / IGMPv3(type="Membership Query", mrcode=100) /
            IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.2"]))

        self.send_and_assert_no_replies(self.pg0, p_gs2, timeout=10)

        #
        # A group and source specific query, with the multiple sources
        # one of which matches the source VPP has.
        # The report should contain only the source VPP has.
        #
        p_gs3 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(
            src=self.pg0.remote_ip4,
            dst='239.1.1.1',
            tos=0xc0,
            options=[
                IPOption(
                    copy_flag=1, optclass="control", option="router_alert")
            ]) / IGMPv3(type="Membership Query", mrcode=100) / IGMPv3mq(
                gaddr="239.1.1.1", srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.3"]))

        self.send(self.pg0, p_gs3)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])

        #
        # Two source and group specific queries in quick succession, the
        # first does not have VPPs source the second does. then vice-versa
        #
        self.send(self.pg0, [p_gs2, p_gs1])
        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])

        self.send(self.pg0, [p_gs1, p_gs2])
        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])

        #
        # remove state, expect the report for the removal
        #
        self.remove_group(h1)

        dump = self.vapi.igmp_dump()
        self.assertFalse(dump)

        #
        # A group with multiple sources
        #
        h2 = self.add_group(
            self.pg0, IgmpSG("239.1.1.1", ["1.1.1.1", "1.1.1.2", "1.1.1.3"]))

        # search for the corresponding state created in VPP
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 3)
        for s in h2.sg.saddrs:
            self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.1", s))
        #
        # Send a general query (to the all router's address)
        # expect VPP to respond with a membership report will all sources
        #
        self.send(self.pg0, p_g)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0], [IgmpRecord(h2.sg, "Mode Is Include")])

        #
        # Group and source specific query; some present some not
        #
        p_gs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(
            src=self.pg0.remote_ip4,
            dst='239.1.1.1',
            tos=0xc0,
            options=[
                IPOption(
                    copy_flag=1, optclass="control", option="router_alert")
            ]) / IGMPv3(type="Membership Query", mrcode=100) / IGMPv3mq(
                gaddr="239.1.1.1", srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.4"]))

        self.send(self.pg0, p_gs)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0], [
            IgmpRecord(IgmpSG('239.1.1.1', ["1.1.1.1", "1.1.1.2"]),
                       "Mode Is Include")
        ])

        #
        # add loads more groups
        #
        h3 = self.add_group(
            self.pg0, IgmpSG("239.1.1.2", ["2.1.1.1", "2.1.1.2", "2.1.1.3"]))
        h4 = self.add_group(
            self.pg0, IgmpSG("239.1.1.3", ["3.1.1.1", "3.1.1.2", "3.1.1.3"]))
        h5 = self.add_group(
            self.pg0, IgmpSG("239.1.1.4", ["4.1.1.1", "4.1.1.2", "4.1.1.3"]))
        h6 = self.add_group(
            self.pg0, IgmpSG("239.1.1.5", ["5.1.1.1", "5.1.1.2", "5.1.1.3"]))
        h7 = self.add_group(
            self.pg0,
            IgmpSG("239.1.1.6", [
                "6.1.1.1", "6.1.1.2", "6.1.1.3", "6.1.1.4", "6.1.1.5",
                "6.1.1.6", "6.1.1.7", "6.1.1.8", "6.1.1.9", "6.1.1.10",
                "6.1.1.11", "6.1.1.12", "6.1.1.13", "6.1.1.14", "6.1.1.15",
                "6.1.1.16"
            ]))

        #
        # general query.
        # the order the groups come in is not important, so what is
        # checked for is what VPP is sending today.
        #
        self.send(self.pg0, p_g)

        capture = self.pg0.get_capture(1, timeout=10)

        self.verify_report(capture[0], [
            IgmpRecord(h3.sg, "Mode Is Include"),
            IgmpRecord(h2.sg, "Mode Is Include"),
            IgmpRecord(h6.sg, "Mode Is Include"),
            IgmpRecord(h4.sg, "Mode Is Include"),
            IgmpRecord(h5.sg, "Mode Is Include"),
            IgmpRecord(h7.sg, "Mode Is Include")
        ])

        #
        # modify a group to add and remove some sources
        #
        h7.sg = IgmpSG("239.1.1.6", [
            "6.1.1.1", "6.1.1.2", "6.1.1.5", "6.1.1.6", "6.1.1.7", "6.1.1.8",
            "6.1.1.9", "6.1.1.10", "6.1.1.11", "6.1.1.12", "6.1.1.13",
            "6.1.1.14", "6.1.1.15", "6.1.1.16", "6.1.1.17", "6.1.1.18"
        ])

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        h7.add_vpp_config()

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0], [
            IgmpRecord(IgmpSG("239.1.1.6", ["6.1.1.17", "6.1.1.18"]),
                       "Allow New Sources"),
            IgmpRecord(IgmpSG("239.1.1.6", ["6.1.1.3", "6.1.1.4"]),
                       "Block Old Sources")
        ])

        #
        # add an additional groups with many sources so that each group
        # consumes the link MTU. We should therefore see multiple state
        # state reports when queried.
        #
        self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [560, 0, 0, 0])

        src_list = []
        for i in range(128):
            src_list.append("10.1.1.%d" % i)

        h8 = self.add_group(self.pg0, IgmpSG("238.1.1.1", src_list))
        h9 = self.add_group(self.pg0, IgmpSG("238.1.1.2", src_list))

        self.send(self.pg0, p_g)

        capture = self.pg0.get_capture(4, timeout=10)

        self.verify_report(capture[0], [
            IgmpRecord(h3.sg, "Mode Is Include"),
            IgmpRecord(h2.sg, "Mode Is Include"),
            IgmpRecord(h6.sg, "Mode Is Include"),
            IgmpRecord(h4.sg, "Mode Is Include"),
            IgmpRecord(h5.sg, "Mode Is Include")
        ])
        self.verify_report(capture[1], [IgmpRecord(h8.sg, "Mode Is Include")])
        self.verify_report(capture[2], [IgmpRecord(h7.sg, "Mode Is Include")])
        self.verify_report(capture[3], [IgmpRecord(h9.sg, "Mode Is Include")])

        #
        # drop the MTU further (so a 128 sized group won't fit)
        #
        self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [512, 0, 0, 0])

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        h10 = VppHostState(self, IGMP_FILTER.INCLUDE, self.pg0.sw_if_index,
                           IgmpSG("238.1.1.3", src_list))
        h10.add_vpp_config()

        capture = self.pg0.get_capture(2, timeout=10)

        #
        # remove state, expect the report for the removal
        # the dump should be empty
        #
        self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [600, 0, 0, 0])
        self.remove_group(h8)
        self.remove_group(h9)
        self.remove_group(h2)
        self.remove_group(h3)
        self.remove_group(h4)
        self.remove_group(h5)
        self.remove_group(h6)
        self.remove_group(h7)
        self.remove_group(h10)

        self.logger.info(self.vapi.cli("sh igmp config"))
        self.assertFalse(self.vapi.igmp_dump())

        #
        # TODO
        #  ADD STATE ON MORE INTERFACES
        #

        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST)

    def test_igmp_router(self):
        """ IGMP Router Functions """

        #
        # Drop reports when not enabled
        #
        p_j = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4,
               dst="224.0.0.22",
               tos=0xc0,
               ttl=1,
               options=[
                   IPOption(
                       copy_flag=1, optclass="control", option="router_alert")
               ]) / IGMPv3(type="Version 3 Membership Report") /
            IGMPv3mr(numgrp=1) / IGMPv3gr(rtype="Allow New Sources",
                                          maddr="239.1.1.1",
                                          srcaddrs=["10.1.1.1", "10.1.1.2"]))
        p_l = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4,
               dst="224.0.0.22",
               tos=0xc0,
               options=[
                   IPOption(
                       copy_flag=1, optclass="control", option="router_alert")
               ]) / IGMPv3(type="Version 3 Membership Report") /
            IGMPv3mr(numgrp=1) / IGMPv3gr(rtype="Block Old Sources",
                                          maddr="239.1.1.1",
                                          srcaddrs=["10.1.1.1", "10.1.1.2"]))

        self.send(self.pg0, p_j)
        self.assertFalse(self.vapi.igmp_dump())

        #
        # drop the default timer values so these tests execute in a
        # reasonable time frame
        #
        self.vapi.cli("test igmp timers query 1 src 3 leave 1")

        #
        # enable router functions on the interface
        #
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1,
                                      IGMP_MODE.ROUTER)
        self.vapi.want_igmp_events(1)

        #
        # wait for router to send general query
        #
        for ii in range(3):
            capture = self.pg0.get_capture(1, timeout=2)
            self.verify_general_query(capture[0])
            self.pg_enable_capture(self.pg_interfaces)
            self.pg_start()

        #
        # re-send the report. VPP should now hold state for the new group
        # VPP sends a notification that a new group has been joined
        #
        self.send(self.pg0, p_j)

        self.assertTrue(
            wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.1", 1))
        self.assertTrue(
            wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 1))
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 2)
        self.assertTrue(
            find_igmp_state(dump, self.pg0, "239.1.1.1", "10.1.1.1"))
        self.assertTrue(
            find_igmp_state(dump, self.pg0, "239.1.1.1", "10.1.1.2"))

        #
        # wait for the per-source timer to expire
        # the state should be reaped
        # VPP sends a notification that the group has been left
        #
        self.assertTrue(
            wait_for_igmp_event(self, 4, self.pg0, "239.1.1.1", "10.1.1.1", 0))
        self.assertTrue(
            wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 0))
        self.assertFalse(self.vapi.igmp_dump())

        #
        # resend the join. wait for two queries and then send a current-state
        # record to include all sources. this should reset the expiry time
        # on the sources and thus they will still be present in 2 seconds time.
        # If the source timer was not refreshed, then the state would have
        # expired in 3 seconds.
        #
        self.send(self.pg0, p_j)
        self.assertTrue(
            wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.1", 1))
        self.assertTrue(
            wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 1))
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 2)

        capture = self.pg0.get_capture(2, timeout=3)
        self.verify_general_query(capture[0])
        self.verify_general_query(capture[1])

        p_cs = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4,
               dst="224.0.0.22",
               tos=0xc0,
               options=[
                   IPOption(
                       copy_flag=1, optclass="control", option="router_alert")
               ]) / IGMPv3(type="Version 3 Membership Report") /
            IGMPv3mr(numgrp=1) / IGMPv3gr(rtype="Mode Is Include",
                                          maddr="239.1.1.1",
                                          srcaddrs=["10.1.1.1", "10.1.1.2"]))

        self.send(self.pg0, p_cs)

        self.sleep(2)
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 2)
        self.assertTrue(
            find_igmp_state(dump, self.pg0, "239.1.1.1", "10.1.1.1"))
        self.assertTrue(
            find_igmp_state(dump, self.pg0, "239.1.1.1", "10.1.1.2"))

        #
        # wait for the per-source timer to expire
        # the state should be reaped
        #
        self.assertTrue(
            wait_for_igmp_event(self, 4, self.pg0, "239.1.1.1", "10.1.1.1", 0))
        self.assertTrue(
            wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 0))
        self.assertFalse(self.vapi.igmp_dump())

        #
        # resend the join, then a leave. Router sends a group+source
        # specific query containing both sources
        #
        self.send(self.pg0, p_j)

        self.assertTrue(
            wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.1", 1))
        self.assertTrue(
            wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 1))
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 2)

        self.send(self.pg0, p_l)
        capture = self.pg0.get_capture(1, timeout=3)
        self.verify_group_query(capture[0], "239.1.1.1",
                                ["10.1.1.1", "10.1.1.2"])

        #
        # the group specific query drops the timeout to leave (=1) seconds
        #
        self.assertTrue(
            wait_for_igmp_event(self, 2, self.pg0, "239.1.1.1", "10.1.1.1", 0))
        self.assertTrue(
            wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 0))
        self.assertFalse(self.vapi.igmp_dump())
        self.assertFalse(self.vapi.igmp_dump())

        #
        # a TO_EX({}) / IN_EX({}) is treated like a (*,G) join
        #
        p_j = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4,
               dst="224.0.0.22",
               tos=0xc0,
               ttl=1,
               options=[
                   IPOption(
                       copy_flag=1, optclass="control", option="router_alert")
               ]) / IGMPv3(type="Version 3 Membership Report") /
            IGMPv3mr(numgrp=1) /
            IGMPv3gr(rtype="Change To Exclude Mode", maddr="239.1.1.2"))

        self.send(self.pg0, p_j)

        self.assertTrue(
            wait_for_igmp_event(self, 1, self.pg0, "239.1.1.2", "0.0.0.0", 1))

        p_j = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4,
               dst="224.0.0.22",
               tos=0xc0,
               ttl=1,
               options=[
                   IPOption(
                       copy_flag=1, optclass="control", option="router_alert")
               ]) / IGMPv3(type="Version 3 Membership Report") /
            IGMPv3mr(numgrp=1) /
            IGMPv3gr(rtype="Mode Is Exclude", maddr="239.1.1.3"))

        self.send(self.pg0, p_j)

        self.assertTrue(
            wait_for_igmp_event(self, 1, self.pg0, "239.1.1.3", "0.0.0.0", 1))

        #
        # A 'allow sources' for {} should be ignored as it should
        # never be sent.
        #
        p_j = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4,
               dst="224.0.0.22",
               tos=0xc0,
               ttl=1,
               options=[
                   IPOption(
                       copy_flag=1, optclass="control", option="router_alert")
               ]) / IGMPv3(type="Version 3 Membership Report") /
            IGMPv3mr(numgrp=1) /
            IGMPv3gr(rtype="Allow New Sources", maddr="239.1.1.4"))

        self.send(self.pg0, p_j)

        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.2",
                                        "0.0.0.0"))
        self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.3",
                                        "0.0.0.0"))
        self.assertFalse(
            find_igmp_state(dump, self.pg0, "239.1.1.4", "0.0.0.0"))

        #
        # a TO_IN({}) and IS_IN({}) are treated like a (*,G) leave
        #
        self.vapi.cli("set logging class igmp level debug")
        p_l = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4,
               dst="224.0.0.22",
               tos=0xc0,
               ttl=1,
               options=[
                   IPOption(
                       copy_flag=1, optclass="control", option="router_alert")
               ]) / IGMPv3(type="Version 3 Membership Report") /
            IGMPv3mr(numgrp=1) /
            IGMPv3gr(rtype="Change To Include Mode", maddr="239.1.1.2"))

        self.send(self.pg0, p_l)
        self.assertTrue(
            wait_for_igmp_event(self, 2, self.pg0, "239.1.1.2", "0.0.0.0", 0))

        p_l = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4,
               dst="224.0.0.22",
               tos=0xc0,
               ttl=1,
               options=[
                   IPOption(
                       copy_flag=1, optclass="control", option="router_alert")
               ]) / IGMPv3(type="Version 3 Membership Report") /
            IGMPv3mr(numgrp=1) /
            IGMPv3gr(rtype="Mode Is Include", maddr="239.1.1.3"))

        self.send(self.pg0, p_l)

        self.assertTrue(
            wait_for_igmp_event(self, 2, self.pg0, "239.1.1.3", "0.0.0.0", 0))
        self.assertFalse(self.vapi.igmp_dump(self.pg0.sw_if_index))

        #
        # disable router config
        #
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0,
                                      IGMP_MODE.ROUTER)

    def _create_igmpv3_pck(self, itf, rtype, maddr, srcaddrs):
        p = (Ether(dst=itf.local_mac, src=itf.remote_mac) /
             IP(src=itf.remote_ip4,
                dst="224.0.0.22",
                tos=0xc0,
                ttl=1,
                options=[
                    IPOption(
                        copy_flag=1, optclass="control", option="router_alert")
                ]) / IGMPv3(type="Version 3 Membership Report") /
             IGMPv3mr(numgrp=1) /
             IGMPv3gr(rtype=rtype, maddr=maddr, srcaddrs=srcaddrs))
        return p

    def test_igmp_proxy_device(self):
        """ IGMP proxy device """
        self.pg2.admin_down()
        self.pg2.unconfig_ip4()
        self.pg2.set_table_ip4(0)
        self.pg2.config_ip4()
        self.pg2.admin_up()

        self.vapi.cli('test igmp timers query 10 src 3 leave 1')

        # enable IGMP
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 1,
                                      IGMP_MODE.ROUTER)
        self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 1,
                                      IGMP_MODE.ROUTER)

        # create IGMP proxy device
        self.vapi.igmp_proxy_device_add_del(0, self.pg0.sw_if_index, 1)
        self.vapi.igmp_proxy_device_add_del_interface(0, self.pg1.sw_if_index,
                                                      1)
        self.vapi.igmp_proxy_device_add_del_interface(0, self.pg2.sw_if_index,
                                                      1)

        # send join on pg1. join should be proxied by pg0
        p_j = self._create_igmpv3_pck(self.pg1, "Allow New Sources",
                                      "239.1.1.1", ["10.1.1.1", "10.1.1.2"])
        self.send(self.pg1, p_j)

        capture = self.pg0.get_capture(1, timeout=1)
        self.verify_report(capture[0], [
            IgmpRecord(IgmpSG("239.1.1.1", ["10.1.1.1", "10.1.1.2"]),
                       "Allow New Sources")
        ])
        self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))

        # send join on pg2. join should be proxied by pg0.
        # the group should contain only 10.1.1.3 as
        # 10.1.1.1 was already reported
        p_j = self._create_igmpv3_pck(self.pg2, "Allow New Sources",
                                      "239.1.1.1", ["10.1.1.1", "10.1.1.3"])
        self.send(self.pg2, p_j)

        capture = self.pg0.get_capture(1, timeout=1)
        self.verify_report(capture[0], [
            IgmpRecord(IgmpSG("239.1.1.1", ["10.1.1.3"]), "Allow New Sources")
        ])
        self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))

        # send leave on pg2. leave for 10.1.1.3 should be proxyed
        # as pg2 was the only interface interested in 10.1.1.3
        p_l = self._create_igmpv3_pck(self.pg2, "Block Old Sources",
                                      "239.1.1.1", ["10.1.1.3"])
        self.send(self.pg2, p_l)

        capture = self.pg0.get_capture(1, timeout=2)
        self.verify_report(capture[0], [
            IgmpRecord(IgmpSG("239.1.1.1", ["10.1.1.3"]), "Block Old Sources")
        ])
        self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))

        # disable igmp on pg1 (also removes interface from proxy device)
        # proxy leave for 10.1.1.2. pg2 is still interested in 10.1.1.1
        self.pg_enable_capture(self.pg_interfaces)
        self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 0,
                                      IGMP_MODE.ROUTER)

        capture = self.pg0.get_capture(1, timeout=1)
        self.verify_report(capture[0], [
            IgmpRecord(IgmpSG("239.1.1.1", ["10.1.1.2"]), "Block Old Sources")
        ])
        self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))

        # disable IGMP on pg0 and pg1.
        #   disabling IGMP on pg0 (proxy device upstream interface)
        #   removes this proxy device
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 0,
                                      IGMP_MODE.ROUTER)
        self.assertFalse(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))
예제 #15
0
    def test_ip_deag(self):
        """ IP Deag Routes """

        #
        # Create a table to be used for:
        #  1 - another destination address lookup
        #  2 - a source address lookup
        #
        table_dst = VppIpTable(self, 1)
        table_src = VppIpTable(self, 2)
        table_dst.add_vpp_config()
        table_src.add_vpp_config()

        #
        # Add a route in the default table to point to a deag/
        # second lookup in each of these tables
        #
        route_to_dst = VppIpRoute(self, "1.1.1.1", 32,
                                  [VppRoutePath("0.0.0.0",
                                                0xffffffff,
                                                nh_table_id=1)])
        route_to_src = VppIpRoute(self, "1.1.1.2", 32,
                                  [VppRoutePath("0.0.0.0",
                                                0xffffffff,
                                                nh_table_id=2,
                                                is_source_lookup=1)])
        route_to_dst.add_vpp_config()
        route_to_src.add_vpp_config()

        #
        # packets to these destination are dropped, since they'll
        # hit the respective default routes in the second table
        #
        p_dst = (Ether(src=self.pg0.remote_mac,
                       dst=self.pg0.local_mac) /
                 IP(src="5.5.5.5", dst="1.1.1.1") /
                 TCP(sport=1234, dport=1234) /
                 Raw('\xa5' * 100))
        p_src = (Ether(src=self.pg0.remote_mac,
                       dst=self.pg0.local_mac) /
                 IP(src="2.2.2.2", dst="1.1.1.2") /
                 TCP(sport=1234, dport=1234) /
                 Raw('\xa5' * 100))
        pkts_dst = p_dst * 257
        pkts_src = p_src * 257

        self.send_and_assert_no_replies(self.pg0, pkts_dst,
                                        "IP in dst table")
        self.send_and_assert_no_replies(self.pg0, pkts_src,
                                        "IP in src table")

        #
        # add a route in the dst table to forward via pg1
        #
        route_in_dst = VppIpRoute(self, "1.1.1.1", 32,
                                  [VppRoutePath(self.pg1.remote_ip4,
                                                self.pg1.sw_if_index)],
                                  table_id=1)
        route_in_dst.add_vpp_config()
        self.send_and_expect(self.pg0, pkts_dst, self.pg1)

        #
        # add a route in the src table to forward via pg2
        #
        route_in_src = VppIpRoute(self, "2.2.2.2", 32,
                                  [VppRoutePath(self.pg2.remote_ip4,
                                                self.pg2.sw_if_index)],
                                  table_id=2)
        route_in_src.add_vpp_config()
        self.send_and_expect(self.pg0, pkts_src, self.pg2)
예제 #16
0
파일: test_igmp.py 프로젝트: chrisy/vpp
class TestIgmp(VppTestCase):
    """ IGMP Test Case """

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

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

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

        self.create_pg_interfaces(range(4))
        self.sg_list = []
        self.config_list = []

        self.ip_addr = []
        self.ip_table = VppIpTable(self, 1)
        self.ip_table.add_vpp_config()

        for pg in self.pg_interfaces[2:]:
            pg.set_table_ip4(1)
        for pg in self.pg_interfaces:
            pg.admin_up()
            pg.config_ip4()
            pg.resolve_arp()

    def tearDown(self):
        for pg in self.pg_interfaces:
            self.vapi.igmp_clear_interface(pg.sw_if_index)
            pg.unconfig_ip4()
            pg.set_table_ip4(0)
            pg.admin_down()
        super(TestIgmp, self).tearDown()

    def send(self, ti, pkts):
        ti.add_stream(pkts)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

    def test_igmp_flush(self):
        """ IGMP Link Up/down and Flush """

        #
        # FIX THIS. Link down.
        #

    def test_igmp_enable(self):
        """ IGMP enable/disable on an interface

        check for the addition/removal of the IGMP mroutes """

        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 1, IGMP_MODE.HOST)

        self.assertTrue(find_mroute(self, "224.0.0.1", "0.0.0.0", 32))
        self.assertTrue(find_mroute(self, "224.0.0.22", "0.0.0.0", 32))

        self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 1, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg3.sw_if_index, 1, IGMP_MODE.HOST)

        self.assertTrue(find_mroute(self, "224.0.0.1", "0.0.0.0", 32,
                                    table_id=1))
        self.assertTrue(find_mroute(self, "224.0.0.22", "0.0.0.0", 32,
                                    table_id=1))
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 0, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 0, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg3.sw_if_index, 0, IGMP_MODE.HOST)

        self.assertFalse(find_mroute(self, "224.0.0.1", "0.0.0.0", 32))
        self.assertFalse(find_mroute(self, "224.0.0.22", "0.0.0.0", 32))
        self.assertFalse(find_mroute(self, "224.0.0.1", "0.0.0.0", 32,
                                     table_id=1))
        self.assertFalse(find_mroute(self, "224.0.0.22", "0.0.0.0", 32,
                                     table_id=1))

    def verify_general_query(self, p):
        ip = p[IP]
        self.assertEqual(len(ip.options), 1)
        self.assertEqual(ip.options[0].option, 20)
        self.assertEqual(ip.dst, "224.0.0.1")
        self.assertEqual(ip.proto, 2)
        igmp = p[IGMPv3]
        self.assertEqual(igmp.type, 0x11)
        self.assertEqual(igmp.gaddr, "0.0.0.0")

    def verify_group_query(self, p, grp, srcs):
        ip = p[IP]
        self.assertEqual(ip.dst, grp)
        self.assertEqual(ip.proto, 2)
        self.assertEqual(len(ip.options), 1)
        self.assertEqual(ip.options[0].option, 20)
        self.assertEqual(ip.proto, 2)
        igmp = p[IGMPv3]
        self.assertEqual(igmp.type, 0x11)
        self.assertEqual(igmp.gaddr, grp)

    def verify_report(self, rx, records):
        ip = rx[IP]
        self.assertEqual(rx[IP].dst, "224.0.0.22")
        self.assertEqual(len(ip.options), 1)
        self.assertEqual(ip.options[0].option, 20)
        self.assertEqual(ip.proto, 2)
        self.assertEqual(IGMPv3.igmpv3types[rx[IGMPv3].type],
                         "Version 3 Membership Report")
        self.assertEqual(rx[IGMPv3mr].numgrp, len(records))

        received = rx[IGMPv3mr].records

        for ii in range(len(records)):
            gr = received[ii]
            r = records[ii]
            self.assertEqual(IGMPv3gr.igmpv3grtypes[gr.rtype], r.type)
            self.assertEqual(gr.numsrc, len(r.sg.saddrs))
            self.assertEqual(gr.maddr, r.sg.gaddr)
            self.assertEqual(len(gr.srcaddrs), len(r.sg.saddrs))

            self.assertEqual(sorted(gr.srcaddrs),
                             sorted(r.sg.saddrs))

    def add_group(self, itf, sg, n_pkts=2):
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        hs = VppHostState(self,
                          IGMP_FILTER.INCLUDE,
                          itf.sw_if_index,
                          sg)
        hs.add_vpp_config()

        capture = itf.get_capture(n_pkts, timeout=10)

        # reports are transmitted twice due to default rebostness value=2
        self.verify_report(capture[0],
                           [IgmpRecord(sg, "Allow New Sources")]),
        self.verify_report(capture[1],
                           [IgmpRecord(sg, "Allow New Sources")]),

        return hs

    def remove_group(self, hs):
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        hs.remove_vpp_config()

        capture = self.pg0.get_capture(1, timeout=10)

        self.verify_report(capture[0],
                           [IgmpRecord(hs.sg, "Block Old Sources")])

    def test_igmp_host(self):
        """ IGMP Host functions """

        #
        # Enable interface for host functions
        #
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index,
                                      1,
                                      IGMP_MODE.HOST)

        #
        # Add one S,G of state and expect a state-change event report
        # indicating the addition of the S,G
        #
        h1 = self.add_group(self.pg0, IgmpSG("239.1.1.1", ["1.1.1.1"]))

        # search for the corresponding state created in VPP
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 1)
        self.assertTrue(find_igmp_state(dump, self.pg0,
                                        "239.1.1.1", "1.1.1.1"))

        #
        # Send a general query (to the all router's address)
        # expect VPP to respond with a membership report
        #
        p_g = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
               IP(src=self.pg0.remote_ip4, dst='224.0.0.1', tos=0xc0) /
               IGMPv3(type="Membership Query", mrcode=100) /
               IGMPv3mq(gaddr="0.0.0.0"))

        self.send(self.pg0, p_g)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0],
                           [IgmpRecord(h1.sg, "Mode Is Include")])

        #
        # Group specific query
        #
        p_gs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0,
                   options=[IPOption(copy_flag=1, optclass="control",
                                     option="router_alert")]) /
                IGMPv3(type="Membership Query", mrcode=100) /
                IGMPv3mq(gaddr="239.1.1.1"))

        self.send(self.pg0, p_gs)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0],
                           [IgmpRecord(h1.sg, "Mode Is Include")])

        #
        # A group and source specific query, with the source matching
        # the source VPP has
        #
        p_gs1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                 IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0,
                    options=[IPOption(copy_flag=1, optclass="control",
                                      option="router_alert")]) /
                 IGMPv3(type="Membership Query", mrcode=100) /
                 IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.1"]))

        self.send(self.pg0, p_gs1)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0],
                           [IgmpRecord(h1.sg, "Mode Is Include")])

        #
        # A group and source specific query, with the source NOT matching
        # the source VPP has. There should be no response.
        #
        p_gs2 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                 IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0,
                    options=[IPOption(copy_flag=1, optclass="control",
                                      option="router_alert")]) /
                 IGMPv3(type="Membership Query", mrcode=100) /
                 IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.2"]))

        self.send_and_assert_no_replies(self.pg0, p_gs2, timeout=10)

        #
        # A group and source specific query, with the multiple sources
        # one of which matches the source VPP has.
        # The report should contain only the source VPP has.
        #
        p_gs3 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                 IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0,
                    options=[IPOption(copy_flag=1, optclass="control",
                                      option="router_alert")]) /
                 IGMPv3(type="Membership Query", mrcode=100) /
                 IGMPv3mq(gaddr="239.1.1.1",
                          srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.3"]))

        self.send(self.pg0, p_gs3)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0],
                           [IgmpRecord(h1.sg, "Mode Is Include")])

        #
        # Two source and group specific queries in quick succession, the
        # first does not have VPPs source the second does. then vice-versa
        #
        self.send(self.pg0, [p_gs2, p_gs1])
        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0],
                           [IgmpRecord(h1.sg, "Mode Is Include")])

        self.send(self.pg0, [p_gs1, p_gs2])
        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0],
                           [IgmpRecord(h1.sg, "Mode Is Include")])

        #
        # remove state, expect the report for the removal
        #
        self.remove_group(h1)

        dump = self.vapi.igmp_dump()
        self.assertFalse(dump)

        #
        # A group with multiple sources
        #
        h2 = self.add_group(self.pg0,
                            IgmpSG("239.1.1.1",
                                   ["1.1.1.1", "1.1.1.2", "1.1.1.3"]))

        # search for the corresponding state created in VPP
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 3)
        for s in h2.sg.saddrs:
            self.assertTrue(find_igmp_state(dump, self.pg0,
                                            "239.1.1.1", s))
        #
        # Send a general query (to the all router's address)
        # expect VPP to respond with a membership report will all sources
        #
        self.send(self.pg0, p_g)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0],
                           [IgmpRecord(h2.sg, "Mode Is Include")])

        #
        # Group and source specific query; some present some not
        #
        p_gs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0,
                   options=[IPOption(copy_flag=1, optclass="control",
                                     option="router_alert")]) /
                IGMPv3(type="Membership Query", mrcode=100) /
                IGMPv3mq(gaddr="239.1.1.1",
                         srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.4"]))

        self.send(self.pg0, p_gs)

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0],
                           [IgmpRecord(
                               IgmpSG('239.1.1.1', ["1.1.1.1", "1.1.1.2"]),
                               "Mode Is Include")])

        #
        # add loads more groups
        #
        h3 = self.add_group(self.pg0,
                            IgmpSG("239.1.1.2",
                                   ["2.1.1.1", "2.1.1.2", "2.1.1.3"]))
        h4 = self.add_group(self.pg0,
                            IgmpSG("239.1.1.3",
                                   ["3.1.1.1", "3.1.1.2", "3.1.1.3"]))
        h5 = self.add_group(self.pg0,
                            IgmpSG("239.1.1.4",
                                   ["4.1.1.1", "4.1.1.2", "4.1.1.3"]))
        h6 = self.add_group(self.pg0,
                            IgmpSG("239.1.1.5",
                                   ["5.1.1.1", "5.1.1.2", "5.1.1.3"]))
        h7 = self.add_group(self.pg0,
                            IgmpSG("239.1.1.6",
                                   ["6.1.1.1", "6.1.1.2",
                                    "6.1.1.3", "6.1.1.4",
                                    "6.1.1.5", "6.1.1.6",
                                    "6.1.1.7", "6.1.1.8",
                                    "6.1.1.9", "6.1.1.10",
                                    "6.1.1.11", "6.1.1.12",
                                    "6.1.1.13", "6.1.1.14",
                                    "6.1.1.15", "6.1.1.16"]))

        #
        # general query.
        # the order the groups come in is not important, so what is
        # checked for is what VPP is sending today.
        #
        self.send(self.pg0, p_g)

        capture = self.pg0.get_capture(1, timeout=10)

        self.verify_report(capture[0],
                           [IgmpRecord(h3.sg, "Mode Is Include"),
                            IgmpRecord(h2.sg, "Mode Is Include"),
                            IgmpRecord(h6.sg, "Mode Is Include"),
                            IgmpRecord(h4.sg, "Mode Is Include"),
                            IgmpRecord(h5.sg, "Mode Is Include"),
                            IgmpRecord(h7.sg, "Mode Is Include")])

        #
        # modify a group to add and remove some sources
        #
        h7.sg = IgmpSG("239.1.1.6",
                       ["6.1.1.1", "6.1.1.2",
                        "6.1.1.5", "6.1.1.6",
                        "6.1.1.7", "6.1.1.8",
                        "6.1.1.9", "6.1.1.10",
                        "6.1.1.11", "6.1.1.12",
                        "6.1.1.13", "6.1.1.14",
                        "6.1.1.15", "6.1.1.16",
                        "6.1.1.17", "6.1.1.18"])

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        h7.add_vpp_config()

        capture = self.pg0.get_capture(1, timeout=10)
        self.verify_report(capture[0],
                           [IgmpRecord(IgmpSG("239.1.1.6",
                                              ["6.1.1.17", "6.1.1.18"]),
                                       "Allow New Sources"),
                            IgmpRecord(IgmpSG("239.1.1.6",
                                              ["6.1.1.3", "6.1.1.4"]),
                                       "Block Old Sources")])

        #
        # add an additional groups with many sources so that each group
        # consumes the link MTU. We should therefore see multiple state
        # state reports when queried.
        #
        self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [560, 0, 0, 0])

        src_list = []
        for i in range(128):
            src_list.append("10.1.1.%d" % i)

        h8 = self.add_group(self.pg0,
                            IgmpSG("238.1.1.1", src_list))
        h9 = self.add_group(self.pg0,
                            IgmpSG("238.1.1.2", src_list))

        self.send(self.pg0, p_g)

        capture = self.pg0.get_capture(4, timeout=10)

        self.verify_report(capture[0],
                           [IgmpRecord(h3.sg, "Mode Is Include"),
                            IgmpRecord(h2.sg, "Mode Is Include"),
                            IgmpRecord(h6.sg, "Mode Is Include"),
                            IgmpRecord(h4.sg, "Mode Is Include"),
                            IgmpRecord(h5.sg, "Mode Is Include")])
        self.verify_report(capture[1],
                           [IgmpRecord(h8.sg, "Mode Is Include")])
        self.verify_report(capture[2],
                           [IgmpRecord(h7.sg, "Mode Is Include")])
        self.verify_report(capture[3],
                           [IgmpRecord(h9.sg, "Mode Is Include")])

        #
        # drop the MTU further (so a 128 sized group won't fit)
        #
        self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [512, 0, 0, 0])

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        h10 = VppHostState(self,
                           IGMP_FILTER.INCLUDE,
                           self.pg0.sw_if_index,
                           IgmpSG("238.1.1.3", src_list))
        h10.add_vpp_config()

        capture = self.pg0.get_capture(2, timeout=10)

        #
        # remove state, expect the report for the removal
        # the dump should be empty
        #
        self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [600, 0, 0, 0])
        self.remove_group(h8)
        self.remove_group(h9)
        self.remove_group(h2)
        self.remove_group(h3)
        self.remove_group(h4)
        self.remove_group(h5)
        self.remove_group(h6)
        self.remove_group(h7)
        self.remove_group(h10)

        self.logger.info(self.vapi.cli("sh igmp config"))
        self.assertFalse(self.vapi.igmp_dump())

        #
        # TODO
        #  ADD STATE ON MORE INTERFACES
        #

        self.vapi.igmp_enable_disable(self.pg0.sw_if_index,
                                      0,
                                      IGMP_MODE.HOST)

    def test_igmp_router(self):
        """ IGMP Router Functions """

        #
        # Drop reports when not enabled
        #
        p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
               IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1,
                  options=[IPOption(copy_flag=1, optclass="control",
                                    option="router_alert")]) /
               IGMPv3(type="Version 3 Membership Report") /
               IGMPv3mr(numgrp=1) /
               IGMPv3gr(rtype="Allow New Sources",
                        maddr="239.1.1.1", srcaddrs=["10.1.1.1", "10.1.1.2"]))
        p_l = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
               IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0,
                  options=[IPOption(copy_flag=1, optclass="control",
                                    option="router_alert")]) /
               IGMPv3(type="Version 3 Membership Report") /
               IGMPv3mr(numgrp=1) /
               IGMPv3gr(rtype="Block Old Sources",
                        maddr="239.1.1.1", srcaddrs=["10.1.1.1", "10.1.1.2"]))

        self.send(self.pg0, p_j)
        self.assertFalse(self.vapi.igmp_dump())

        #
        # drop the default timer values so these tests execute in a
        # reasonable time frame
        #
        self.vapi.cli("test igmp timers query 1 src 3 leave 1")

        #
        # enable router functions on the interface
        #
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index,
                                      1,
                                      IGMP_MODE.ROUTER)
        self.vapi.want_igmp_events(1)

        #
        # wait for router to send general query
        #
        for ii in range(3):
            capture = self.pg0.get_capture(1, timeout=2)
            self.verify_general_query(capture[0])
            self.pg_enable_capture(self.pg_interfaces)
            self.pg_start()

        #
        # re-send the report. VPP should now hold state for the new group
        # VPP sends a notification that a new group has been joined
        #
        self.send(self.pg0, p_j)

        self.assertTrue(wait_for_igmp_event(self, 1, self.pg0,
                                            "239.1.1.1", "10.1.1.1", 1))
        self.assertTrue(wait_for_igmp_event(self, 1, self.pg0,
                                            "239.1.1.1", "10.1.1.2", 1))
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 2)
        self.assertTrue(find_igmp_state(dump, self.pg0,
                                        "239.1.1.1", "10.1.1.1"))
        self.assertTrue(find_igmp_state(dump, self.pg0,
                                        "239.1.1.1", "10.1.1.2"))

        #
        # wait for the per-source timer to expire
        # the state should be reaped
        # VPP sends a notification that the group has been left
        #
        self.assertTrue(wait_for_igmp_event(self, 4, self.pg0,
                                            "239.1.1.1", "10.1.1.1", 0))
        self.assertTrue(wait_for_igmp_event(self, 1, self.pg0,
                                            "239.1.1.1", "10.1.1.2", 0))
        self.assertFalse(self.vapi.igmp_dump())

        #
        # resend the join. wait for two queries and then send a current-state
        # record to include all sources. this should reset the expiry time
        # on the sources and thus they will still be present in 2 seconds time.
        # If the source timer was not refreshed, then the state would have
        # expired in 3 seconds.
        #
        self.send(self.pg0, p_j)
        self.assertTrue(wait_for_igmp_event(self, 1, self.pg0,
                                            "239.1.1.1", "10.1.1.1", 1))
        self.assertTrue(wait_for_igmp_event(self, 1, self.pg0,
                                            "239.1.1.1", "10.1.1.2", 1))
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 2)

        capture = self.pg0.get_capture(2, timeout=3)
        self.verify_general_query(capture[0])
        self.verify_general_query(capture[1])

        p_cs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0,
                   options=[IPOption(copy_flag=1, optclass="control",
                                     option="router_alert")]) /
                IGMPv3(type="Version 3 Membership Report") /
                IGMPv3mr(numgrp=1) /
                IGMPv3gr(rtype="Mode Is Include",
                         maddr="239.1.1.1", srcaddrs=["10.1.1.1", "10.1.1.2"]))

        self.send(self.pg0, p_cs)

        self.sleep(2)
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 2)
        self.assertTrue(find_igmp_state(dump, self.pg0,
                                        "239.1.1.1", "10.1.1.1"))
        self.assertTrue(find_igmp_state(dump, self.pg0,
                                        "239.1.1.1", "10.1.1.2"))

        #
        # wait for the per-source timer to expire
        # the state should be reaped
        #
        self.assertTrue(wait_for_igmp_event(self, 4, self.pg0,
                                            "239.1.1.1", "10.1.1.1", 0))
        self.assertTrue(wait_for_igmp_event(self, 1, self.pg0,
                                            "239.1.1.1", "10.1.1.2", 0))
        self.assertFalse(self.vapi.igmp_dump())

        #
        # resend the join, then a leave. Router sends a group+source
        # specific query containing both sources
        #
        self.send(self.pg0, p_j)

        self.assertTrue(wait_for_igmp_event(self, 1, self.pg0,
                                            "239.1.1.1", "10.1.1.1", 1))
        self.assertTrue(wait_for_igmp_event(self, 1, self.pg0,
                                            "239.1.1.1", "10.1.1.2", 1))
        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertEqual(len(dump), 2)

        self.send(self.pg0, p_l)
        capture = self.pg0.get_capture(1, timeout=3)
        self.verify_group_query(capture[0], "239.1.1.1",
                                ["10.1.1.1", "10.1.1.2"])

        #
        # the group specific query drops the timeout to leave (=1) seconds
        #
        self.assertTrue(wait_for_igmp_event(self, 2, self.pg0,
                                            "239.1.1.1", "10.1.1.1", 0))
        self.assertTrue(wait_for_igmp_event(self, 1, self.pg0,
                                            "239.1.1.1", "10.1.1.2", 0))
        self.assertFalse(self.vapi.igmp_dump())
        self.assertFalse(self.vapi.igmp_dump())

        #
        # a TO_EX({}) / IN_EX({}) is treated like a (*,G) join
        #
        p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
               IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1,
                  options=[IPOption(copy_flag=1, optclass="control",
                                    option="router_alert")]) /
               IGMPv3(type="Version 3 Membership Report") /
               IGMPv3mr(numgrp=1) /
               IGMPv3gr(rtype="Change To Exclude Mode", maddr="239.1.1.2"))

        self.send(self.pg0, p_j)

        self.assertTrue(wait_for_igmp_event(self, 1, self.pg0,
                                            "239.1.1.2", "0.0.0.0", 1))

        p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
               IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1,
                  options=[IPOption(copy_flag=1, optclass="control",
                                    option="router_alert")]) /
               IGMPv3(type="Version 3 Membership Report") /
               IGMPv3mr(numgrp=1) /
               IGMPv3gr(rtype="Mode Is Exclude", maddr="239.1.1.3"))

        self.send(self.pg0, p_j)

        self.assertTrue(wait_for_igmp_event(self, 1, self.pg0,
                                            "239.1.1.3", "0.0.0.0", 1))

        #
        # A 'allow sources' for {} should be ignored as it should
        # never be sent.
        #
        p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
               IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1,
                  options=[IPOption(copy_flag=1, optclass="control",
                                    option="router_alert")]) /
               IGMPv3(type="Version 3 Membership Report") /
               IGMPv3mr(numgrp=1) /
               IGMPv3gr(rtype="Allow New Sources", maddr="239.1.1.4"))

        self.send(self.pg0, p_j)

        dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
        self.assertTrue(find_igmp_state(dump, self.pg0,
                                        "239.1.1.2", "0.0.0.0"))
        self.assertTrue(find_igmp_state(dump, self.pg0,
                                        "239.1.1.3", "0.0.0.0"))
        self.assertFalse(find_igmp_state(dump, self.pg0,
                                         "239.1.1.4", "0.0.0.0"))

        #
        # a TO_IN({}) and IS_IN({}) are treated like a (*,G) leave
        #
        self.vapi.cli("set logging class igmp level debug")
        p_l = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
               IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1,
                  options=[IPOption(copy_flag=1, optclass="control",
                                    option="router_alert")]) /
               IGMPv3(type="Version 3 Membership Report") /
               IGMPv3mr(numgrp=1) /
               IGMPv3gr(rtype="Change To Include Mode", maddr="239.1.1.2"))

        self.send(self.pg0, p_l)
        self.assertTrue(wait_for_igmp_event(self, 2, self.pg0,
                                            "239.1.1.2", "0.0.0.0", 0))

        p_l = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
               IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1,
                  options=[IPOption(copy_flag=1, optclass="control",
                                    option="router_alert")]) /
               IGMPv3(type="Version 3 Membership Report") /
               IGMPv3mr(numgrp=1) /
               IGMPv3gr(rtype="Mode Is Include", maddr="239.1.1.3"))

        self.send(self.pg0, p_l)

        self.assertTrue(wait_for_igmp_event(self, 2, self.pg0,
                                            "239.1.1.3", "0.0.0.0", 0))
        self.assertFalse(self.vapi.igmp_dump(self.pg0.sw_if_index))

        #
        # disable router config
        #
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index,
                                      0,
                                      IGMP_MODE.ROUTER)

    def _create_igmpv3_pck(self, itf, rtype, maddr, srcaddrs):
        p = (Ether(dst=itf.local_mac, src=itf.remote_mac) /
             IP(src=itf.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1,
                options=[IPOption(copy_flag=1, optclass="control",
                                  option="router_alert")]) /
             IGMPv3(type="Version 3 Membership Report") /
             IGMPv3mr(numgrp=1) /
             IGMPv3gr(rtype=rtype,
                      maddr=maddr, srcaddrs=srcaddrs))
        return p

    def test_igmp_proxy_device(self):
        """ IGMP proxy device """
        self.pg2.admin_down()
        self.pg2.unconfig_ip4()
        self.pg2.set_table_ip4(0)
        self.pg2.config_ip4()
        self.pg2.admin_up()

        self.vapi.cli('test igmp timers query 10 src 3 leave 1')

        # enable IGMP
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 1,
                                      IGMP_MODE.ROUTER)
        self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 1,
                                      IGMP_MODE.ROUTER)

        # create IGMP proxy device
        self.vapi.igmp_proxy_device_add_del(0, self.pg0.sw_if_index, 1)
        self.vapi.igmp_proxy_device_add_del_interface(0,
                                                      self.pg1.sw_if_index, 1)
        self.vapi.igmp_proxy_device_add_del_interface(0,
                                                      self.pg2.sw_if_index, 1)

        # send join on pg1. join should be proxied by pg0
        p_j = self._create_igmpv3_pck(self.pg1, "Allow New Sources",
                                      "239.1.1.1", ["10.1.1.1", "10.1.1.2"])
        self.send(self.pg1, p_j)

        capture = self.pg0.get_capture(1, timeout=1)
        self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1",
                           ["10.1.1.1", "10.1.1.2"]), "Allow New Sources")])
        self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))

        # send join on pg2. join should be proxied by pg0.
        # the group should contain only 10.1.1.3 as
        # 10.1.1.1 was already reported
        p_j = self._create_igmpv3_pck(self.pg2, "Allow New Sources",
                                      "239.1.1.1", ["10.1.1.1", "10.1.1.3"])
        self.send(self.pg2, p_j)

        capture = self.pg0.get_capture(1, timeout=1)
        self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1",
                           ["10.1.1.3"]), "Allow New Sources")])
        self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))

        # send leave on pg2. leave for 10.1.1.3 should be proxyed
        # as pg2 was the only interface interested in 10.1.1.3
        p_l = self._create_igmpv3_pck(self.pg2, "Block Old Sources",
                                      "239.1.1.1", ["10.1.1.3"])
        self.send(self.pg2, p_l)

        capture = self.pg0.get_capture(1, timeout=2)
        self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1",
                           ["10.1.1.3"]), "Block Old Sources")])
        self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))

        # disable igmp on pg1 (also removes interface from proxy device)
        # proxy leave for 10.1.1.2. pg2 is still interested in 10.1.1.1
        self.pg_enable_capture(self.pg_interfaces)
        self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 0,
                                      IGMP_MODE.ROUTER)

        capture = self.pg0.get_capture(1, timeout=1)
        self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1",
                           ["10.1.1.2"]), "Block Old Sources")])
        self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))

        # disable IGMP on pg0 and pg1.
        #   disabling IGMP on pg0 (proxy device upstream interface)
        #   removes this proxy device
        self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST)
        self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 0,
                                      IGMP_MODE.ROUTER)
        self.assertFalse(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))
예제 #17
0
파일: test_gre.py 프로젝트: chrisy/vpp
class TestGRE(VppTestCase):
    """ GRE Test Case """

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

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

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

        # create 3 pg interfaces - set one in a non-default table.
        self.create_pg_interfaces(range(3))

        self.tbl = VppIpTable(self, 1)
        self.tbl.add_vpp_config()
        self.pg1.set_table_ip4(1)

        for i in self.pg_interfaces:
            i.admin_up()

        self.pg0.config_ip4()
        self.pg0.resolve_arp()
        self.pg1.config_ip4()
        self.pg1.resolve_arp()
        self.pg2.config_ip6()
        self.pg2.resolve_ndp()

    def tearDown(self):
        for i in self.pg_interfaces:
            i.unconfig_ip4()
            i.unconfig_ip6()
            i.admin_down()
        self.pg1.set_table_ip4(0)
        super(TestGRE, self).tearDown()

    def create_stream_ip4(self, src_if, src_ip, dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=src_ip, dst=dst_ip) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_stream_ip6(self, src_if, src_ip, dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IPv6(src=src_ip, dst=dst_ip) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_4o4(self, src_if,
                                 tunnel_src, tunnel_dst,
                                 src_ip, dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=tunnel_src, dst=tunnel_dst) /
                 GRE() /
                 IP(src=src_ip, dst=dst_ip) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_6o4(self, src_if,
                                 tunnel_src, tunnel_dst,
                                 src_ip, dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=tunnel_src, dst=tunnel_dst) /
                 GRE() /
                 IPv6(src=src_ip, dst=dst_ip) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_6o6(self, src_if,
                                 tunnel_src, tunnel_dst,
                                 src_ip, dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IPv6(src=tunnel_src, dst=tunnel_dst) /
                 GRE() /
                 IPv6(src=src_ip, dst=dst_ip) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_l2o4(self, src_if,
                                  tunnel_src, tunnel_dst):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=tunnel_src, dst=tunnel_dst) /
                 GRE() /
                 Ether(dst=RandMAC('*:*:*:*:*:*'),
                       src=RandMAC('*:*:*:*:*:*')) /
                 IP(src=scapy.compat.raw(RandIP()),
                    dst=scapy.compat.raw(RandIP())) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_vlano4(self, src_if,
                                    tunnel_src, tunnel_dst, vlan):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=tunnel_src, dst=tunnel_dst) /
                 GRE() /
                 Ether(dst=RandMAC('*:*:*:*:*:*'),
                       src=RandMAC('*:*:*:*:*:*')) /
                 Dot1Q(vlan=vlan) /
                 IP(src=scapy.compat.raw(RandIP()),
                    dst=scapy.compat.raw(RandIP())) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def verify_tunneled_4o4(self, src_if, capture, sent,
                            tunnel_src, tunnel_dst):

        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = rx[GRE]
                rx_ip = rx_gre[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # IP processing post pop has decremented the TTL
                self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_6o6(self, src_if, capture, sent,
                            tunnel_src, tunnel_dst):

        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IPv6]
                rx_ip = rx[IPv6]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = GRE(scapy.compat.raw(rx_ip[IPv6].payload))
                rx_ip = rx_gre[IPv6]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_4o6(self, src_if, capture, sent,
                            tunnel_src, tunnel_dst):

        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                rx_ip = rx[IPv6]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = GRE(scapy.compat.raw(rx_ip[IPv6].payload))
                tx_ip = tx[IP]
                rx_ip = rx_gre[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_6o4(self, src_if, capture, sent,
                            tunnel_src, tunnel_dst):

        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                rx_ip = rx[IP]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = GRE(scapy.compat.raw(rx_ip[IP].payload))
                rx_ip = rx_gre[IPv6]
                tx_ip = tx[IPv6]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_l2o4(self, src_if, capture, sent,
                             tunnel_src, tunnel_dst):
        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = rx[GRE]
                rx_l2 = rx_gre[Ether]
                rx_ip = rx_l2[IP]
                tx_gre = tx[GRE]
                tx_l2 = tx_gre[Ether]
                tx_ip = tx_l2[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # bridged, not L3 forwarded, so no TTL decrement
                self.assertEqual(rx_ip.ttl, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_vlano4(self, src_if, capture, sent,
                               tunnel_src, tunnel_dst, vlan):
        try:
            self.assertEqual(len(capture), len(sent))
        except:
            ppc("Unexpected packets captured:", capture)
            raise

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = rx[GRE]
                rx_l2 = rx_gre[Ether]
                rx_vlan = rx_l2[Dot1Q]
                rx_ip = rx_l2[IP]

                self.assertEqual(rx_vlan.vlan, vlan)

                tx_gre = tx[GRE]
                tx_l2 = tx_gre[Ether]
                tx_ip = tx_l2[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # bridged, not L3 forwarded, so no TTL decrement
                self.assertEqual(rx_ip.ttl, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_decapped_4o4(self, src_if, capture, sent):
        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]
                tx_gre = tx[GRE]
                tx_ip = tx_gre[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # IP processing post pop has decremented the TTL
                self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_decapped_6o4(self, src_if, capture, sent):
        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IPv6]
                tx_gre = tx[GRE]
                tx_ip = tx_gre[IPv6]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def test_gre(self):
        """ GRE IPv4 tunnel Tests """

        #
        # Create an L3 GRE tunnel.
        #  - set it admin up
        #  - assign an IP Addres
        #  - Add a route via the tunnel
        #
        gre_if = VppGreInterface(self,
                                 self.pg0.local_ip4,
                                 "1.1.1.2")
        gre_if.add_vpp_config()

        #
        # The double create (create the same tunnel twice) should fail,
        # and we should still be able to use the original
        #
        try:
            gre_if.add_vpp_config()
        except Exception:
            pass
        else:
            self.fail("Double GRE tunnel add does not fail")

        gre_if.admin_up()
        gre_if.config_ip4()

        route_via_tun = VppIpRoute(self, "4.4.4.4", 32,
                                   [VppRoutePath("0.0.0.0",
                                                 gre_if.sw_if_index)])

        route_via_tun.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - they are all dropped since the tunnel's destintation IP
        #    is unresolved - or resolves via the default route - which
        #    which is a drop.
        #
        tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")

        self.send_and_assert_no_replies(self.pg0, tx)

        #
        # Add a route that resolves the tunnel's destination
        #
        route_tun_dst = VppIpRoute(self, "1.1.1.2", 32,
                                   [VppRoutePath(self.pg0.remote_ip4,
                                                 self.pg0.sw_if_index)])
        route_tun_dst.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - packets are GRE encapped
        #
        tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_tunneled_4o4(self.pg0, rx, tx,
                                 self.pg0.local_ip4, "1.1.1.2")

        #
        # Send tunneled packets that match the created tunnel and
        # are decapped and forwarded
        #
        tx = self.create_tunnel_stream_4o4(self.pg0,
                                           "1.1.1.2",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_decapped_4o4(self.pg0, rx, tx)

        #
        # Send tunneled packets that do not match the tunnel's src
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_4o4(self.pg0,
                                           "1.1.1.3",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        self.send_and_assert_no_replies(
            self.pg0, tx,
            remark="GRE packets forwarded despite no SRC address match")

        #
        # Configure IPv6 on the PG interface so we can route IPv6
        # packets
        #
        self.pg0.config_ip6()
        self.pg0.resolve_ndp()

        #
        # Send IPv6 tunnel encapslated packets
        #  - dropped since IPv6 is not enabled on the tunnel
        #
        tx = self.create_tunnel_stream_6o4(self.pg0,
                                           "1.1.1.2",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip6,
                                           self.pg0.remote_ip6)
        self.send_and_assert_no_replies(self.pg0, tx,
                                        "IPv6 GRE packets forwarded "
                                        "despite IPv6 not enabled on tunnel")

        #
        # Enable IPv6 on the tunnel
        #
        gre_if.config_ip6()

        #
        # Send IPv6 tunnel encapslated packets
        #  - forwarded since IPv6 is enabled on the tunnel
        #
        tx = self.create_tunnel_stream_6o4(self.pg0,
                                           "1.1.1.2",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip6,
                                           self.pg0.remote_ip6)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_decapped_6o4(self.pg0, rx, tx)

        #
        # Send v6 packets for v4 encap
        #
        route6_via_tun = VppIpRoute(
            self, "2001::1", 128,
            [VppRoutePath("::",
                          gre_if.sw_if_index,
                          proto=DpoProto.DPO_PROTO_IP6)],
            is_ip6=1)
        route6_via_tun.add_vpp_config()

        tx = self.create_stream_ip6(self.pg0, "2001::2", "2001::1")
        rx = self.send_and_expect(self.pg0, tx, self.pg0)

        self.verify_tunneled_6o4(self.pg0, rx, tx,
                                 self.pg0.local_ip4, "1.1.1.2")

        #
        # test case cleanup
        #
        route_tun_dst.remove_vpp_config()
        route_via_tun.remove_vpp_config()
        route6_via_tun.remove_vpp_config()
        gre_if.remove_vpp_config()

        self.pg0.unconfig_ip6()

    def test_gre6(self):
        """ GRE IPv6 tunnel Tests """

        self.pg1.config_ip6()
        self.pg1.resolve_ndp()

        #
        # Create an L3 GRE tunnel.
        #  - set it admin up
        #  - assign an IP Address
        #  - Add a route via the tunnel
        #
        gre_if = VppGreInterface(self,
                                 self.pg2.local_ip6,
                                 "1002::1")
        gre_if.add_vpp_config()
        gre_if.admin_up()
        gre_if.config_ip6()

        route_via_tun = VppIpRoute(
            self, "4004::1", 128,
            [VppRoutePath("0::0",
                          gre_if.sw_if_index,
                          proto=DpoProto.DPO_PROTO_IP6)],
            is_ip6=1)

        route_via_tun.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - they are all dropped since the tunnel's destintation IP
        #    is unresolved - or resolves via the default route - which
        #    which is a drop.
        #
        tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
        self.send_and_assert_no_replies(
            self.pg2, tx,
            "GRE packets forwarded without DIP resolved")

        #
        # Add a route that resolves the tunnel's destination
        #
        route_tun_dst = VppIpRoute(
            self, "1002::1", 128,
            [VppRoutePath(self.pg2.remote_ip6,
                          self.pg2.sw_if_index,
                          proto=DpoProto.DPO_PROTO_IP6)],
            is_ip6=1)
        route_tun_dst.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - packets are GRE encapped
        #
        tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
        rx = self.send_and_expect(self.pg2, tx, self.pg2)
        self.verify_tunneled_6o6(self.pg2, rx, tx,
                                 self.pg2.local_ip6, "1002::1")

        #
        # Test decap. decapped packets go out pg1
        #
        tx = self.create_tunnel_stream_6o6(self.pg2,
                                           "1002::1",
                                           self.pg2.local_ip6,
                                           "2001::1",
                                           self.pg1.remote_ip6)
        rx = self.send_and_expect(self.pg2, tx, self.pg1)

        #
        # RX'd packet is UDP over IPv6, test the GRE header is gone.
        #
        self.assertFalse(rx[0].haslayer(GRE))
        self.assertEqual(rx[0][IPv6].dst, self.pg1.remote_ip6)

        #
        # Send v4 over v6
        #
        route4_via_tun = VppIpRoute(self, "1.1.1.1", 32,
                                    [VppRoutePath("0.0.0.0",
                                                  gre_if.sw_if_index)])
        route4_via_tun.add_vpp_config()

        tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "1.1.1.1")
        rx = self.send_and_expect(self.pg0, tx, self.pg2)

        self.verify_tunneled_4o6(self.pg0, rx, tx,
                                 self.pg2.local_ip6, "1002::1")

        #
        # test case cleanup
        #
        route_tun_dst.remove_vpp_config()
        route_via_tun.remove_vpp_config()
        route4_via_tun.remove_vpp_config()
        gre_if.remove_vpp_config()

        self.pg2.unconfig_ip6()
        self.pg1.unconfig_ip6()

    def test_gre_vrf(self):
        """ GRE tunnel VRF Tests """

        #
        # Create an L3 GRE tunnel whose destination is in the non-default
        # table. The underlay is thus non-default - the overlay is still
        # the default.
        #  - set it admin up
        #  - assign an IP Addres
        #
        gre_if = VppGreInterface(self, self.pg1.local_ip4,
                                 "2.2.2.2",
                                 outer_fib_id=1)
        gre_if.add_vpp_config()
        gre_if.admin_up()
        gre_if.config_ip4()

        #
        # Add a route via the tunnel - in the overlay
        #
        route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
                                   [VppRoutePath("0.0.0.0",
                                                 gre_if.sw_if_index)])
        route_via_tun.add_vpp_config()

        #
        # Add a route that resolves the tunnel's destination - in the
        # underlay table
        #
        route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
                                   paths=[VppRoutePath(self.pg1.remote_ip4,
                                                       self.pg1.sw_if_index)])
        route_tun_dst.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        # packets are sent in on pg0 which is in the default table
        #  - packets are GRE encapped
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
        rx = self.send_and_expect(self.pg0, tx, self.pg1)
        self.verify_tunneled_4o4(self.pg1, rx, tx,
                                 self.pg1.local_ip4, "2.2.2.2")

        #
        # Send tunneled packets that match the created tunnel and
        # are decapped and forwarded. This tests the decap lookup
        # does not happen in the encap table
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_4o4(self.pg1,
                                           "2.2.2.2",
                                           self.pg1.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        rx = self.send_and_expect(self.pg1, tx, self.pg0)
        self.verify_decapped_4o4(self.pg0, rx, tx)

        #
        # Send tunneled packets that match the created tunnel
        # but arrive on an interface that is not in the tunnel's
        # encap VRF, these are dropped.
        # IP enable the interface so they aren't dropped due to
        # IP not being enabled.
        #
        self.pg2.config_ip4()
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_4o4(self.pg2,
                                           "2.2.2.2",
                                           self.pg1.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        rx = self.send_and_assert_no_replies(
            self.pg2, tx,
            "GRE decap packets in wrong VRF")

        self.pg2.unconfig_ip4()

        #
        # test case cleanup
        #
        route_tun_dst.remove_vpp_config()
        route_via_tun.remove_vpp_config()
        gre_if.remove_vpp_config()

    def test_gre_l2(self):
        """ GRE tunnel L2 Tests """

        #
        # Add routes to resolve the tunnel destinations
        #
        route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
                                    [VppRoutePath(self.pg0.remote_ip4,
                                                  self.pg0.sw_if_index)])
        route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
                                    [VppRoutePath(self.pg0.remote_ip4,
                                                  self.pg0.sw_if_index)])

        route_tun1_dst.add_vpp_config()
        route_tun2_dst.add_vpp_config()

        #
        # Create 2 L2 GRE tunnels and x-connect them
        #
        gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
                                  "2.2.2.2",
                                  type=(VppEnum.vl_api_gre_tunnel_type_t.
                                        GRE_API_TUNNEL_TYPE_TEB))
        gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
                                  "2.2.2.3",
                                  type=(VppEnum.vl_api_gre_tunnel_type_t.
                                        GRE_API_TUNNEL_TYPE_TEB))
        gre_if1.add_vpp_config()
        gre_if2.add_vpp_config()

        gre_if1.admin_up()
        gre_if2.admin_up()

        self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
                                               gre_if2.sw_if_index,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
                                               gre_if1.sw_if_index,
                                               enable=1)

        #
        # Send in tunnel encapped L2. expect out tunnel encapped L2
        # in both directions
        #
        tx = self.create_tunnel_stream_l2o4(self.pg0,
                                            "2.2.2.2",
                                            self.pg0.local_ip4)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_tunneled_l2o4(self.pg0, rx, tx,
                                  self.pg0.local_ip4,
                                  "2.2.2.3")

        tx = self.create_tunnel_stream_l2o4(self.pg0,
                                            "2.2.2.3",
                                            self.pg0.local_ip4)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_tunneled_l2o4(self.pg0, rx, tx,
                                  self.pg0.local_ip4,
                                  "2.2.2.2")

        self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
                                               gre_if2.sw_if_index,
                                               enable=0)
        self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
                                               gre_if1.sw_if_index,
                                               enable=0)

        #
        # Create a VLAN sub-interfaces on the GRE TEB interfaces
        # then x-connect them
        #
        gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
        gre_if_12 = VppDot1QSubint(self, gre_if2, 12)

        # gre_if_11.add_vpp_config()
        # gre_if_12.add_vpp_config()

        gre_if_11.admin_up()
        gre_if_12.admin_up()

        self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
                                               gre_if_12.sw_if_index,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
                                               gre_if_11.sw_if_index,
                                               enable=1)

        #
        # Configure both to pop thier respective VLAN tags,
        # so that during the x-coonect they will subsequently push
        #
        self.vapi.l2_interface_vlan_tag_rewrite(
            sw_if_index=gre_if_12.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
            push_dot1q=12)
        self.vapi.l2_interface_vlan_tag_rewrite(
            sw_if_index=gre_if_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
            push_dot1q=11)

        #
        # Send traffic in both directiond - expect the VLAN tags to
        # be swapped.
        #
        tx = self.create_tunnel_stream_vlano4(self.pg0,
                                              "2.2.2.2",
                                              self.pg0.local_ip4,
                                              11)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_tunneled_vlano4(self.pg0, rx, tx,
                                    self.pg0.local_ip4,
                                    "2.2.2.3",
                                    12)

        tx = self.create_tunnel_stream_vlano4(self.pg0,
                                              "2.2.2.3",
                                              self.pg0.local_ip4,
                                              12)
        rx = self.send_and_expect(self.pg0, tx, self.pg0)
        self.verify_tunneled_vlano4(self.pg0, rx, tx,
                                    self.pg0.local_ip4,
                                    "2.2.2.2",
                                    11)

        #
        # Cleanup Test resources
        #
        gre_if_11.remove_vpp_config()
        gre_if_12.remove_vpp_config()
        gre_if1.remove_vpp_config()
        gre_if2.remove_vpp_config()
        route_tun1_dst.add_vpp_config()
        route_tun2_dst.add_vpp_config()

    def test_gre_loop(self):
        """ GRE tunnel loop Tests """

        #
        # Create an L3 GRE tunnel.
        #  - set it admin up
        #  - assign an IP Addres
        #
        gre_if = VppGreInterface(self,
                                 self.pg0.local_ip4,
                                 "1.1.1.2")
        gre_if.add_vpp_config()
        gre_if.admin_up()
        gre_if.config_ip4()

        #
        # add a route to the tunnel's destination that points
        # through the tunnel, hence forming a loop in the forwarding
        # graph
        #
        route_dst = VppIpRoute(self, "1.1.1.2", 32,
                               [VppRoutePath("0.0.0.0",
                                             gre_if.sw_if_index)])
        route_dst.add_vpp_config()

        #
        # packets to the tunnels destination should be dropped
        #
        tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "1.1.1.2")
        self.send_and_assert_no_replies(self.pg2, tx)

        self.logger.info(self.vapi.ppcli("sh adj 7"))

        #
        # break the loop
        #
        route_dst.modify([VppRoutePath(self.pg1.remote_ip4,
                                       self.pg1.sw_if_index)])
        route_dst.add_vpp_config()

        rx = self.send_and_expect(self.pg0, tx, self.pg1)

        #
        # a good route throught the tunnel to check it restacked
        #
        route_via_tun_2 = VppIpRoute(self, "2.2.2.2", 32,
                                     [VppRoutePath("0.0.0.0",
                                                   gre_if.sw_if_index)])
        route_via_tun_2.add_vpp_config()

        tx = self.create_stream_ip4(self.pg0, "2.2.2.3", "2.2.2.2")
        rx = self.send_and_expect(self.pg0, tx, self.pg1)
        self.verify_tunneled_4o4(self.pg1, rx, tx,
                                 self.pg0.local_ip4, "1.1.1.2")

        #
        # cleanup
        #
        route_via_tun_2.remove_vpp_config()
        gre_if.remove_vpp_config()
예제 #18
0
파일: test_ipip.py 프로젝트: zzqcn/vpp
    def test_mipip4(self):
        """ p2mp IPv4 tunnel Tests """

        for itf in self.pg_interfaces[:2]:
            #
            # one underlay nh for each overlay/tunnel peer
            #
            itf.generate_remote_hosts(4)
            itf.configure_ipv4_neighbors()

            #
            # Create an p2mo IPIP tunnel.
            #  - set it admin up
            #  - assign an IP Addres
            #  - Add a route via the tunnel
            #
            ipip_if = VppIpIpTunInterface(
                self,
                itf,
                itf.local_ip4,
                "0.0.0.0",
                mode=(VppEnum.vl_api_tunnel_mode_t.TUNNEL_API_MODE_MP))
            ipip_if.add_vpp_config()
            ipip_if.admin_up()
            ipip_if.config_ip4()
            ipip_if.generate_remote_hosts(4)

            self.logger.info(self.vapi.cli("sh adj"))
            self.logger.info(self.vapi.cli("sh ip fib"))

            #
            # ensure we don't match to the tunnel if the source address
            # is all zeros
            #
            # tx = self.create_tunnel_stream_4o4(self.pg0,
            #                                    "0.0.0.0",
            #                                    itf.local_ip4,
            #                                    self.pg0.local_ip4,
            #                                    self.pg0.remote_ip4)
            # self.send_and_assert_no_replies(self.pg0, tx)

            #
            # for-each peer
            #
            for ii in range(1, 4):
                route_addr = "4.4.4.%d" % ii

                #
                # route traffic via the peer
                #
                route_via_tun = VppIpRoute(self, route_addr, 32, [
                    VppRoutePath(ipip_if._remote_hosts[ii].ip4,
                                 ipip_if.sw_if_index)
                ])
                route_via_tun.add_vpp_config()

                #
                # Add a TEIB entry resolves the peer
                #
                teib = VppTeib(self, ipip_if, ipip_if._remote_hosts[ii].ip4,
                               itf._remote_hosts[ii].ip4)
                teib.add_vpp_config()
                self.logger.info(
                    self.vapi.cli("sh adj nbr ipip0 %s" %
                                  ipip_if._remote_hosts[ii].ip4))

                #
                # Send a packet stream that is routed into the tunnel
                #  - packets are IPIP encapped
                #
                inner = (IP(dst=route_addr, src="5.5.5.5") /
                         UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100))
                tx_e = [
                    (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                     inner) for x in range(63)
                ]

                rxs = self.send_and_expect(self.pg0, tx_e, itf)

                for rx in rxs:
                    self.assertEqual(rx[IP].src, itf.local_ip4)
                    self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)

                tx_i = [
                    (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                     IP(src=itf._remote_hosts[ii].ip4, dst=itf.local_ip4) /
                     IP(src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) /
                     UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100))
                    for x in range(63)
                ]

                self.logger.info(self.vapi.cli("sh ipip tunnel-hash"))
                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)

                #
                # delete and re-add the TEIB
                #
                teib.remove_vpp_config()
                self.send_and_assert_no_replies(self.pg0, tx_e)
                self.send_and_assert_no_replies(self.pg0, tx_i)

                teib.add_vpp_config()
                rx = self.send_and_expect(self.pg0, tx_e, itf)
                for rx in rxs:
                    self.assertEqual(rx[IP].src, itf.local_ip4)
                    self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)
                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)

                #
                # we can also send to the peer's address
                #
                inner = (IP(dst=teib.peer, src="5.5.5.5") /
                         UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100))
                tx_e = [
                    (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                     inner) for x in range(63)
                ]

                rxs = self.send_and_expect(self.pg0, tx_e, itf)

            #
            # with all of the peers in place, swap the ip-table of
            # the ipip interface
            #
            table = VppIpTable(self, 2)
            table.add_vpp_config()

            ipip_if.unconfig_ip4()
            ipip_if.set_table_ip4(self.table.table_id)
            ipip_if.config_ip4()

            #
            # we should still be able to reach the peers from the new table
            #
            inner = (IP(dst=teib.peer, src="5.5.5.5") /
                     UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100))
            tx_e = [(Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                     inner) for x in range(63)]

            rxs = self.send_and_expect(self.pg2, tx_e, itf)

            ipip_if.admin_down()
            ipip_if.unconfig_ip4()
            ipip_if.set_table_ip4(0)
예제 #19
0
파일: test_ipip.py 프로젝트: zzqcn/vpp
class TestIPIP(VppTestCase):
    """ IPIP Test Case """
    @classmethod
    def setUpClass(cls):
        super(TestIPIP, cls).setUpClass()
        cls.create_pg_interfaces(range(3))
        cls.interfaces = list(cls.pg_interfaces)

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

    def setUp(self):
        super(TestIPIP, self).setUp()
        self.table = VppIpTable(self, 1, register=False)
        self.table.add_vpp_config()

        for i in self.interfaces:
            i.admin_up()

        self.pg2.set_table_ip4(self.table.table_id)
        for i in self.interfaces:
            i.config_ip4()
            i.config_ip6()
            i.disable_ipv6_ra()
            i.resolve_arp()
            i.resolve_ndp()

    def tearDown(self):
        super(TestIPIP, self).tearDown()
        if not self.vpp_dead:
            for i in self.pg_interfaces:
                i.unconfig_ip4()
                i.unconfig_ip6()
                i.set_table_ip4(0)
                i.admin_down()

        self.table.remove_vpp_config()

    def validate(self, rx, expected):
        self.assertEqual(rx, expected.__class__(expected))

    def generate_ip4_frags(self, payload_length, fragment_size):
        p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
        p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
        p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
        outer_ip4 = (p_ether / IP(
            src=self.pg1.remote_ip4, id=RandShort(), dst=self.pg0.local_ip4) /
                     p_ip4 / p_payload)
        frags = fragment(outer_ip4, fragment_size)
        p4_reply = (p_ip4 / p_payload)
        p4_reply.ttl -= 1
        return frags, p4_reply

    def verify_ip4ip4_encaps(self, a, p_ip4s, p_ip4_encaps):
        for i, p_ip4 in enumerate(p_ip4s):
            p_ip4.dst = a
            p4 = (self.p_ether / p_ip4 / self.p_payload)
            p_ip4_inner = p_ip4
            p_ip4_inner.ttl -= 1
            p4_reply = (p_ip4_encaps[i] / p_ip4_inner / self.p_payload)
            p4_reply.ttl -= 1
            p4_reply.id = 0
            rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
            for p in rx:
                self.validate(p[1], p4_reply)
                self.assert_packet_checksums_valid(p)

    def verify_ip6ip4_encaps(self, a, p_ip6s, p_ip4_encaps):
        for i, p_ip6 in enumerate(p_ip6s):
            p_ip6.dst = a
            p6 = (self.p_ether / p_ip6 / self.p_payload)
            p_inner_ip6 = p_ip6
            p_inner_ip6.hlim -= 1
            p6_reply = (p_ip4_encaps[i] / p_inner_ip6 / self.p_payload)
            p6_reply.ttl -= 1
            rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
            for p in rx:
                self.validate(p[1], p6_reply)
                self.assert_packet_checksums_valid(p)

    def test_ipip4(self):
        """ ip{v4,v6} over ip4 test """

        self.pg1.generate_remote_hosts(5)
        self.pg1.configure_ipv4_neighbors()
        e = VppEnum.vl_api_tunnel_encap_decap_flags_t
        d = VppEnum.vl_api_ip_dscp_t
        self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
        self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)

        # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
        # are for the ECN.
        dscp = d.IP_API_DSCP_AF31 << 2
        ecn = 3
        dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn

        # IPv4 transport that copies the DCSP from the payload
        tun_dscp = VppIpIpTunInterface(
            self,
            self.pg0,
            self.pg0.local_ip4,
            self.pg1.remote_hosts[0].ip4,
            flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
        tun_dscp.add_vpp_config()
        # IPv4 transport that copies the DCSP and ECN from the payload
        tun_dscp_ecn = VppIpIpTunInterface(
            self,
            self.pg0,
            self.pg0.local_ip4,
            self.pg1.remote_hosts[1].ip4,
            flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP
                   | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))
        tun_dscp_ecn.add_vpp_config()
        # IPv4 transport that copies the ECN from the payload and sets the
        # DF bit on encap. copies the ECN on decap
        tun_ecn = VppIpIpTunInterface(
            self,
            self.pg0,
            self.pg0.local_ip4,
            self.pg1.remote_hosts[2].ip4,
            flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN
                   | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF
                   | e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN))
        tun_ecn.add_vpp_config()
        # IPv4 transport that sets a fixed DSCP in the encap and copies
        # the DF bit
        tun = VppIpIpTunInterface(
            self,
            self.pg0,
            self.pg0.local_ip4,
            self.pg1.remote_hosts[3].ip4,
            dscp=d.IP_API_DSCP_AF11,
            flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
        tun.add_vpp_config()

        # array of all the tunnels
        tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]

        # addresses for prefixes routed via each tunnel
        a4s = ["" for i in range(len(tuns))]
        a6s = ["" for i in range(len(tuns))]

        # IP headers with each combination of DSCp/ECN tested
        p_ip6s = [
            IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
            IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
            IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
            IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)
        ]
        p_ip4s = [
            IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
            IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
            IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
            IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)
        ]

        # Configure each tunnel
        for i, t in enumerate(tuns):
            # Set interface up and enable IP on it
            self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
            self.vapi.sw_interface_set_unnumbered(
                sw_if_index=self.pg0.sw_if_index,
                unnumbered_sw_if_index=t.sw_if_index)

            # prefix for route / destination address for packets
            a4s[i] = "130.67.%d.0" % i
            a6s[i] = "dead:%d::" % i

            # Add IPv4 and IPv6 routes via tunnel interface
            ip4_via_tunnel = VppIpRoute(self, a4s[i], 24, [
                VppRoutePath("0.0.0.0",
                             t.sw_if_index,
                             proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
            ])
            ip4_via_tunnel.add_vpp_config()

            ip6_via_tunnel = VppIpRoute(self, a6s[i], 64, [
                VppRoutePath("::",
                             t.sw_if_index,
                             proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
            ])
            ip6_via_tunnel.add_vpp_config()

        #
        # Encapsulation
        #

        # tun_dscp copies only the dscp
        # expected TC values are thus only the DCSP value is present from the
        # inner
        exp_tcs = [dscp, dscp, 0, 0xfc]
        p_ip44_encaps = [
            IP(src=self.pg0.local_ip4, dst=tun_dscp.dst, tos=tc)
            for tc in exp_tcs
        ]
        p_ip64_encaps = [
            IP(src=self.pg0.local_ip4,
               dst=tun_dscp.dst,
               proto='ipv6',
               id=0,
               tos=tc) for tc in exp_tcs
        ]

        # IPv4 in to IPv4 tunnel
        self.verify_ip4ip4_encaps(a4s[0], p_ip4s, p_ip44_encaps)
        # IPv6 in to IPv4 tunnel
        self.verify_ip6ip4_encaps(a6s[0], p_ip6s, p_ip64_encaps)

        # tun_dscp_ecn copies the dscp and the ecn
        exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
        p_ip44_encaps = [
            IP(src=self.pg0.local_ip4, dst=tun_dscp_ecn.dst, tos=tc)
            for tc in exp_tcs
        ]
        p_ip64_encaps = [
            IP(src=self.pg0.local_ip4,
               dst=tun_dscp_ecn.dst,
               proto='ipv6',
               id=0,
               tos=tc) for tc in exp_tcs
        ]

        self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps)
        self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps)

        # tun_ecn copies only the ecn and always sets DF
        exp_tcs = [0, ecn, ecn, ecn]
        p_ip44_encaps = [
            IP(src=self.pg0.local_ip4, dst=tun_ecn.dst, flags='DF', tos=tc)
            for tc in exp_tcs
        ]
        p_ip64_encaps = [
            IP(src=self.pg0.local_ip4,
               dst=tun_ecn.dst,
               flags='DF',
               proto='ipv6',
               id=0,
               tos=tc) for tc in exp_tcs
        ]

        self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps)
        self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps)

        # tun sets a fixed dscp and copies DF
        fixed_dscp = tun.dscp << 2
        flags = ['DF', 0, 0, 0]
        p_ip44_encaps = [
            IP(src=self.pg0.local_ip4, dst=tun.dst, flags=f, tos=fixed_dscp)
            for f in flags
        ]
        p_ip64_encaps = [
            IP(src=self.pg0.local_ip4,
               dst=tun.dst,
               proto='ipv6',
               id=0,
               tos=fixed_dscp) for i in range(len(p_ip4s))
        ]

        self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps)
        self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps)

        #
        # Decapsulation
        #
        n_packets_decapped = 0
        self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)

        # IPv4 tunnel to IPv4
        tcs = [0, dscp, dscp_ecn, ecn]

        # one overlay packet and all combinations of its encap
        p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
        p_ip4_encaps = [
            IP(src=tun.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs
        ]

        # for each encap tun will produce the same inner packet because it does
        # not copy up fields from the payload
        for p_ip4_encap in p_ip4_encaps:
            p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
            p4_reply = (p_ip4 / self.p_payload)
            p4_reply.ttl -= 1
            rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
            n_packets_decapped += N_PACKETS
            for p in rx:
                self.validate(p[1], p4_reply)
                self.assert_packet_checksums_valid(p)

        err = self.statistics.get_err_counter(
            '/err/ipip4-input/packets decapsulated')
        self.assertEqual(err, n_packets_decapped)

        # tun_ecn copies the ECN bits from the encap to the inner
        p_ip4_encaps = [
            IP(src=tun_ecn.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs
        ]
        p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip4_encaps))]
        p_ip4_replys[2].tos = ecn
        p_ip4_replys[3].tos = ecn
        for i, p_ip4_encap in enumerate(p_ip4_encaps):
            p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
            p4_reply = (p_ip4_replys[i] / self.p_payload)
            p4_reply.ttl -= 1
            rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
            n_packets_decapped += N_PACKETS
            for p in rx:
                self.validate(p[1], p4_reply)
                self.assert_packet_checksums_valid(p)

        err = self.statistics.get_err_counter(
            '/err/ipip4-input/packets decapsulated')
        self.assertEqual(err, n_packets_decapped)

        # IPv4 tunnel to IPv6
        # for each encap tun will produce the same inner packet because it does
        # not copy up fields from the payload
        p_ip4_encaps = [
            IP(src=tun.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs
        ]
        p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
        for p_ip4_encap in p_ip4_encaps:
            p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload)
            p6_reply = (p_ip6 / self.p_payload)
            p6_reply.hlim = 63
            rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
            n_packets_decapped += N_PACKETS
            for p in rx:
                self.validate(p[1], p6_reply)
                self.assert_packet_checksums_valid(p)

        err = self.statistics.get_err_counter(
            '/err/ipip4-input/packets decapsulated')
        self.assertEqual(err, n_packets_decapped)

        # IPv4 tunnel to IPv6
        # tun_ecn copies the ECN bits from the encap to the inner
        p_ip4_encaps = [
            IP(src=tun_ecn.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs
        ]
        p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
        p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip4_encaps))]
        p_ip6_replys[2].tc = ecn
        p_ip6_replys[3].tc = ecn
        for i, p_ip4_encap in enumerate(p_ip4_encaps):
            p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload)
            p6_reply = (p_ip6_replys[i] / self.p_payload)
            p6_reply.hlim = 63
            rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
            n_packets_decapped += N_PACKETS
            for p in rx:
                self.validate(p[1], p6_reply)
                self.assert_packet_checksums_valid(p)

        err = self.statistics.get_err_counter(
            '/err/ipip4-input/packets decapsulated')
        self.assertEqual(err, n_packets_decapped)

        #
        # Fragmentation / Reassembly and Re-fragmentation
        #
        rv = self.vapi.ip_reassembly_enable_disable(
            sw_if_index=self.pg1.sw_if_index, enable_ip4=1)

        self.vapi.ip_reassembly_set(timeout_ms=1000,
                                    max_reassemblies=1000,
                                    max_reassembly_length=1000,
                                    expire_walk_interval_ms=10000,
                                    is_ip6=0)

        # Send lots of fragments, verify reassembled packet
        frags, p4_reply = self.generate_ip4_frags(3131, 1400)
        f = []
        for i in range(0, 1000):
            f.extend(frags)
        self.pg1.add_stream(f)
        self.pg_enable_capture()
        self.pg_start()
        rx = self.pg0.get_capture(1000)
        n_packets_decapped += 1000

        for p in rx:
            self.validate(p[1], p4_reply)

        err = self.statistics.get_err_counter(
            '/err/ipip4-input/packets decapsulated')
        self.assertEqual(err, n_packets_decapped)

        f = []
        r = []
        for i in range(1, 90):
            frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
            f.extend(frags)
            r.extend(p4_reply)
        self.pg_enable_capture()
        self.pg1.add_stream(f)
        self.pg_start()
        rx = self.pg0.get_capture(89)
        i = 0
        for p in rx:
            self.validate(p[1], r[i])
            i += 1

        # Now try with re-fragmentation
        #
        # Send fragments to tunnel head-end, for the tunnel head end
        # to reassemble and then refragment
        #
        self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
        frags, p4_reply = self.generate_ip4_frags(3123, 1200)
        self.pg_enable_capture()
        self.pg1.add_stream(frags)
        self.pg_start()
        rx = self.pg0.get_capture(6)
        reass_pkt = reassemble4(rx)
        p4_reply.id = 256
        self.validate(reass_pkt, p4_reply)

        self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
        frags, p4_reply = self.generate_ip4_frags(3123, 1200)
        self.pg_enable_capture()
        self.pg1.add_stream(frags)
        self.pg_start()
        rx = self.pg0.get_capture(2)
        reass_pkt = reassemble4(rx)
        p4_reply.id = 512
        self.validate(reass_pkt, p4_reply)

        # send large packets through the tunnel, expect them to be fragmented
        self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0])

        p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
              IP(src="1.2.3.4", dst="130.67.0.1", tos=42) /
              UDP(sport=1234, dport=1234) / Raw(b'Q' * 1000))
        rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30)
        inners = []
        for p in rx:
            inners.append(p[IP].payload)
        reass_pkt = reassemble4(inners)
        for p in reass_pkt:
            self.assert_packet_checksums_valid(p)
            self.assertEqual(p[IP].ttl, 63)

    def test_ipip_create(self):
        """ ipip create / delete interface test """
        rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
        sw_if_index = rv.sw_if_index
        self.vapi.ipip_del_tunnel(sw_if_index)

    def test_ipip_vrf_create(self):
        """ ipip create / delete interface VRF test """

        t = VppIpTable(self, 20)
        t.add_vpp_config()
        rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
        sw_if_index = rv.sw_if_index
        self.vapi.ipip_del_tunnel(sw_if_index)

    def payload(self, len):
        return 'x' * len

    def test_mipip4(self):
        """ p2mp IPv4 tunnel Tests """

        for itf in self.pg_interfaces[:2]:
            #
            # one underlay nh for each overlay/tunnel peer
            #
            itf.generate_remote_hosts(4)
            itf.configure_ipv4_neighbors()

            #
            # Create an p2mo IPIP tunnel.
            #  - set it admin up
            #  - assign an IP Addres
            #  - Add a route via the tunnel
            #
            ipip_if = VppIpIpTunInterface(
                self,
                itf,
                itf.local_ip4,
                "0.0.0.0",
                mode=(VppEnum.vl_api_tunnel_mode_t.TUNNEL_API_MODE_MP))
            ipip_if.add_vpp_config()
            ipip_if.admin_up()
            ipip_if.config_ip4()
            ipip_if.generate_remote_hosts(4)

            self.logger.info(self.vapi.cli("sh adj"))
            self.logger.info(self.vapi.cli("sh ip fib"))

            #
            # ensure we don't match to the tunnel if the source address
            # is all zeros
            #
            # tx = self.create_tunnel_stream_4o4(self.pg0,
            #                                    "0.0.0.0",
            #                                    itf.local_ip4,
            #                                    self.pg0.local_ip4,
            #                                    self.pg0.remote_ip4)
            # self.send_and_assert_no_replies(self.pg0, tx)

            #
            # for-each peer
            #
            for ii in range(1, 4):
                route_addr = "4.4.4.%d" % ii

                #
                # route traffic via the peer
                #
                route_via_tun = VppIpRoute(self, route_addr, 32, [
                    VppRoutePath(ipip_if._remote_hosts[ii].ip4,
                                 ipip_if.sw_if_index)
                ])
                route_via_tun.add_vpp_config()

                #
                # Add a TEIB entry resolves the peer
                #
                teib = VppTeib(self, ipip_if, ipip_if._remote_hosts[ii].ip4,
                               itf._remote_hosts[ii].ip4)
                teib.add_vpp_config()
                self.logger.info(
                    self.vapi.cli("sh adj nbr ipip0 %s" %
                                  ipip_if._remote_hosts[ii].ip4))

                #
                # Send a packet stream that is routed into the tunnel
                #  - packets are IPIP encapped
                #
                inner = (IP(dst=route_addr, src="5.5.5.5") /
                         UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100))
                tx_e = [
                    (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                     inner) for x in range(63)
                ]

                rxs = self.send_and_expect(self.pg0, tx_e, itf)

                for rx in rxs:
                    self.assertEqual(rx[IP].src, itf.local_ip4)
                    self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)

                tx_i = [
                    (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                     IP(src=itf._remote_hosts[ii].ip4, dst=itf.local_ip4) /
                     IP(src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) /
                     UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100))
                    for x in range(63)
                ]

                self.logger.info(self.vapi.cli("sh ipip tunnel-hash"))
                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)

                #
                # delete and re-add the TEIB
                #
                teib.remove_vpp_config()
                self.send_and_assert_no_replies(self.pg0, tx_e)
                self.send_and_assert_no_replies(self.pg0, tx_i)

                teib.add_vpp_config()
                rx = self.send_and_expect(self.pg0, tx_e, itf)
                for rx in rxs:
                    self.assertEqual(rx[IP].src, itf.local_ip4)
                    self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)
                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)

                #
                # we can also send to the peer's address
                #
                inner = (IP(dst=teib.peer, src="5.5.5.5") /
                         UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100))
                tx_e = [
                    (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                     inner) for x in range(63)
                ]

                rxs = self.send_and_expect(self.pg0, tx_e, itf)

            #
            # with all of the peers in place, swap the ip-table of
            # the ipip interface
            #
            table = VppIpTable(self, 2)
            table.add_vpp_config()

            ipip_if.unconfig_ip4()
            ipip_if.set_table_ip4(self.table.table_id)
            ipip_if.config_ip4()

            #
            # we should still be able to reach the peers from the new table
            #
            inner = (IP(dst=teib.peer, src="5.5.5.5") /
                     UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100))
            tx_e = [(Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                     inner) for x in range(63)]

            rxs = self.send_and_expect(self.pg2, tx_e, itf)

            ipip_if.admin_down()
            ipip_if.unconfig_ip4()
            ipip_if.set_table_ip4(0)
예제 #20
0
    def test_pipe(self):
        """ Pipes """

        pipes = [VppPipe(self), VppPipe(self, 10)]

        for p in pipes:
            p.add_vpp_config()
            p.admin_up()

        #
        # L2 cross-connect pipe0 east with pg0 and west with pg1
        #
        self.vapi.sw_interface_set_l2_xconnect(self.pg0.sw_if_index,
                                               pipes[0].east,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(pipes[0].east,
                                               self.pg0.sw_if_index,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
                                               pipes[0].west,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(pipes[0].west,
                                               self.pg1.sw_if_index,
                                               enable=1)

        # test bi-directional L2 flow pg0<->pg1
        p = (Ether(src=self.pg0.remote_mac,
                   dst=self.pg1.remote_mac) /
             IP(src="1.1.1.1",
                dst="1.1.1.2") /
             UDP(sport=1234, dport=1234) /
             Raw('\xa5' * 100))

        self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
        self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)

        #
        # Attach ACL to ensure features are run on the pipe
        #
        rule_1 = ({'is_permit': 0,
                   'is_ipv6': 0,
                   'proto': 17,
                   'srcport_or_icmptype_first': 1234,
                   'srcport_or_icmptype_last': 1234,
                   'src_ip_prefix_len': 32,
                   'src_ip_addr': inet_pton(AF_INET, "1.1.1.1"),
                   'dstport_or_icmpcode_first': 1234,
                   'dstport_or_icmpcode_last': 1234,
                   'dst_ip_prefix_len': 32,
                   'dst_ip_addr': inet_pton(AF_INET, "1.1.1.2")})
        acl = self.vapi.acl_add_replace(acl_index=4294967295,
                                        r=[rule_1])

        # Apply the ACL on the pipe on output
        self.vapi.acl_interface_set_acl_list(pipes[0].east,
                                             0,
                                             [acl.acl_index])
        self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS)
        self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)

        # remove from output and apply on input
        self.vapi.acl_interface_set_acl_list(pipes[0].east,
                                             0,
                                             [])
        self.vapi.acl_interface_set_acl_list(pipes[0].west,
                                             1,
                                             [acl.acl_index])
        self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS)
        self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)
        self.vapi.acl_interface_set_acl_list(pipes[0].west,
                                             0,
                                             [])
        self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
        self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)

        #
        # L3 routes in two separate tables so a pipe can be used to L3
        # x-connect
        #
        tables = []
        tables.append(VppIpTable(self, 1))
        tables.append(VppIpTable(self, 2))

        for t in tables:
            t.add_vpp_config()

        self.pg2.set_table_ip4(1)
        self.pg2.config_ip4()
        self.pg2.resolve_arp()
        self.pg3.set_table_ip4(2)
        self.pg3.config_ip4()
        self.pg3.resolve_arp()

        routes = []
        routes.append(VppIpRoute(self, "1.1.1.1", 32,
                                 [VppRoutePath(self.pg3.remote_ip4,
                                               self.pg3.sw_if_index)],
                                 table_id=2))
        routes.append(VppIpRoute(self, "1.1.1.1", 32,
                                 [VppRoutePath("0.0.0.0", pipes[1].east)],
                                 table_id=1))
        routes.append(VppIpRoute(self, "1.1.1.2", 32,
                                 [VppRoutePath("0.0.0.0", pipes[1].west)],
                                 table_id=2))
        routes.append(VppIpRoute(self, "1.1.1.2", 32,
                                 [VppRoutePath(self.pg2.remote_ip4,
                                               self.pg2.sw_if_index)],
                                 table_id=1))

        for r in routes:
            r.add_vpp_config()

        p_east = (Ether(src=self.pg2.remote_mac,
                        dst=self.pg2.local_mac) /
                  IP(src="1.1.1.2",
                     dst="1.1.1.1") /
                  UDP(sport=1234, dport=1234) /
                  Raw('\xa5' * 100))

        # bind the pipe ends to the correct tables
        self.vapi.sw_interface_set_table(pipes[1].west, 0, 2)
        self.vapi.sw_interface_set_table(pipes[1].east, 0, 1)

        # IP is not enabled on the pipes at this point
        self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS)

        # IP enable the Pipes by making them unnumbered
        pipes[0].set_unnumbered(self.pg2.sw_if_index)
        pipes[1].set_unnumbered(self.pg3.sw_if_index)

        self.send_and_expect(self.pg2, p_east * NUM_PKTS, self.pg3)

        # and the return path
        p_west = (Ether(src=self.pg3.remote_mac,
                        dst=self.pg3.local_mac) /
                  IP(src="1.1.1.1",
                     dst="1.1.1.2") /
                  UDP(sport=1234, dport=1234) /
                  Raw('\xa5' * 100))
        self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)

        #
        # Use ACLs to test features run on the Pipes
        #
        self.vapi.acl_interface_set_acl_list(pipes[1].east,
                                             0,
                                             [acl.acl_index])
        self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS)
        self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)

        # remove from output and apply on input
        self.vapi.acl_interface_set_acl_list(pipes[1].east,
                                             0,
                                             [])
        self.vapi.acl_interface_set_acl_list(pipes[1].west,
                                             1,
                                             [acl.acl_index])
        self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS)
        self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)
        self.vapi.acl_interface_set_acl_list(pipes[1].west,
                                             0,
                                             [])
        self.send_and_expect(self.pg2, p_east * NUM_PKTS, self.pg3)
        self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)

        # cleanup (so the tables delete)
        self.pg2.unconfig_ip4()
        self.pg2.set_table_ip4(0)
        self.pg3.unconfig_ip4()
        self.pg3.set_table_ip4(0)
        self.vapi.sw_interface_set_table(pipes[1].west, 0, 0)
        self.vapi.sw_interface_set_table(pipes[1].east, 0, 0)
예제 #21
0
class TestGRE(VppTestCase):
    """ GRE Test Case """
    @classmethod
    def setUpClass(cls):
        super(TestGRE, cls).setUpClass()

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

        # create 3 pg interfaces - set one in a non-default table.
        self.create_pg_interfaces(range(3))

        self.tbl = VppIpTable(self, 1)
        self.tbl.add_vpp_config()
        self.pg1.set_table_ip4(1)

        for i in self.pg_interfaces:
            i.admin_up()

        self.pg0.config_ip4()
        self.pg0.resolve_arp()
        self.pg1.config_ip4()
        self.pg1.resolve_arp()
        self.pg2.config_ip6()
        self.pg2.resolve_ndp()

    def tearDown(self):
        for i in self.pg_interfaces:
            i.unconfig_ip4()
            i.unconfig_ip6()
            i.admin_down()
        self.pg1.set_table_ip4(0)
        super(TestGRE, self).tearDown()

    def create_stream_ip4(self, src_if, src_ip, dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=src_ip, dst=dst_ip) / UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_stream_ip6(self, src_if, src_ip, dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IPv6(src=src_ip, dst=dst_ip) / UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_4o4(self, src_if, tunnel_src, tunnel_dst, src_ip,
                                 dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=tunnel_src, dst=tunnel_dst) / GRE() /
                 IP(src=src_ip, dst=dst_ip) / UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_6o4(self, src_if, tunnel_src, tunnel_dst, src_ip,
                                 dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=tunnel_src, dst=tunnel_dst) / GRE() /
                 IPv6(src=src_ip, dst=dst_ip) / UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_6o6(self, src_if, tunnel_src, tunnel_dst, src_ip,
                                 dst_ip):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IPv6(src=tunnel_src, dst=tunnel_dst) / GRE() /
                 IPv6(src=src_ip, dst=dst_ip) / UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_l2o4(self, src_if, tunnel_src, tunnel_dst):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (
                Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                IP(src=tunnel_src, dst=tunnel_dst) / GRE() /
                Ether(dst=RandMAC('*:*:*:*:*:*'), src=RandMAC('*:*:*:*:*:*')) /
                IP(src=str(RandIP()), dst=str(RandIP())) /
                UDP(sport=1234, dport=1234) / Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_tunnel_stream_vlano4(self, src_if, tunnel_src, tunnel_dst,
                                    vlan):
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (
                Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                IP(src=tunnel_src, dst=tunnel_dst) / GRE() /
                Ether(dst=RandMAC('*:*:*:*:*:*'), src=RandMAC('*:*:*:*:*:*')) /
                Dot1Q(vlan=vlan) / IP(src=str(RandIP()), dst=str(RandIP())) /
                UDP(sport=1234, dport=1234) / Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def verify_tunneled_4o4(self, src_if, capture, sent, tunnel_src,
                            tunnel_dst):

        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = rx[GRE]
                rx_ip = rx_gre[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # IP processing post pop has decremented the TTL
                self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_6o6(self, src_if, capture, sent, tunnel_src,
                            tunnel_dst):

        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IPv6]
                rx_ip = rx[IPv6]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = GRE(str(rx_ip[IPv6].payload))
                rx_ip = rx_gre[IPv6]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_l2o4(self, src_if, capture, sent, tunnel_src,
                             tunnel_dst):
        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = rx[GRE]
                rx_l2 = rx_gre[Ether]
                rx_ip = rx_l2[IP]
                tx_gre = tx[GRE]
                tx_l2 = tx_gre[Ether]
                tx_ip = tx_l2[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # bridged, not L3 forwarded, so no TTL decrement
                self.assertEqual(rx_ip.ttl, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_tunneled_vlano4(self, src_if, capture, sent, tunnel_src,
                               tunnel_dst, vlan):
        try:
            self.assertEqual(len(capture), len(sent))
        except:
            ppc("Unexpected packets captured:", capture)
            raise

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]

                self.assertEqual(rx_ip.src, tunnel_src)
                self.assertEqual(rx_ip.dst, tunnel_dst)

                rx_gre = rx[GRE]
                rx_l2 = rx_gre[Ether]
                rx_vlan = rx_l2[Dot1Q]
                rx_ip = rx_l2[IP]

                self.assertEqual(rx_vlan.vlan, vlan)

                tx_gre = tx[GRE]
                tx_l2 = tx_gre[Ether]
                tx_ip = tx_l2[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # bridged, not L3 forwarded, so no TTL decrement
                self.assertEqual(rx_ip.ttl, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_decapped_4o4(self, src_if, capture, sent):
        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IP]
                tx_gre = tx[GRE]
                tx_ip = tx_gre[IP]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # IP processing post pop has decremented the TTL
                self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def verify_decapped_6o4(self, src_if, capture, sent):
        self.assertEqual(len(capture), len(sent))

        for i in range(len(capture)):
            try:
                tx = sent[i]
                rx = capture[i]

                tx_ip = tx[IP]
                rx_ip = rx[IPv6]
                tx_gre = tx[GRE]
                tx_ip = tx_gre[IPv6]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)

            except:
                self.logger.error(ppp("Rx:", rx))
                self.logger.error(ppp("Tx:", tx))
                raise

    def test_gre(self):
        """ GRE IPv4 tunnel Tests """

        #
        # Create an L3 GRE tunnel.
        #  - set it admin up
        #  - assign an IP Addres
        #  - Add a route via the tunnel
        #
        gre_if = VppGreInterface(self, self.pg0.local_ip4, "1.1.1.2")
        gre_if.add_vpp_config()

        #
        # The double create (create the same tunnel twice) should fail,
        # and we should still be able to use the original
        #
        try:
            gre_if.add_vpp_config()
        except Exception:
            pass
        else:
            self.fail("Double GRE tunnel add does not fail")

        gre_if.admin_up()
        gre_if.config_ip4()

        route_via_tun = VppIpRoute(
            self, "4.4.4.4", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)])

        route_via_tun.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - they are all dropped since the tunnel's desintation IP
        #    is unresolved - or resolves via the default route - which
        #    which is a drop.
        #
        tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        self.pg0.assert_nothing_captured(
            remark="GRE packets forwarded without DIP resolved")

        #
        # Add a route that resolves the tunnel's destination
        #
        route_tun_dst = VppIpRoute(
            self, "1.1.1.2", 32,
            [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index)])
        route_tun_dst.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - packets are GRE encapped
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture(len(tx))
        self.verify_tunneled_4o4(self.pg0, rx, tx, self.pg0.local_ip4,
                                 "1.1.1.2")

        #
        # Send tunneled packets that match the created tunnel and
        # are decapped and forwarded
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_4o4(self.pg0, "1.1.1.2",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture(len(tx))
        self.verify_decapped_4o4(self.pg0, rx, tx)

        #
        # Send tunneled packets that do not match the tunnel's src
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_4o4(self.pg0, "1.1.1.3",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        self.pg0.assert_nothing_captured(
            remark="GRE packets forwarded despite no SRC address match")

        #
        # Configure IPv6 on the PG interface so we can route IPv6
        # packets
        #
        self.pg0.config_ip6()
        self.pg0.resolve_ndp()

        #
        # Send IPv6 tunnel encapslated packets
        #  - dropped since IPv6 is not enabled on the tunnel
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_6o4(self.pg0, "1.1.1.2",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip6,
                                           self.pg0.remote_ip6)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        self.pg0.assert_nothing_captured(remark="IPv6 GRE packets forwarded "
                                         "despite IPv6 not enabled on tunnel")

        #
        # Enable IPv6 on the tunnel
        #
        gre_if.config_ip6()

        #
        # Send IPv6 tunnel encapslated packets
        #  - forwarded since IPv6 is enabled on the tunnel
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_6o4(self.pg0, "1.1.1.2",
                                           self.pg0.local_ip4,
                                           self.pg0.local_ip6,
                                           self.pg0.remote_ip6)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture(len(tx))
        self.verify_decapped_6o4(self.pg0, rx, tx)

        #
        # test case cleanup
        #
        route_tun_dst.remove_vpp_config()
        route_via_tun.remove_vpp_config()
        gre_if.remove_vpp_config()

        self.pg0.unconfig_ip6()

    def test_gre6(self):
        """ GRE IPv6 tunnel Tests """

        self.pg1.config_ip6()
        self.pg1.resolve_ndp()

        #
        # Create an L3 GRE tunnel.
        #  - set it admin up
        #  - assign an IP Address
        #  - Add a route via the tunnel
        #
        gre_if = VppGre6Interface(self, self.pg2.local_ip6, "1002::1")
        gre_if.add_vpp_config()
        gre_if.admin_up()
        gre_if.config_ip6()

        route_via_tun = VppIpRoute(
            self,
            "4004::1",
            128, [
                VppRoutePath(
                    "0::0", gre_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)
            ],
            is_ip6=1)

        route_via_tun.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - they are all dropped since the tunnel's desintation IP
        #    is unresolved - or resolves via the default route - which
        #    which is a drop.
        #
        tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
        self.pg2.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        self.pg2.assert_nothing_captured(
            remark="GRE packets forwarded without DIP resolved")

        #
        # Add a route that resolves the tunnel's destination
        #
        route_tun_dst = VppIpRoute(
            self,
            "1002::1",
            128, [
                VppRoutePath(self.pg2.remote_ip6,
                             self.pg2.sw_if_index,
                             proto=DpoProto.DPO_PROTO_IP6)
            ],
            is_ip6=1)
        route_tun_dst.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        #  - packets are GRE encapped
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
        self.pg2.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(len(tx))
        self.verify_tunneled_6o6(self.pg2, rx, tx, self.pg2.local_ip6,
                                 "1002::1")

        #
        # Test decap. decapped packets go out pg1
        #
        tx = self.create_tunnel_stream_6o6(self.pg2, "1002::1",
                                           self.pg2.local_ip6, "2001::1",
                                           self.pg1.remote_ip6)
        self.vapi.cli("clear trace")
        self.pg2.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        rx = self.pg1.get_capture(len(tx))

        #
        # RX'd packet is UDP over IPv6, test the GRE header is gone.
        #
        self.assertFalse(rx[0].haslayer(GRE))
        self.assertEqual(rx[0][IPv6].dst, self.pg1.remote_ip6)

        #
        # test case cleanup
        #
        route_tun_dst.remove_vpp_config()
        route_via_tun.remove_vpp_config()
        gre_if.remove_vpp_config()

        self.pg2.unconfig_ip6()
        self.pg1.unconfig_ip6()

    def test_gre_vrf(self):
        """ GRE tunnel VRF Tests """

        #
        # Create an L3 GRE tunnel whose destination is in the non-default
        # table. The underlay is thus non-default - the overlay is still
        # the default.
        #  - set it admin up
        #  - assign an IP Addres
        #
        gre_if = VppGreInterface(self,
                                 self.pg1.local_ip4,
                                 "2.2.2.2",
                                 outer_fib_id=1)
        gre_if.add_vpp_config()
        gre_if.admin_up()
        gre_if.config_ip4()

        #
        # Add a route via the tunnel - in the overlay
        #
        route_via_tun = VppIpRoute(
            self, "9.9.9.9", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)])
        route_via_tun.add_vpp_config()

        #
        # Add a route that resolves the tunnel's destination - in the
        # underlay table
        #
        route_tun_dst = VppIpRoute(
            self,
            "2.2.2.2",
            32,
            table_id=1,
            paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)])
        route_tun_dst.add_vpp_config()

        #
        # Send a packet stream that is routed into the tunnel
        # packets are sent in on pg0 which is in the default table
        #  - packets are GRE encapped
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(len(tx))
        self.verify_tunneled_4o4(self.pg1, rx, tx, self.pg1.local_ip4,
                                 "2.2.2.2")

        #
        # Send tunneled packets that match the created tunnel and
        # are decapped and forwarded. This tests the decap lookup
        # does not happen in the encap table
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_4o4(self.pg1, "2.2.2.2",
                                           self.pg1.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        self.pg1.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture(len(tx))
        self.verify_decapped_4o4(self.pg0, rx, tx)

        #
        # Send tunneled packets that match the created tunnel and
        # but arrive on an interface that is not in the tunnel's
        # encap VRF, these are dropped
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_4o4(self.pg2, "2.2.2.2",
                                           self.pg1.local_ip4,
                                           self.pg0.local_ip4,
                                           self.pg0.remote_ip4)
        self.pg1.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        self.pg0.assert_nothing_captured(
            remark="GRE decap packets in wrong VRF")

        #
        # test case cleanup
        #
        route_tun_dst.remove_vpp_config()
        route_via_tun.remove_vpp_config()
        gre_if.remove_vpp_config()

    def test_gre_l2(self):
        """ GRE tunnel L2 Tests """

        #
        # Add routes to resolve the tunnel destinations
        #
        route_tun1_dst = VppIpRoute(
            self, "2.2.2.2", 32,
            [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index)])
        route_tun2_dst = VppIpRoute(
            self, "2.2.2.3", 32,
            [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index)])

        route_tun1_dst.add_vpp_config()
        route_tun2_dst.add_vpp_config()

        #
        # Create 2 L2 GRE tunnels and x-connect them
        #
        gre_if1 = VppGreInterface(self,
                                  self.pg0.local_ip4,
                                  "2.2.2.2",
                                  type=GreTunnelTypes.TT_TEB)
        gre_if2 = VppGreInterface(self,
                                  self.pg0.local_ip4,
                                  "2.2.2.3",
                                  type=GreTunnelTypes.TT_TEB)
        gre_if1.add_vpp_config()
        gre_if2.add_vpp_config()

        gre_if1.admin_up()
        gre_if2.admin_up()

        self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
                                               gre_if2.sw_if_index,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
                                               gre_if1.sw_if_index,
                                               enable=1)

        #
        # Send in tunnel encapped L2. expect out tunnel encapped L2
        # in both directions
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_l2o4(self.pg0, "2.2.2.2",
                                            self.pg0.local_ip4)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture(len(tx))
        self.verify_tunneled_l2o4(self.pg0, rx, tx, self.pg0.local_ip4,
                                  "2.2.2.3")

        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_l2o4(self.pg0, "2.2.2.3",
                                            self.pg0.local_ip4)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture(len(tx))
        self.verify_tunneled_l2o4(self.pg0, rx, tx, self.pg0.local_ip4,
                                  "2.2.2.2")

        self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
                                               gre_if2.sw_if_index,
                                               enable=0)
        self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
                                               gre_if1.sw_if_index,
                                               enable=0)

        #
        # Create a VLAN sub-interfaces on the GRE TEB interfaces
        # then x-connect them
        #
        gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
        gre_if_12 = VppDot1QSubint(self, gre_if2, 12)

        # gre_if_11.add_vpp_config()
        # gre_if_12.add_vpp_config()

        gre_if_11.admin_up()
        gre_if_12.admin_up()

        self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
                                               gre_if_12.sw_if_index,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
                                               gre_if_11.sw_if_index,
                                               enable=1)

        #
        # Configure both to pop thier respective VLAN tags,
        # so that during the x-coonect they will subsequently push
        #
        self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
                                                  L2_VTR_OP.L2_POP_1, 12)
        self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
                                                  L2_VTR_OP.L2_POP_1, 11)

        #
        # Send traffic in both directiond - expect the VLAN tags to
        # be swapped.
        #
        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_vlano4(self.pg0, "2.2.2.2",
                                              self.pg0.local_ip4, 11)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture(len(tx))
        self.verify_tunneled_vlano4(self.pg0, rx, tx, self.pg0.local_ip4,
                                    "2.2.2.3", 12)

        self.vapi.cli("clear trace")
        tx = self.create_tunnel_stream_vlano4(self.pg0, "2.2.2.3",
                                              self.pg0.local_ip4, 12)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture(len(tx))
        self.verify_tunneled_vlano4(self.pg0, rx, tx, self.pg0.local_ip4,
                                    "2.2.2.2", 11)

        #
        # Cleanup Test resources
        #
        gre_if_11.remove_vpp_config()
        gre_if_12.remove_vpp_config()
        gre_if1.remove_vpp_config()
        gre_if2.remove_vpp_config()
        route_tun1_dst.add_vpp_config()
        route_tun2_dst.add_vpp_config()
예제 #22
0
파일: test_abf.py 프로젝트: vpp-dev/vpp
    def test_abf4(self):
        """ IPv4 ACL Based Forwarding
        """

        #
        # We are not testing the various matching capabilities
        # of ACLs, that's done elsewhere. Here ware are testing
        # the application of ACLs to a forwarding path to achieve
        # ABF
        # So we construct just a few ACLs to ensure the ABF policies
        # are correclty constructed and used. And a few path types
        # to test the API path decoding.
        #

        #
        # Rule 1
        #
        rule_1 = ({'is_permit': 1,
                   'is_ipv6': 0,
                   'proto': 17,
                   'srcport_or_icmptype_first': 1234,
                   'srcport_or_icmptype_last': 1234,
                   'src_ip_prefix_len': 32,
                   'src_ip_addr': inet_pton(AF_INET, "1.1.1.1"),
                   'dstport_or_icmpcode_first': 1234,
                   'dstport_or_icmpcode_last': 1234,
                   'dst_ip_prefix_len': 32,
                   'dst_ip_addr': inet_pton(AF_INET, "1.1.1.2")})
        acl_1 = self.vapi.acl_add_replace(acl_index=4294967295, r=[rule_1])

        #
        # ABF policy for ACL 1 - path via interface 1
        #
        abf_1 = VppAbfPolicy(self, 10, acl_1,
                             [VppRoutePath(self.pg1.remote_ip4,
                                           self.pg1.sw_if_index)])
        abf_1.add_vpp_config()

        #
        # Attach the policy to input interface Pg0
        #
        attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 50)
        attach_1.add_vpp_config()

        #
        # fire in packet matching the ACL src,dst. If it's forwarded
        # then the ABF was successful, since default routing will drop it
        #
        p_1 = (Ether(src=self.pg0.remote_mac,
                     dst=self.pg0.local_mac) /
               IP(src="1.1.1.1", dst="1.1.1.2") /
               UDP(sport=1234, dport=1234) /
               Raw('\xa5' * 100))
        self.send_and_expect(self.pg0, p_1*65, self.pg1)

        #
        # Attach a 'better' priority policy to the same interface
        #
        abf_2 = VppAbfPolicy(self, 11, acl_1,
                             [VppRoutePath(self.pg2.remote_ip4,
                                           self.pg2.sw_if_index)])
        abf_2.add_vpp_config()
        attach_2 = VppAbfAttach(self, 11, self.pg0.sw_if_index, 40)
        attach_2.add_vpp_config()

        self.send_and_expect(self.pg0, p_1*65, self.pg2)

        #
        # Attach a policy with priority in the middle
        #
        abf_3 = VppAbfPolicy(self, 12, acl_1,
                             [VppRoutePath(self.pg3.remote_ip4,
                                           self.pg3.sw_if_index)])
        abf_3.add_vpp_config()
        attach_3 = VppAbfAttach(self, 12, self.pg0.sw_if_index, 45)
        attach_3.add_vpp_config()

        self.send_and_expect(self.pg0, p_1*65, self.pg2)

        #
        # remove the best priority
        #
        attach_2.remove_vpp_config()
        self.send_and_expect(self.pg0, p_1*65, self.pg3)

        #
        # Attach one of the same policies to Pg1
        #
        attach_4 = VppAbfAttach(self, 12, self.pg1.sw_if_index, 45)
        attach_4.add_vpp_config()

        p_2 = (Ether(src=self.pg1.remote_mac,
                     dst=self.pg1.local_mac) /
               IP(src="1.1.1.1", dst="1.1.1.2") /
               UDP(sport=1234, dport=1234) /
               Raw('\xa5' * 100))
        self.send_and_expect(self.pg1, p_2 * 65, self.pg3)

        #
        # detach the policy from PG1, now expect traffic to be dropped
        #
        attach_4.remove_vpp_config()

        self.send_and_assert_no_replies(self.pg1, p_2 * 65, "Detached")

        #
        # Swap to route via a next-hop in the non-default table
        #
        table_20 = VppIpTable(self, 20)
        table_20.add_vpp_config()

        self.pg4.set_table_ip4(table_20.table_id)
        self.pg4.admin_up()
        self.pg4.config_ip4()
        self.pg4.resolve_arp()

        abf_13 = VppAbfPolicy(self, 13, acl_1,
                              [VppRoutePath(self.pg4.remote_ip4,
                                            0xffffffff,
                                            nh_table_id=table_20.table_id)])
        abf_13.add_vpp_config()
        attach_5 = VppAbfAttach(self, 13, self.pg0.sw_if_index, 30)
        attach_5.add_vpp_config()

        self.send_and_expect(self.pg0, p_1*65, self.pg4)

        self.pg4.unconfig_ip4()
        self.pg4.set_table_ip4(0)
예제 #23
0
class ARPTestCase(VppTestCase):
    """ ARP Test Case """
    def setUp(self):
        super(ARPTestCase, self).setUp()

        # create 3 pg interfaces
        self.create_pg_interfaces(range(4))

        # pg0 configured with ip4 and 6 addresses used for input
        # pg1 configured with ip4 and 6 addresses used for output
        # pg2 is unnumbered to pg0
        for i in self.pg_interfaces:
            i.admin_up()

        self.pg0.config_ip4()
        self.pg0.config_ip6()
        self.pg0.resolve_arp()

        self.pg1.config_ip4()
        self.pg1.config_ip6()

        # pg3 in a different VRF
        self.tbl = VppIpTable(self, 1)
        self.tbl.add_vpp_config()

        self.pg3.set_table_ip4(1)
        self.pg3.config_ip4()

    def tearDown(self):
        self.pg0.unconfig_ip4()
        self.pg0.unconfig_ip6()

        self.pg1.unconfig_ip4()
        self.pg1.unconfig_ip6()

        self.pg3.unconfig_ip4()
        self.pg3.set_table_ip4(0)

        for i in self.pg_interfaces:
            i.admin_down()

        super(ARPTestCase, self).tearDown()

    def verify_arp_req(self, rx, smac, sip, dip):
        ether = rx[Ether]
        self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
        self.assertEqual(ether.src, smac)

        arp = rx[ARP]
        self.assertEqual(arp.hwtype, 1)
        self.assertEqual(arp.ptype, 0x800)
        self.assertEqual(arp.hwlen, 6)
        self.assertEqual(arp.plen, 4)
        self.assertEqual(arp.op, arp_opts["who-has"])
        self.assertEqual(arp.hwsrc, smac)
        self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
        self.assertEqual(arp.psrc, sip)
        self.assertEqual(arp.pdst, dip)

    def verify_arp_resp(self, rx, smac, dmac, sip, dip):
        ether = rx[Ether]
        self.assertEqual(ether.dst, dmac)
        self.assertEqual(ether.src, smac)

        arp = rx[ARP]
        self.assertEqual(arp.hwtype, 1)
        self.assertEqual(arp.ptype, 0x800)
        self.assertEqual(arp.hwlen, 6)
        self.assertEqual(arp.plen, 4)
        self.assertEqual(arp.op, arp_opts["is-at"])
        self.assertEqual(arp.hwsrc, smac)
        self.assertEqual(arp.hwdst, dmac)
        self.assertEqual(arp.psrc, sip)
        self.assertEqual(arp.pdst, dip)

    def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
        ether = rx[Ether]
        self.assertEqual(ether.dst, dmac)
        self.assertEqual(ether.src, smac)

        arp = rx[ARP]
        self.assertEqual(arp.hwtype, 1)
        self.assertEqual(arp.ptype, 0x800)
        self.assertEqual(arp.hwlen, 6)
        self.assertEqual(arp.plen, 4)
        self.assertEqual(arp.op, arp_opts["is-at"])
        self.assertNotEqual(arp.hwsrc, smac)
        self.assertTrue("00:00:5e:00:01" in arp.hwsrc
                        or "00:00:5E:00:01" in arp.hwsrc)
        self.assertEqual(arp.hwdst, dmac)
        self.assertEqual(arp.psrc, sip)
        self.assertEqual(arp.pdst, dip)

    def verify_ip(self, rx, smac, dmac, sip, dip):
        ether = rx[Ether]
        self.assertEqual(ether.dst, dmac)
        self.assertEqual(ether.src, smac)

        ip = rx[IP]
        self.assertEqual(ip.src, sip)
        self.assertEqual(ip.dst, dip)

    def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
        ether = rx[Ether]
        self.assertEqual(ether.dst, dmac)
        self.assertEqual(ether.src, smac)

        mpls = rx[MPLS]
        self.assertTrue(mpls.label, label)

        ip = rx[IP]
        self.assertEqual(ip.src, sip)
        self.assertEqual(ip.dst, dip)

    def test_arp(self):
        """ ARP """

        #
        # Generate some hosts on the LAN
        #
        self.pg1.generate_remote_hosts(11)

        #
        # Send IP traffic to one of these unresolved hosts.
        #  expect the generation of an ARP request
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
             UDP(sport=1234, dport=1234) / Raw())

        self.pg0.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(1)

        self.verify_arp_req(rx[0], self.pg1.local_mac, self.pg1.local_ip4,
                            self.pg1._remote_hosts[1].ip4)

        #
        # And a dynamic ARP entry for host 1
        #
        dyn_arp = VppNeighbor(self, self.pg1.sw_if_index,
                              self.pg1.remote_hosts[1].mac,
                              self.pg1.remote_hosts[1].ip4)
        dyn_arp.add_vpp_config()

        #
        # now we expect IP traffic forwarded
        #
        dyn_p = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
            UDP(sport=1234, dport=1234) / Raw())

        self.pg0.add_stream(dyn_p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(1)

        self.verify_ip(rx[0], self.pg1.local_mac, self.pg1.remote_hosts[1].mac,
                       self.pg0.remote_ip4, self.pg1._remote_hosts[1].ip4)

        #
        # And a Static ARP entry for host 2
        #
        static_arp = VppNeighbor(self,
                                 self.pg1.sw_if_index,
                                 self.pg1.remote_hosts[2].mac,
                                 self.pg1.remote_hosts[2].ip4,
                                 is_static=1)
        static_arp.add_vpp_config()

        static_p = (
            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
            IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[2].ip4) /
            UDP(sport=1234, dport=1234) / Raw())

        self.pg0.add_stream(static_p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(1)

        self.verify_ip(rx[0], self.pg1.local_mac, self.pg1.remote_hosts[2].mac,
                       self.pg0.remote_ip4, self.pg1._remote_hosts[2].ip4)

        #
        # flap the link. dynamic ARPs get flush, statics don't
        #
        self.pg1.admin_down()
        self.pg1.admin_up()

        self.pg0.add_stream(static_p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        rx = self.pg1.get_capture(1)

        self.verify_ip(rx[0], self.pg1.local_mac, self.pg1.remote_hosts[2].mac,
                       self.pg0.remote_ip4, self.pg1._remote_hosts[2].ip4)

        self.pg0.add_stream(dyn_p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(1)
        self.verify_arp_req(rx[0], self.pg1.local_mac, self.pg1.local_ip4,
                            self.pg1._remote_hosts[1].ip4)

        #
        # Send an ARP request from one of the so-far unlearned remote hosts
        #
        p = (
            Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[3].mac) /
            ARP(op="who-has",
                hwsrc=self.pg1._remote_hosts[3].mac,
                pdst=self.pg1.local_ip4,
                psrc=self.pg1._remote_hosts[3].ip4))

        self.pg1.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg1.local_mac,
                             self.pg1._remote_hosts[3].mac, self.pg1.local_ip4,
                             self.pg1._remote_hosts[3].ip4)

        #
        # VPP should have learned the mapping for the remote host
        #
        self.assertTrue(
            find_nbr(self, self.pg1.sw_if_index,
                     self.pg1._remote_hosts[3].ip4))
        #
        # Fire in an ARP request before the interface becomes IP enabled
        #
        self.pg2.generate_remote_hosts(4)

        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg2.remote_mac,
                 pdst=self.pg1.local_ip4,
                 psrc=self.pg2.remote_hosts[3].ip4))
        pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
              Dot1Q(vlan=0) / ARP(op="who-has",
                                  hwsrc=self.pg2.remote_mac,
                                  pdst=self.pg1.local_ip4,
                                  psrc=self.pg2.remote_hosts[3].ip4))
        self.send_and_assert_no_replies(self.pg2, p,
                                        "interface not IP enabled")

        #
        # Make pg2 un-numbered to pg1
        #
        self.pg2.set_unnumbered(self.pg1.sw_if_index)

        unnum = self.vapi.ip_unnumbered_dump()
        self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
        self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)

        #
        # We should respond to ARP requests for the unnumbered to address
        # once an attached route to the source is known
        #
        self.send_and_assert_no_replies(
            self.pg2, p, "ARP req for unnumbered address - no source")

        attached_host = VppIpRoute(
            self, self.pg2.remote_hosts[3].ip4, 32,
            [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)])
        attached_host.add_vpp_config()

        self.pg2.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac,
                             self.pg1.local_ip4, self.pg2.remote_hosts[3].ip4)

        self.pg2.add_stream(pt)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac,
                             self.pg1.local_ip4, self.pg2.remote_hosts[3].ip4)

        #
        # A neighbor entry that has no associated FIB-entry
        #
        arp_no_fib = VppNeighbor(self,
                                 self.pg1.sw_if_index,
                                 self.pg1.remote_hosts[4].mac,
                                 self.pg1.remote_hosts[4].ip4,
                                 is_no_fib_entry=1)
        arp_no_fib.add_vpp_config()

        #
        # check we have the neighbor, but no route
        #
        self.assertTrue(
            find_nbr(self, self.pg1.sw_if_index,
                     self.pg1._remote_hosts[4].ip4))
        self.assertFalse(find_route(self, self.pg1._remote_hosts[4].ip4, 32))
        #
        # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
        # from within pg1's subnet
        #
        arp_unnum = VppNeighbor(self, self.pg2.sw_if_index,
                                self.pg1.remote_hosts[5].mac,
                                self.pg1.remote_hosts[5].ip4)
        arp_unnum.add_vpp_config()

        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[5].ip4) /
             UDP(sport=1234, dport=1234) / Raw())

        self.pg0.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(1)

        self.verify_ip(rx[0], self.pg2.local_mac, self.pg1.remote_hosts[5].mac,
                       self.pg0.remote_ip4, self.pg1._remote_hosts[5].ip4)

        #
        # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
        # with the unnumbered interface's address as the source
        #
        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg2.remote_mac,
                 pdst=self.pg1.local_ip4,
                 psrc=self.pg1.remote_hosts[6].ip4))

        self.pg2.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac,
                             self.pg1.local_ip4, self.pg1.remote_hosts[6].ip4)

        #
        # An attached host route out of pg2 for an undiscovered hosts generates
        # an ARP request with the unnumbered address as the source
        #
        att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
                               [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)])
        att_unnum.add_vpp_config()

        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[7].ip4) /
             UDP(sport=1234, dport=1234) / Raw())

        self.pg0.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(1)

        self.verify_arp_req(rx[0], self.pg2.local_mac, self.pg1.local_ip4,
                            self.pg1._remote_hosts[7].ip4)

        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg2.remote_mac,
                 pdst=self.pg1.local_ip4,
                 psrc=self.pg1.remote_hosts[7].ip4))

        self.pg2.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac,
                             self.pg1.local_ip4, self.pg1.remote_hosts[7].ip4)

        #
        # An attached host route as yet unresolved out of pg2 for an
        # undiscovered host, an ARP requests begets a response.
        #
        att_unnum1 = VppIpRoute(
            self, self.pg1.remote_hosts[8].ip4, 32,
            [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)])
        att_unnum1.add_vpp_config()

        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg2.remote_mac,
                 pdst=self.pg1.local_ip4,
                 psrc=self.pg1.remote_hosts[8].ip4))

        self.pg2.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac,
                             self.pg1.local_ip4, self.pg1.remote_hosts[8].ip4)

        #
        # Send an ARP request from one of the so-far unlearned remote hosts
        # with a VLAN0 tag
        #
        p = (
            Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[9].mac) /
            Dot1Q(vlan=0) / ARP(op="who-has",
                                hwsrc=self.pg1._remote_hosts[9].mac,
                                pdst=self.pg1.local_ip4,
                                psrc=self.pg1._remote_hosts[9].ip4))

        self.pg1.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg1.local_mac,
                             self.pg1._remote_hosts[9].mac, self.pg1.local_ip4,
                             self.pg1._remote_hosts[9].ip4)

        #
        # Add a hierachy of routes for a host in the sub-net.
        # Should still get an ARP resp since the cover is attached
        #
        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg1.remote_mac,
                 pdst=self.pg1.local_ip4,
                 psrc=self.pg1.remote_hosts[10].ip4))

        r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30, [
            VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)
        ])
        r1.add_vpp_config()

        self.pg1.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        rx = self.pg1.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1.remote_mac,
                             self.pg1.local_ip4, self.pg1.remote_hosts[10].ip4)

        r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32, [
            VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)
        ])
        r2.add_vpp_config()

        self.pg1.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        rx = self.pg1.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1.remote_mac,
                             self.pg1.local_ip4, self.pg1.remote_hosts[10].ip4)

        #
        # add an ARP entry that's not on the sub-net and so whose
        # adj-fib fails the refinement check. then send an ARP request
        # from that source
        #
        a1 = VppNeighbor(self, self.pg0.sw_if_index, self.pg0.remote_mac,
                         "100.100.100.50")
        a1.add_vpp_config()

        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg0.remote_mac,
                 psrc="100.100.100.50",
                 pdst=self.pg0.remote_ip4))
        self.send_and_assert_no_replies(self.pg0, p,
                                        "ARP req for from failed adj-fib")

        #
        # ERROR Cases
        #  1 - don't respond to ARP request for address not within the
        #      interface's sub-net
        #  1b - nor within the unnumbered subnet
        #  1c - nor within the subnet of a different interface
        #
        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg0.remote_mac,
                 pdst="10.10.10.3",
                 psrc=self.pg0.remote_ip4))
        self.send_and_assert_no_replies(self.pg0, p,
                                        "ARP req for non-local destination")
        self.assertFalse(find_nbr(self, self.pg0.sw_if_index, "10.10.10.3"))

        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg2.remote_mac,
                 pdst="10.10.10.3",
                 psrc=self.pg1.remote_hosts[7].ip4))
        self.send_and_assert_no_replies(
            self.pg0, p, "ARP req for non-local destination - unnum")

        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg0.remote_mac,
                 pdst=self.pg1.local_ip4,
                 psrc=self.pg1.remote_ip4))
        self.send_and_assert_no_replies(self.pg0, p, "ARP req diff sub-net")
        self.assertFalse(
            find_nbr(self, self.pg0.sw_if_index, self.pg1.remote_ip4))

        #
        #  2 - don't respond to ARP request from an address not within the
        #      interface's sub-net
        #   2b - to a prxied address
        #   2c - not within a differents interface's sub-net
        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg0.remote_mac,
                 psrc="10.10.10.3",
                 pdst=self.pg0.local_ip4))
        self.send_and_assert_no_replies(self.pg0, p,
                                        "ARP req for non-local source")
        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg2.remote_mac,
                 psrc="10.10.10.3",
                 pdst=self.pg0.local_ip4))
        self.send_and_assert_no_replies(
            self.pg0, p, "ARP req for non-local source - unnum")
        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg0.remote_mac,
                 psrc=self.pg1.remote_ip4,
                 pdst=self.pg0.local_ip4))
        self.send_and_assert_no_replies(self.pg0, p,
                                        "ARP req for non-local source 2c")

        #
        #  3 - don't respond to ARP request from an address that belongs to
        #      the router
        #
        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg0.remote_mac,
                 psrc=self.pg0.local_ip4,
                 pdst=self.pg0.local_ip4))
        self.send_and_assert_no_replies(self.pg0, p,
                                        "ARP req for non-local source")

        #
        #  4 - don't respond to ARP requests that has mac source different
        #      from ARP request HW source
        #
        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
             ARP(op="who-has",
                 hwsrc="00:00:00:DE:AD:BE",
                 psrc=self.pg0.remote_ip4,
                 pdst=self.pg0.local_ip4))
        self.send_and_assert_no_replies(self.pg0, p,
                                        "ARP req for non-local source")

        #
        #  5 - don't respond to ARP requests for address within the
        #      interface's sub-net but not the interface's address
        #
        self.pg0.generate_remote_hosts(2)
        p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
             ARP(op="who-has",
                 hwsrc=self.pg0.remote_mac,
                 psrc=self.pg0.remote_hosts[0].ip4,
                 pdst=self.pg0.remote_hosts[1].ip4))
        self.send_and_assert_no_replies(self.pg0, p,
                                        "ARP req for non-local destination")

        #
        # cleanup
        #
        dyn_arp.remove_vpp_config()
        static_arp.remove_vpp_config()
        self.pg2.unset_unnumbered(self.pg1.sw_if_index)

        # need this to flush the adj-fibs
        self.pg2.unset_unnumbered(self.pg1.sw_if_index)
        self.pg2.admin_down()
        self.pg1.admin_down()

    def test_proxy_mirror_arp(self):
        """ Interface Mirror Proxy ARP """

        #
        # When VPP has an interface whose address is also applied to a TAP
        # interface on the host, then VPP's TAP interface will be unnumbered
        # to the 'real' interface and do proxy ARP from the host.
        # the curious aspect of this setup is that ARP requests from the host
        # will come from the VPP's own address.
        #
        self.pg0.generate_remote_hosts(2)

        arp_req_from_me = (
            Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") /
            ARP(op="who-has",
                hwsrc=self.pg2.remote_mac,
                pdst=self.pg0.remote_hosts[1].ip4,
                psrc=self.pg0.local_ip4))

        #
        # Configure Proxy ARP for the subnet on PG0addresses on pg0
        #
        self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet,
                                    self.pg0._local_ip4n_bcast)

        # Make pg2 un-numbered to pg0
        #
        self.pg2.set_unnumbered(self.pg0.sw_if_index)

        #
        # Enable pg2 for proxy ARP
        #
        self.pg2.set_proxy_arp()

        #
        # Send the ARP request with an originating address that
        # is VPP's own address
        #
        self.pg2.add_stream(arp_req_from_me)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac,
                             self.pg0.remote_hosts[1].ip4, self.pg0.local_ip4)

        #
        # validate we have not learned an ARP entry as a result of this
        #
        self.assertFalse(
            find_nbr(self, self.pg2.sw_if_index, self.pg0.local_ip4))

        #
        # cleanup
        #
        self.pg2.set_proxy_arp(0)
        self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet,
                                    self.pg0._local_ip4n_bcast,
                                    is_add=0)

    def test_proxy_arp(self):
        """ Proxy ARP """

        self.pg1.generate_remote_hosts(2)

        #
        # Proxy ARP rewquest packets for each interface
        #
        arp_req_pg0 = (
            Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") /
            ARP(op="who-has",
                hwsrc=self.pg0.remote_mac,
                pdst="10.10.10.3",
                psrc=self.pg0.remote_ip4))
        arp_req_pg0_tagged = (
            Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") /
            Dot1Q(vlan=0) / ARP(op="who-has",
                                hwsrc=self.pg0.remote_mac,
                                pdst="10.10.10.3",
                                psrc=self.pg0.remote_ip4))
        arp_req_pg1 = (
            Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") /
            ARP(op="who-has",
                hwsrc=self.pg1.remote_mac,
                pdst="10.10.10.3",
                psrc=self.pg1.remote_ip4))
        arp_req_pg2 = (
            Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") /
            ARP(op="who-has",
                hwsrc=self.pg2.remote_mac,
                pdst="10.10.10.3",
                psrc=self.pg1.remote_hosts[1].ip4))
        arp_req_pg3 = (
            Ether(src=self.pg3.remote_mac, dst="ff:ff:ff:ff:ff:ff") /
            ARP(op="who-has",
                hwsrc=self.pg3.remote_mac,
                pdst="10.10.10.3",
                psrc=self.pg3.remote_ip4))

        #
        # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
        #
        self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
                                    inet_pton(AF_INET, "10.10.10.124"))

        #
        # No responses are sent when the interfaces are not enabled for proxy
        # ARP
        #
        self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
                                        "ARP req from unconfigured interface")
        self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
                                        "ARP req from unconfigured interface")

        #
        # Make pg2 un-numbered to pg1
        #  still won't reply.
        #
        self.pg2.set_unnumbered(self.pg1.sw_if_index)

        self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
                                        "ARP req from unnumbered interface")

        #
        # Enable each interface to reply to proxy ARPs
        #
        for i in self.pg_interfaces:
            i.set_proxy_arp()

        #
        # Now each of the interfaces should reply to a request to a proxied
        # address
        #
        self.pg0.add_stream(arp_req_pg0)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg0.local_mac, self.pg0.remote_mac,
                             "10.10.10.3", self.pg0.remote_ip4)

        self.pg0.add_stream(arp_req_pg0_tagged)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg0.local_mac, self.pg0.remote_mac,
                             "10.10.10.3", self.pg0.remote_ip4)

        self.pg1.add_stream(arp_req_pg1)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1.remote_mac,
                             "10.10.10.3", self.pg1.remote_ip4)

        self.pg2.add_stream(arp_req_pg2)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(1)
        self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac,
                             "10.10.10.3", self.pg1.remote_hosts[1].ip4)

        #
        # A request for an address out of the configured range
        #
        arp_req_pg1_hi = (
            Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") /
            ARP(op="who-has",
                hwsrc=self.pg1.remote_mac,
                pdst="10.10.10.125",
                psrc=self.pg1.remote_ip4))
        self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
                                        "ARP req out of range HI")
        arp_req_pg1_low = (
            Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") /
            ARP(op="who-has",
                hwsrc=self.pg1.remote_mac,
                pdst="10.10.10.1",
                psrc=self.pg1.remote_ip4))
        self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
                                        "ARP req out of range Low")

        #
        # Request for an address in the proxy range but from an interface
        # in a different VRF
        #
        self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
                                        "ARP req from different VRF")

        #
        # Disable Each interface for proxy ARP
        #  - expect none to respond
        #
        for i in self.pg_interfaces:
            i.set_proxy_arp(0)

        self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
                                        "ARP req from disable")
        self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
                                        "ARP req from disable")
        self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
                                        "ARP req from disable")

        #
        # clean up on interface 2
        #
        self.pg2.unset_unnumbered(self.pg1.sw_if_index)

    def test_mpls(self):
        """ MPLS """

        #
        # Interface 2 does not yet have ip4 config
        #
        self.pg2.config_ip4()
        self.pg2.generate_remote_hosts(2)

        #
        # Add a reoute with out going label via an ARP unresolved next-hop
        #
        ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [
            VppRoutePath(self.pg2.remote_hosts[1].ip4,
                         self.pg2.sw_if_index,
                         labels=[55])
        ])
        ip_10_0_0_1.add_vpp_config()

        #
        # packets should generate an ARP request
        #
        p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
             IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
             UDP(sport=1234, dport=1234) / Raw('\xa5' * 100))

        self.pg0.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(1)
        self.verify_arp_req(rx[0], self.pg2.local_mac, self.pg2.local_ip4,
                            self.pg2._remote_hosts[1].ip4)

        #
        # now resolve the neighbours
        #
        self.pg2.configure_ipv4_neighbors()

        #
        # Now packet should be properly MPLS encapped.
        #  This verifies that MPLS link-type adjacencies are completed
        #  when the ARP entry resolves
        #
        self.pg0.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg2.get_capture(1)
        self.verify_ip_o_mpls(rx[0], self.pg2.local_mac,
                              self.pg2.remote_hosts[1].mac, 55,
                              self.pg0.remote_ip4, "10.0.0.1")
        self.pg2.unconfig_ip4()

    def test_arp_vrrp(self):
        """ ARP reply with VRRP virtual src hw addr """

        #
        # IP packet destined for pg1 remote host arrives on pg0 resulting
        # in an ARP request for the address of the remote host on pg1
        #
        p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
              UDP(sport=1234, dport=1234) / Raw())

        self.pg0.add_stream(p0)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx1 = self.pg1.get_capture(1)

        self.verify_arp_req(rx1[0], self.pg1.local_mac, self.pg1.local_ip4,
                            self.pg1.remote_ip4)

        #
        # ARP reply for address of pg1 remote host arrives on pg1 with
        # the hw src addr set to a value in the VRRP IPv4 range of
        # MAC addresses
        #
        p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
              ARP(op="is-at",
                  hwdst=self.pg1.local_mac,
                  hwsrc="00:00:5e:00:01:09",
                  pdst=self.pg1.local_ip4,
                  psrc=self.pg1.remote_ip4))

        self.pg1.add_stream(p1)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        #
        # IP packet destined for pg1 remote host arrives on pg0 again.
        # VPP should have an ARP entry for that address now and the packet
        # should be sent out pg1.
        #
        self.pg0.add_stream(p0)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx1 = self.pg1.get_capture(1)

        self.verify_ip(rx1[0], self.pg1.local_mac, "00:00:5e:00:01:09",
                       self.pg0.remote_ip4, self.pg1.remote_ip4)

        self.pg1.admin_down()
        self.pg1.admin_up()

    def test_arp_duplicates(self):
        """ ARP Duplicates"""

        #
        # Generate some hosts on the LAN
        #
        self.pg1.generate_remote_hosts(3)

        #
        # Add host 1 on pg1 and pg2
        #
        arp_pg1 = VppNeighbor(self, self.pg1.sw_if_index,
                              self.pg1.remote_hosts[1].mac,
                              self.pg1.remote_hosts[1].ip4)
        arp_pg1.add_vpp_config()
        arp_pg2 = VppNeighbor(self, self.pg2.sw_if_index, self.pg2.remote_mac,
                              self.pg1.remote_hosts[1].ip4)
        arp_pg2.add_vpp_config()

        #
        # IP packet destined for pg1 remote host arrives on pg1 again.
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4) /
             UDP(sport=1234, dport=1234) / Raw())

        self.pg0.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx1 = self.pg1.get_capture(1)

        self.verify_ip(rx1[0], self.pg1.local_mac,
                       self.pg1.remote_hosts[1].mac, self.pg0.remote_ip4,
                       self.pg1.remote_hosts[1].ip4)

        #
        # remove the duplicate on pg1
        # packet stream shoud generate ARPs out of pg1
        #
        arp_pg1.remove_vpp_config()

        self.pg0.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx1 = self.pg1.get_capture(1)

        self.verify_arp_req(rx1[0], self.pg1.local_mac, self.pg1.local_ip4,
                            self.pg1.remote_hosts[1].ip4)

        #
        # Add it back
        #
        arp_pg1.add_vpp_config()

        self.pg0.add_stream(p)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx1 = self.pg1.get_capture(1)

        self.verify_ip(rx1[0], self.pg1.local_mac,
                       self.pg1.remote_hosts[1].mac, self.pg0.remote_ip4,
                       self.pg1.remote_hosts[1].ip4)

    def test_arp_static(self):
        """ ARP Static"""
        self.pg2.generate_remote_hosts(3)

        #
        # Add a static ARP entry
        #
        static_arp = VppNeighbor(self,
                                 self.pg2.sw_if_index,
                                 self.pg2.remote_hosts[1].mac,
                                 self.pg2.remote_hosts[1].ip4,
                                 is_static=1)
        static_arp.add_vpp_config()

        #
        # Add the connected prefix to the interface
        #
        self.pg2.config_ip4()

        #
        # We should now find the adj-fib
        #
        self.assertTrue(
            find_nbr(self,
                     self.pg2.sw_if_index,
                     self.pg2.remote_hosts[1].ip4,
                     is_static=1))
        self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32))

        #
        # remove the connected
        #
        self.pg2.unconfig_ip4()

        #
        # put the interface into table 1
        #
        self.pg2.set_table_ip4(1)

        #
        # configure the same connected and expect to find the
        # adj fib in the new table
        #
        self.pg2.config_ip4()
        self.assertTrue(
            find_route(self, self.pg2.remote_hosts[1].ip4, 32, table_id=1))

        #
        # clean-up
        #
        self.pg2.unconfig_ip4()
        self.pg2.set_table_ip4(0)

    def test_arp_incomplete(self):
        """ ARP Incomplete"""
        self.pg1.generate_remote_hosts(3)

        p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4) /
              UDP(sport=1234, dport=1234) / Raw())
        p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4) /
              UDP(sport=1234, dport=1234) / Raw())

        #
        # a packet to an unresolved destination generates an ARP request
        #
        rx = self.send_and_expect(self.pg0, [p0], self.pg1)
        self.verify_arp_req(rx[0], self.pg1.local_mac, self.pg1.local_ip4,
                            self.pg1._remote_hosts[1].ip4)

        #
        # add a neighbour for remote host 1
        #
        static_arp = VppNeighbor(self,
                                 self.pg1.sw_if_index,
                                 self.pg1.remote_hosts[1].mac,
                                 self.pg1.remote_hosts[1].ip4,
                                 is_static=1)
        static_arp.add_vpp_config()

        #
        # change the interface's MAC
        #
        mac = [
            chr(0x00),
            chr(0x00),
            chr(0x00),
            chr(0x33),
            chr(0x33),
            chr(0x33)
        ]
        mac_string = ''.join(mac)

        self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
                                               mac_string)

        #
        # now ARP requests come from the new source mac
        #
        rx = self.send_and_expect(self.pg0, [p1], self.pg1)
        self.verify_arp_req(rx[0], "00:00:00:33:33:33", self.pg1.local_ip4,
                            self.pg1._remote_hosts[2].ip4)

        #
        # packets to the resolved host also have the new source mac
        #
        rx = self.send_and_expect(self.pg0, [p0], self.pg1)
        self.verify_ip(rx[0], "00:00:00:33:33:33",
                       self.pg1.remote_hosts[1].mac, self.pg0.remote_ip4,
                       self.pg1.remote_hosts[1].ip4)

        #
        # set the mac address on the inteface that does not have a
        # configured subnet and thus no glean
        #
        self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
                                               mac_string)

    def test_garp(self):
        """ GARP """

        #
        # Generate some hosts on the LAN
        #
        self.pg1.generate_remote_hosts(4)

        #
        # And an ARP entry
        #
        arp = VppNeighbor(self, self.pg1.sw_if_index,
                          self.pg1.remote_hosts[1].mac,
                          self.pg1.remote_hosts[1].ip4)
        arp.add_vpp_config()

        self.assertTrue(
            find_nbr(self,
                     self.pg1.sw_if_index,
                     self.pg1.remote_hosts[1].ip4,
                     mac=self.pg1.remote_hosts[1].mac))

        #
        # Send a GARP (request) to swap the host 1's address to that of host 2
        #
        p1 = (
            Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[2].mac) /
            ARP(op="who-has",
                hwdst=self.pg1.local_mac,
                hwsrc=self.pg1.remote_hosts[2].mac,
                pdst=self.pg1.remote_hosts[1].ip4,
                psrc=self.pg1.remote_hosts[1].ip4))

        self.pg1.add_stream(p1)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        self.assertTrue(
            find_nbr(self,
                     self.pg1.sw_if_index,
                     self.pg1.remote_hosts[1].ip4,
                     mac=self.pg1.remote_hosts[2].mac))

        #
        # Send a GARP (reply) to swap the host 1's address to that of host 3
        #
        p1 = (
            Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) /
            ARP(op="is-at",
                hwdst=self.pg1.local_mac,
                hwsrc=self.pg1.remote_hosts[3].mac,
                pdst=self.pg1.remote_hosts[1].ip4,
                psrc=self.pg1.remote_hosts[1].ip4))

        self.pg1.add_stream(p1)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        self.assertTrue(
            find_nbr(self,
                     self.pg1.sw_if_index,
                     self.pg1.remote_hosts[1].ip4,
                     mac=self.pg1.remote_hosts[3].mac))

        #
        # GARPs (requets nor replies) for host we don't know yet
        # don't result in new neighbour entries
        #
        p1 = (
            Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) /
            ARP(op="who-has",
                hwdst=self.pg1.local_mac,
                hwsrc=self.pg1.remote_hosts[3].mac,
                pdst=self.pg1.remote_hosts[2].ip4,
                psrc=self.pg1.remote_hosts[2].ip4))

        self.pg1.add_stream(p1)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        self.assertFalse(
            find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4))

        p1 = (
            Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) /
            ARP(op="is-at",
                hwdst=self.pg1.local_mac,
                hwsrc=self.pg1.remote_hosts[3].mac,
                pdst=self.pg1.remote_hosts[2].ip4,
                psrc=self.pg1.remote_hosts[2].ip4))

        self.pg1.add_stream(p1)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        self.assertFalse(
            find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4))
예제 #24
0
    def test_pipe(self):
        """ Pipes """

        pipes = [VppPipe(self), VppPipe(self, 10)]

        for p in pipes:
            p.add_vpp_config()
            p.admin_up()

        #
        # L2 cross-connect pipe0 east with pg0 and west with pg1
        #
        self.vapi.sw_interface_set_l2_xconnect(self.pg0.sw_if_index,
                                               pipes[0].east,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(pipes[0].east,
                                               self.pg0.sw_if_index,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
                                               pipes[0].west,
                                               enable=1)
        self.vapi.sw_interface_set_l2_xconnect(pipes[0].west,
                                               self.pg1.sw_if_index,
                                               enable=1)

        # test bi-directional L2 flow pg0<->pg1
        p = (Ether(src=self.pg0.remote_mac,
                   dst=self.pg1.remote_mac) /
             IP(src="1.1.1.1",
                dst="1.1.1.2") /
             UDP(sport=1234, dport=1234) /
             Raw(b'\xa5' * 100))

        self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
        self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)

        #
        # Attach ACL to ensure features are run on the pipe
        #
        rule_1 = AclRule(is_permit=0, proto=17,
                         src_prefix=IPv4Network("1.1.1.1/32"),
                         dst_prefix=IPv4Network("1.1.1.2/32"), ports=1234)
        acl = VppAcl(self, rules=[rule_1])
        acl.add_vpp_config()

        # Apply the ACL on the pipe on output
        acl_if_e = VppAclInterface(self, sw_if_index=pipes[0].east, n_input=0,
                                   acls=[acl])
        acl_if_e.add_vpp_config()

        self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS)
        self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)

        # remove from output and apply on input
        acl_if_e.remove_vpp_config()
        acl_if_w = VppAclInterface(self, sw_if_index=pipes[0].west, n_input=1,
                                   acls=[acl])
        acl_if_w.add_vpp_config()

        self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS)
        self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)

        acl_if_w.remove_vpp_config()
        self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
        self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)

        #
        # L3 routes in two separate tables so a pipe can be used to L3
        # x-connect
        #
        tables = []
        tables.append(VppIpTable(self, 1))
        tables.append(VppIpTable(self, 2))

        for t in tables:
            t.add_vpp_config()

        self.pg2.set_table_ip4(1)
        self.pg2.config_ip4()
        self.pg2.resolve_arp()
        self.pg3.set_table_ip4(2)
        self.pg3.config_ip4()
        self.pg3.resolve_arp()

        routes = []
        routes.append(VppIpRoute(self, "1.1.1.1", 32,
                                 [VppRoutePath(self.pg3.remote_ip4,
                                               self.pg3.sw_if_index)],
                                 table_id=2))
        routes.append(VppIpRoute(self, "1.1.1.1", 32,
                                 [VppRoutePath("0.0.0.0", pipes[1].east)],
                                 table_id=1))
        routes.append(VppIpRoute(self, "1.1.1.2", 32,
                                 [VppRoutePath("0.0.0.0", pipes[1].west)],
                                 table_id=2))
        routes.append(VppIpRoute(self, "1.1.1.2", 32,
                                 [VppRoutePath(self.pg2.remote_ip4,
                                               self.pg2.sw_if_index)],
                                 table_id=1))

        for r in routes:
            r.add_vpp_config()

        p_east = (Ether(src=self.pg2.remote_mac,
                        dst=self.pg2.local_mac) /
                  IP(src="1.1.1.2",
                     dst="1.1.1.1") /
                  UDP(sport=1234, dport=1234) /
                  Raw(b'\xa5' * 100))

        # bind the pipe ends to the correct tables
        self.vapi.sw_interface_set_table(pipes[1].west, 0, 2)
        self.vapi.sw_interface_set_table(pipes[1].east, 0, 1)

        # IP is not enabled on the pipes at this point
        self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS)

        # IP enable the Pipes by making them unnumbered
        pipes[0].set_unnumbered(self.pg2.sw_if_index)
        pipes[1].set_unnumbered(self.pg3.sw_if_index)

        self.send_and_expect(self.pg2, p_east * NUM_PKTS, self.pg3)

        # and the return path
        p_west = (Ether(src=self.pg3.remote_mac,
                        dst=self.pg3.local_mac) /
                  IP(src="1.1.1.1",
                     dst="1.1.1.2") /
                  UDP(sport=1234, dport=1234) /
                  Raw(b'\xa5' * 100))
        self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)

        #
        # Use ACLs to test features run on the Pipes
        #
        acl_if_e1 = VppAclInterface(self, sw_if_index=pipes[1].east, n_input=0,
                                    acls=[acl])
        acl_if_e1.add_vpp_config()
        self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS)
        self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)

        # remove from output and apply on input
        acl_if_e1.remove_vpp_config()
        acl_if_w1 = VppAclInterface(self, sw_if_index=pipes[1].west, n_input=1,
                                    acls=[acl])
        acl_if_w1.add_vpp_config()
        self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS)
        self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)
        acl_if_w1.remove_vpp_config()

        self.send_and_expect(self.pg2, p_east * NUM_PKTS, self.pg3)
        self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)

        # cleanup (so the tables delete)
        self.pg2.unconfig_ip4()
        self.pg2.set_table_ip4(0)
        self.pg3.unconfig_ip4()
        self.pg3.set_table_ip4(0)
        self.vapi.sw_interface_set_table(pipes[1].west, 0, 0)
        self.vapi.sw_interface_set_table(pipes[1].east, 0, 0)
예제 #25
0
    def test_gbp(self):
        """ Group Based Policy """

        nat_table = VppIpTable(self, 20)
        nat_table.add_vpp_config()
        nat_table = VppIpTable(self, 20, is_ip6=True)
        nat_table.add_vpp_config()

        #
        # Bridge Domains
        #
        self.vapi.bridge_domain_add_del(1,
                                        flood=1,
                                        uu_flood=1,
                                        forward=1,
                                        learn=0,
                                        arp_term=1,
                                        is_add=1)
        self.vapi.bridge_domain_add_del(2,
                                        flood=1,
                                        uu_flood=1,
                                        forward=1,
                                        learn=0,
                                        arp_term=1,
                                        is_add=1)
        self.vapi.bridge_domain_add_del(20,
                                        flood=1,
                                        uu_flood=1,
                                        forward=1,
                                        learn=0,
                                        arp_term=1,
                                        is_add=1)

        #
        # 3 EPGs, 2 of which share a BD.
        #
        epgs = []
        recircs = []
        epgs.append(
            VppGbpEndpointGroup(self, 220, 0, 1, self.pg4, self.loop0,
                                "10.0.0.128", "2001:10::128"))
        recircs.append(VppGbpRecirc(self, epgs[0], self.loop3))
        epgs.append(
            VppGbpEndpointGroup(self, 221, 0, 1, self.pg5, self.loop0,
                                "10.0.1.128", "2001:10:1::128"))
        recircs.append(VppGbpRecirc(self, epgs[1], self.loop4))
        epgs.append(
            VppGbpEndpointGroup(self, 222, 0, 2, self.pg6, self.loop1,
                                "10.0.2.128", "2001:10:2::128"))
        recircs.append(VppGbpRecirc(self, epgs[2], self.loop5))

        #
        # 2 NAT EPGs, one for floating-IP subnets, the other for internet
        #
        epgs.append(
            VppGbpEndpointGroup(self, 333, 20, 20, self.pg7, self.loop2,
                                "11.0.0.128", "3001::128"))
        recircs.append(VppGbpRecirc(self, epgs[3], self.loop6, is_ext=True))
        epgs.append(
            VppGbpEndpointGroup(self, 444, 20, 20, self.pg8, self.loop2,
                                "11.0.0.129", "3001::129"))
        recircs.append(VppGbpRecirc(self, epgs[4], self.loop8, is_ext=True))

        epg_nat = epgs[3]
        recirc_nat = recircs[3]

        #
        # 4 end-points, 2 in the same subnet, 3 in the same BD
        #
        eps = []
        eps.append(
            VppGbpEndpoint(self, self.pg0, epgs[0], recircs[0], "10.0.0.1",
                           "11.0.0.1"))
        eps.append(
            VppGbpEndpoint(self, self.pg1, epgs[0], recircs[0], "10.0.0.2",
                           "11.0.0.2"))
        eps.append(
            VppGbpEndpoint(self, self.pg2, epgs[1], recircs[1], "10.0.1.1",
                           "11.0.0.3"))
        eps.append(
            VppGbpEndpoint(self, self.pg3, epgs[2], recircs[2], "10.0.2.1",
                           "11.0.0.4"))
        eps.append(
            VppGbpEndpoint(self,
                           self.pg0,
                           epgs[0],
                           recircs[0],
                           "2001:10::1",
                           "3001::1",
                           is_ip6=True))
        eps.append(
            VppGbpEndpoint(self,
                           self.pg1,
                           epgs[0],
                           recircs[0],
                           "2001:10::2",
                           "3001::2",
                           is_ip6=True))
        eps.append(
            VppGbpEndpoint(self,
                           self.pg2,
                           epgs[1],
                           recircs[1],
                           "2001:10:1::1",
                           "3001::3",
                           is_ip6=True))
        eps.append(
            VppGbpEndpoint(self,
                           self.pg3,
                           epgs[2],
                           recircs[2],
                           "2001:10:2::1",
                           "3001::4",
                           is_ip6=True))

        #
        # Config related to each of the EPGs
        #
        for epg in epgs:
            # IP config on the BVI interfaces
            if epg != epgs[1] and epg != epgs[4]:
                epg.bvi.set_table_ip4(epg.rd)
                epg.bvi.set_table_ip6(epg.rd)

                # The BVIs are NAT inside interfaces
                self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
                                                          is_inside=1,
                                                          is_add=1)
                self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
                                                  is_inside=1,
                                                  is_add=1)

            self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
                                                   epg.bvi_ip4_n, 32)
            self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
                                                   epg.bvi_ip6_n,
                                                   128,
                                                   is_ipv6=True)

            # EPG uplink interfaces in the BD
            epg.uplink.set_table_ip4(epg.rd)
            epg.uplink.set_table_ip6(epg.rd)
            self.vapi.sw_interface_set_l2_bridge(epg.uplink.sw_if_index,
                                                 epg.bd)

            # add the BD ARP termination entry for BVI IP
            self.vapi.bd_ip_mac_add_del(bd_id=epg.bd,
                                        mac=mactobinary(self.router_mac),
                                        ip=epg.bvi_ip4_n,
                                        is_ipv6=0,
                                        is_add=1)
            self.vapi.bd_ip_mac_add_del(bd_id=epg.bd,
                                        mac=mactobinary(self.router_mac),
                                        ip=epg.bvi_ip6_n,
                                        is_ipv6=1,
                                        is_add=1)

            # epg[1] shares the same BVI to epg[0]
            if epg != epgs[1] and epg != epgs[4]:
                # BVI in BD
                self.vapi.sw_interface_set_l2_bridge(epg.bvi.sw_if_index,
                                                     epg.bd,
                                                     bvi=1)
                # BVI L2 FIB entry
                self.vapi.l2fib_add_del(self.router_mac,
                                        epg.bd,
                                        epg.bvi.sw_if_index,
                                        is_add=1,
                                        bvi_mac=1)

            # EPG in VPP
            epg.add_vpp_config()

        for recirc in recircs:
            # EPG's ingress recirculation interface maps to its RD
            recirc.recirc.set_table_ip4(recirc.epg.rd)
            recirc.recirc.set_table_ip6(recirc.epg.rd)

            # in the bridge to allow DVR. L2 emulation to punt to L3
            self.vapi.sw_interface_set_l2_bridge(recirc.recirc.sw_if_index,
                                                 recirc.epg.bd)
            self.vapi.sw_interface_set_l2_emulation(recirc.recirc.sw_if_index)

            self.vapi.nat44_interface_add_del_feature(
                recirc.recirc.sw_if_index, is_inside=0, is_add=1)
            self.vapi.nat66_add_del_interface(recirc.recirc.sw_if_index,
                                              is_inside=0,
                                              is_add=1)

            recirc.add_vpp_config()

        ep_routes = []
        ep_arps = []
        for ep in eps:
            self.pg_enable_capture(self.pg_interfaces)
            self.pg_start()
            #
            # routes to the endpoints. We need these since there are no
            # adj-fibs due to the fact the the BVI address has /32 and
            # the subnet is not attached.
            #
            r = VppIpRoute(
                self,
                ep.ip,
                ep.ip_len,
                [VppRoutePath(ep.ip, ep.epg.bvi.sw_if_index, proto=ep.proto)],
                is_ip6=ep.is_ip6)
            r.add_vpp_config()
            ep_routes.append(r)

            #
            # ARP entries for the endpoints
            #
            a = VppNeighbor(self,
                            ep.epg.bvi.sw_if_index,
                            ep.itf.remote_mac,
                            ep.ip,
                            af=ep.af)
            a.add_vpp_config()
            ep_arps.append(a)

            # add each EP itf to the its BD
            self.vapi.sw_interface_set_l2_bridge(ep.itf.sw_if_index, ep.epg.bd)

            # add the BD ARP termination entry
            self.vapi.bd_ip_mac_add_del(bd_id=ep.epg.bd,
                                        mac=ep.bin_mac,
                                        ip=ep.ip_n,
                                        is_ipv6=0,
                                        is_add=1)

            # L2 FIB entry
            self.vapi.l2fib_add_del(ep.mac,
                                    ep.epg.bd,
                                    ep.itf.sw_if_index,
                                    is_add=1)

            # Add static mappings for each EP from the 10/8 to 11/8 network
            if ep.af == AF_INET:
                self.vapi.nat44_add_del_static_mapping(ep.ip_n,
                                                       ep.floating_ip_n,
                                                       vrf_id=0,
                                                       addr_only=1)
            else:
                self.vapi.nat66_add_del_static_mapping(ep.ip_n,
                                                       ep.floating_ip_n,
                                                       vrf_id=0)

            # VPP EP create ...
            ep.add_vpp_config()

            # ... results in a Gratuitous ARP/ND on the EPG's uplink
            rx = ep.epg.uplink.get_capture(1, timeout=0.2)

            if ep.is_ip6:
                self.assertTrue(rx[0].haslayer(ICMPv6ND_NA))
                self.assertEqual(rx[0][ICMPv6ND_NA].tgt, ep.ip)
            else:
                self.assertTrue(rx[0].haslayer(ARP))
                self.assertEqual(rx[0][ARP].psrc, ep.ip)
                self.assertEqual(rx[0][ARP].pdst, ep.ip)

            # add the BD ARP termination entry for floating IP
            self.vapi.bd_ip_mac_add_del(bd_id=epg_nat.bd,
                                        mac=ep.bin_mac,
                                        ip=ep.floating_ip_n,
                                        is_ipv6=ep.is_ip6,
                                        is_add=1)

            # floating IPs route via EPG recirc
            r = VppIpRoute(self,
                           ep.floating_ip,
                           ep.ip_len, [
                               VppRoutePath(ep.floating_ip,
                                            ep.recirc.recirc.sw_if_index,
                                            is_dvr=1,
                                            proto=ep.proto)
                           ],
                           table_id=20,
                           is_ip6=ep.is_ip6)
            r.add_vpp_config()
            ep_routes.append(r)

            # L2 FIB entries in the NAT EPG BD to bridge the packets from
            # the outside direct to the internal EPG
            self.vapi.l2fib_add_del(ep.mac,
                                    epg_nat.bd,
                                    ep.recirc.recirc.sw_if_index,
                                    is_add=1)

        #
        # ARP packets for unknown IP are flooded
        #
        pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
                   ARP(op="who-has",
                       hwdst="ff:ff:ff:ff:ff:ff",
                       hwsrc=self.pg0.remote_mac,
                       pdst=epgs[0].bvi_ip4,
                       psrc="10.0.0.88"))

        self.send_and_expect(self.pg0, [pkt_arp], self.pg0)

        #
        # ARP/ND packets get a response
        #
        pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
                   ARP(op="who-has",
                       hwdst="ff:ff:ff:ff:ff:ff",
                       hwsrc=self.pg0.remote_mac,
                       pdst=epgs[0].bvi_ip4,
                       psrc=eps[0].ip))

        self.send_and_expect(self.pg0, [pkt_arp], self.pg0)

        nsma = in6_getnsma(inet_pton(AF_INET6, eps[4].ip))
        d = inet_ntop(AF_INET6, nsma)
        pkt_nd = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=eps[4].ip) /
                  ICMPv6ND_NS(tgt=epgs[0].bvi_ip6) /
                  ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
        self.send_and_expect(self.pg0, [pkt_nd], self.pg0)

        #
        # broadcast packets are flooded
        #
        pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
                     IP(src=eps[0].ip, dst="232.1.1.1") /
                     UDP(sport=1234, dport=1234) / Raw('\xa5' * 100))

        self.vapi.cli("clear trace")
        self.pg0.add_stream(pkt_bcast)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rxd = eps[1].itf.get_capture(1)
        self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
        rxd = epgs[0].uplink.get_capture(1)
        self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)

        #
        # packets to non-local L3 destinations dropped
        #
        pkt_intra_epg_220_ip4 = (
            Ether(src=self.pg0.remote_mac, dst=self.router_mac) /
            IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) /
            Raw('\xa5' * 100))
        pkt_inter_epg_222_ip4 = (
            Ether(src=self.pg0.remote_mac, dst=self.router_mac) /
            IP(src=eps[0].ip, dst="10.0.1.99") / UDP(sport=1234, dport=1234) /
            Raw('\xa5' * 100))

        self.send_and_assert_no_replies(self.pg0, pkt_intra_epg_220_ip4 * 65)

        pkt_inter_epg_222_ip6 = (
            Ether(src=self.pg0.remote_mac, dst=self.router_mac) /
            IPv6(src=eps[4].ip, dst="2001:10::99") /
            UDP(sport=1234, dport=1234) / Raw('\xa5' * 100))
        self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65)

        #
        # Add the subnet routes
        #
        s41 = VppGbpSubnet(self, 0, "10.0.0.0", 24)
        s42 = VppGbpSubnet(self, 0, "10.0.1.0", 24)
        s43 = VppGbpSubnet(self, 0, "10.0.2.0", 24)
        s41.add_vpp_config()
        s42.add_vpp_config()
        s43.add_vpp_config()
        s61 = VppGbpSubnet(self, 0, "2001:10::1", 64, is_ip6=True)
        s62 = VppGbpSubnet(self, 0, "2001:10:1::1", 64, is_ip6=True)
        s63 = VppGbpSubnet(self, 0, "2001:10:2::1", 64, is_ip6=True)
        s61.add_vpp_config()
        s62.add_vpp_config()
        s63.add_vpp_config()

        self.send_and_expect_bridged(self.pg0, pkt_intra_epg_220_ip4 * 65,
                                     self.pg4)
        self.send_and_expect_bridged(self.pg3, pkt_inter_epg_222_ip4 * 65,
                                     self.pg6)
        self.send_and_expect_bridged6(self.pg3, pkt_inter_epg_222_ip6 * 65,
                                      self.pg6)

        self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
        self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
        self.logger.info(self.vapi.cli("sh gbp endpoint"))
        self.logger.info(self.vapi.cli("sh gbp recirc"))
        self.logger.info(self.vapi.cli("sh int"))
        self.logger.info(self.vapi.cli("sh int addr"))
        self.logger.info(self.vapi.cli("sh int feat loop6"))
        self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
        self.logger.info(self.vapi.cli("sh int feat loop3"))

        #
        # Packet destined to unknown unicast is sent on the epg uplink ...
        #
        pkt_intra_epg_220_to_uplink = (
            Ether(src=self.pg0.remote_mac, dst="00:00:00:33:44:55") /
            IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) /
            Raw('\xa5' * 100))

        self.send_and_expect_bridged(self.pg0,
                                     pkt_intra_epg_220_to_uplink * 65,
                                     self.pg4)
        # ... and nowhere else
        self.pg1.get_capture(0, timeout=0.1)
        self.pg1.assert_nothing_captured(remark="Flood onto other VMS")

        pkt_intra_epg_221_to_uplink = (
            Ether(src=self.pg2.remote_mac, dst="00:00:00:33:44:66") /
            IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) /
            Raw('\xa5' * 100))

        self.send_and_expect_bridged(self.pg2,
                                     pkt_intra_epg_221_to_uplink * 65,
                                     self.pg5)

        #
        # Packets from the uplink are forwarded in the absence of a contract
        #
        pkt_intra_epg_220_from_uplink = (
            Ether(src="00:00:00:33:44:55", dst=self.pg0.remote_mac) /
            IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) /
            Raw('\xa5' * 100))

        self.send_and_expect_bridged(self.pg4,
                                     pkt_intra_epg_220_from_uplink * 65,
                                     self.pg0)

        #
        # in the absence of policy, endpoints in the same EPG
        # can communicate
        #
        pkt_intra_epg = (
            Ether(src=self.pg0.remote_mac, dst=self.pg1.remote_mac) /
            IP(src=eps[0].ip, dst=eps[1].ip) / UDP(sport=1234, dport=1234) /
            Raw('\xa5' * 100))

        self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)

        #
        # in the abscense of policy, endpoints in the different EPG
        # cannot communicate
        #
        pkt_inter_epg_220_to_221 = (
            Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac) /
            IP(src=eps[0].ip, dst=eps[2].ip) / UDP(sport=1234, dport=1234) /
            Raw('\xa5' * 100))
        pkt_inter_epg_221_to_220 = (
            Ether(src=self.pg2.remote_mac, dst=self.pg0.remote_mac) /
            IP(src=eps[2].ip, dst=eps[0].ip) / UDP(sport=1234, dport=1234) /
            Raw('\xa5' * 100))
        pkt_inter_epg_220_to_222 = (
            Ether(src=self.pg0.remote_mac, dst=self.router_mac) /
            IP(src=eps[0].ip, dst=eps[3].ip) / UDP(sport=1234, dport=1234) /
            Raw('\xa5' * 100))

        self.send_and_assert_no_replies(self.pg0,
                                        pkt_inter_epg_220_to_221 * 65)
        self.send_and_assert_no_replies(self.pg0,
                                        pkt_inter_epg_220_to_222 * 65)

        #
        # A uni-directional contract from EPG 220 -> 221
        #
        c1 = VppGbpContract(self, 220, 221, 0)
        c1.add_vpp_config()

        self.send_and_expect_bridged(self.pg0, pkt_inter_epg_220_to_221 * 65,
                                     self.pg2)
        self.send_and_assert_no_replies(self.pg0,
                                        pkt_inter_epg_220_to_222 * 65)

        #
        # contract for the return direction
        #
        c2 = VppGbpContract(self, 221, 220, 0)
        c2.add_vpp_config()

        self.send_and_expect_bridged(self.pg0, pkt_inter_epg_220_to_221 * 65,
                                     self.pg2)
        self.send_and_expect_bridged(self.pg2, pkt_inter_epg_221_to_220 * 65,
                                     self.pg0)

        #
        # check that inter group is still disabled for the groups
        # not in the contract.
        #
        self.send_and_assert_no_replies(self.pg0,
                                        pkt_inter_epg_220_to_222 * 65)

        #
        # A uni-directional contract from EPG 220 -> 222 'L3 routed'
        #
        c3 = VppGbpContract(self, 220, 222, 0)
        c3.add_vpp_config()

        self.logger.info(self.vapi.cli("sh gbp contract"))

        self.send_and_expect_routed(self.pg0, pkt_inter_epg_220_to_222 * 65,
                                    self.pg3, self.router_mac)

        #
        # remove both contracts, traffic stops in both directions
        #
        c2.remove_vpp_config()
        c1.remove_vpp_config()
        c3.remove_vpp_config()

        self.send_and_assert_no_replies(self.pg2,
                                        pkt_inter_epg_221_to_220 * 65)
        self.send_and_assert_no_replies(self.pg0,
                                        pkt_inter_epg_220_to_221 * 65)
        self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)

        #
        # EPs to the outside world
        #

        # in the EP's RD an external subnet via the NAT EPG's recirc
        se1 = VppGbpSubnet(self,
                           0,
                           "0.0.0.0",
                           0,
                           is_internal=False,
                           sw_if_index=recirc_nat.recirc.sw_if_index,
                           epg=epg_nat.epg)
        se1.add_vpp_config()
        se2 = VppGbpSubnet(self,
                           0,
                           "11.0.0.0",
                           8,
                           is_internal=False,
                           sw_if_index=recirc_nat.recirc.sw_if_index,
                           epg=epg_nat.epg)
        se2.add_vpp_config()
        se16 = VppGbpSubnet(self,
                            0,
                            "::",
                            0,
                            is_internal=False,
                            sw_if_index=recirc_nat.recirc.sw_if_index,
                            epg=epg_nat.epg,
                            is_ip6=True)
        se16.add_vpp_config()
        # in the NAT RD an external subnet via the NAT EPG's uplink
        se3 = VppGbpSubnet(self,
                           20,
                           "0.0.0.0",
                           0,
                           is_internal=False,
                           sw_if_index=epg_nat.uplink.sw_if_index,
                           epg=epg_nat.epg)
        se36 = VppGbpSubnet(self,
                            20,
                            "::",
                            0,
                            is_internal=False,
                            sw_if_index=epg_nat.uplink.sw_if_index,
                            epg=epg_nat.epg,
                            is_ip6=True)
        se4 = VppGbpSubnet(self,
                           20,
                           "11.0.0.0",
                           8,
                           is_internal=False,
                           sw_if_index=epg_nat.uplink.sw_if_index,
                           epg=epg_nat.epg)
        se3.add_vpp_config()
        se36.add_vpp_config()
        se4.add_vpp_config()

        self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
        self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
        self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
        self.logger.info(self.vapi.cli("sh ip6 fib %s" % eps[4].floating_ip))

        #
        # From an EP to an outside addess: IN2OUT
        #
        pkt_inter_epg_220_to_global = (
            Ether(src=self.pg0.remote_mac, dst=self.router_mac) /
            IP(src=eps[0].ip, dst="1.1.1.1") / UDP(sport=1234, dport=1234) /
            Raw('\xa5' * 100))

        # no policy yet
        self.send_and_assert_no_replies(self.pg0,
                                        pkt_inter_epg_220_to_global * 65)

        c4 = VppGbpContract(self, 220, 333, 0)
        c4.add_vpp_config()

        self.send_and_expect_natted(self.pg0, pkt_inter_epg_220_to_global * 65,
                                    self.pg7, eps[0].floating_ip)

        pkt_inter_epg_220_to_global = (
            Ether(src=self.pg0.remote_mac, dst=self.router_mac) /
            IPv6(src=eps[4].ip, dst="6001::1") / UDP(sport=1234, dport=1234) /
            Raw('\xa5' * 100))

        self.send_and_expect_natted6(self.pg0,
                                     pkt_inter_epg_220_to_global * 65,
                                     self.pg7, eps[4].floating_ip)

        #
        # From a global address to an EP: OUT2IN
        #
        pkt_inter_epg_220_from_global = (
            Ether(src=self.router_mac, dst=self.pg0.remote_mac) /
            IP(dst=eps[0].floating_ip, src="1.1.1.1") /
            UDP(sport=1234, dport=1234) / Raw('\xa5' * 100))

        self.send_and_assert_no_replies(self.pg7,
                                        pkt_inter_epg_220_from_global * 65)

        c5 = VppGbpContract(self, 333, 220, 0)
        c5.add_vpp_config()

        self.send_and_expect_unnatted(self.pg7,
                                      pkt_inter_epg_220_from_global * 65,
                                      eps[0].itf, eps[0].ip)

        pkt_inter_epg_220_from_global = (
            Ether(src=self.router_mac, dst=self.pg0.remote_mac) /
            IPv6(dst=eps[4].floating_ip, src="6001::1") /
            UDP(sport=1234, dport=1234) / Raw('\xa5' * 100))

        self.send_and_expect_unnatted6(self.pg7,
                                       pkt_inter_epg_220_from_global * 65,
                                       eps[4].itf, eps[4].ip)

        #
        # From a local VM to another local VM using resp. public addresses:
        #  IN2OUT2IN
        #
        pkt_intra_epg_220_global = (
            Ether(src=self.pg0.remote_mac, dst=self.router_mac) /
            IP(src=eps[0].ip, dst=eps[1].floating_ip) /
            UDP(sport=1234, dport=1234) / Raw('\xa5' * 100))

        self.send_and_expect_double_natted(eps[0].itf,
                                           pkt_intra_epg_220_global * 65,
                                           eps[1].itf, eps[0].floating_ip,
                                           eps[1].ip)

        pkt_intra_epg_220_global = (
            Ether(src=self.pg4.remote_mac, dst=self.router_mac) /
            IPv6(src=eps[4].ip, dst=eps[5].floating_ip) /
            UDP(sport=1234, dport=1234) / Raw('\xa5' * 100))

        self.send_and_expect_double_natted6(eps[4].itf,
                                            pkt_intra_epg_220_global * 65,
                                            eps[5].itf, eps[4].floating_ip,
                                            eps[5].ip)

        #
        # cleanup
        #
        for ep in eps:
            # del static mappings for each EP from the 10/8 to 11/8 network
            if ep.af == AF_INET:
                self.vapi.nat44_add_del_static_mapping(ep.ip_n,
                                                       ep.floating_ip_n,
                                                       vrf_id=0,
                                                       addr_only=1,
                                                       is_add=0)
            else:
                self.vapi.nat66_add_del_static_mapping(ep.ip_n,
                                                       ep.floating_ip_n,
                                                       vrf_id=0,
                                                       is_add=0)

        for epg in epgs:
            # IP config on the BVI interfaces
            self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
                                                   epg.bvi_ip4_n,
                                                   32,
                                                   is_add=0)
            self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
                                                   epg.bvi_ip6_n,
                                                   128,
                                                   is_add=0,
                                                   is_ipv6=True)
            self.logger.info(self.vapi.cli("sh int addr"))

            epg.uplink.set_table_ip4(0)
            epg.uplink.set_table_ip6(0)

            if epg != epgs[0] and epg != epgs[3]:
                epg.bvi.set_table_ip4(0)
                epg.bvi.set_table_ip6(0)

                self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
                                                          is_inside=1,
                                                          is_add=0)
                self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
                                                  is_inside=1,
                                                  is_add=0)

        for recirc in recircs:
            recirc.recirc.set_table_ip4(0)
            recirc.recirc.set_table_ip6(0)

            self.vapi.nat44_interface_add_del_feature(
                recirc.recirc.sw_if_index, is_inside=0, is_add=0)
            self.vapi.nat66_add_del_interface(recirc.recirc.sw_if_index,
                                              is_inside=0,
                                              is_add=0)