aboutsummaryrefslogtreecommitdiffstats
path: root/test/test_p2p_ethernet.py
blob: 7cc6cdce48524b226f32e5e6be948cdf2e47e13d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
/*
 * Copyright (c) 2016 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @brief
 * The data-path object representing puntping the packet
 */

#include <vnet/dpo/dpo.h>

static dpo_id_t punt_dpos[DPO_PROTO_NUM];

const dpo_id_t *
punt_dpo_get (dpo_proto_t proto)
{
    dpo_set(&punt_dpos[proto], DPO_PUNT, proto, 1);

    return (&punt_dpos[proto]);
}

int
dpo_is_punt (const dpo_id_t *dpo)
{
    return (dpo->dpoi_type == DPO_PUNT);
}

static void
punt_dpo_lock (dpo_id_t *dpo)
{
    /*
     * not maintaining a lock count on the punt
     * more trouble than it's worth.
     * There always needs to be one around. no point it managaing its lifetime
     */
}
static void
punt_dpo_unlock (dpo_id_t *dpo)
{
}

static u8*
format_punt_dpo (u8 *s, va_list *ap)
{
    CLIB_UNUSED(index_t index) = va_arg(*ap, index_t);
    CLIB_UNUSED(u32 indent) = va_arg(*
#!/usr/bin/env python3
import random
import unittest
import datetime
import re

from scapy.packet import Raw
from scapy.layers.l2 import Ether
from scapy.layers.inet import IP, UDP
from scapy.layers.inet6 import IPv6

from framework import VppTestCase, VppTestRunner
from vpp_sub_interface import VppP2PSubint
from vpp_ip import DpoProto
from vpp_ip_route import VppIpRoute, VppRoutePath
from vpp_papi import mac_pton


class P2PEthernetAPI(VppTestCase):
    """P2P Ethernet tests"""

    p2p_sub_ifs = []

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

        # Create pg interfaces
        cls.create_pg_interfaces(range(4))

        # Set up all interfaces
        for i in cls.pg_interfaces:
            i.admin_up()

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

    def create_p2p_ethernet(self, parent_if, sub_id, remote_mac):
        p2p = VppP2PSubint(self, parent_if, sub_id, mac_pton(remote_mac))
        self.p2p_sub_ifs.append(p2p)

    def delete_p2p_ethernet(self, parent_if, remote_mac):
        self.vapi.p2p_ethernet_del(parent_if.sw_if_index,
                                   mac_pton(remote_mac))

    def test_api(self):
        """delete/create p2p subif"""
        self.logger.info("FFP_TEST_START_0000")

        self.create_p2p_ethernet(self.pg0, 1, "de:ad:00:00:00:01")
        self.create_p2p_ethernet(self.pg0, 2, "de:ad:00:00:00:02")
        intfs = self.vapi.cli("show interface")

        self.assertIn('pg0.1', intfs)
        self.assertIn('pg0.2', intfs)
        self.assertNotIn('pg0.5', intfs)

        # create pg2.5 subif
        self.create_p2p_ethernet(self.pg0, 5, "de:ad:00:00:00:ff")
        intfs = self.vapi.cli("show interface")
        self.assertIn('pg0.5', intfs)
        # delete pg2.5 subif
        self.delete_p2p_ethernet(self.pg0, "de:ad:00:00:00:ff")

        intfs = self.vapi.cli("show interface")

        self.assertIn('pg0.1', intfs)
        self.assertIn('pg0.2', intfs)
        self.assertNotIn('pg0.5', intfs)

        self.logger.info("FFP_TEST_FINISH_0000")

    def test_p2p_subif_creation_1k(self):
        """create 1k of p2p subifs"""
        self.logger.info("FFP_TEST_START_0001")

        macs = []
        clients = 1000
        mac = int("dead00000000", 16)

        for i in range(1, clients+1):
            try:
                macs.append(':'.join(re.findall('..', '{:02x}'.format(
                    mac+i))))
                self.vapi.p2p_ethernet_add(self.pg2.sw_if_index,
                                           mac_pton(macs[i-1]),
                                           i)
            except Exception:
                self.logger.info("Failed to create subif %d %s" % (
                    i, macs[i-1]))
                raise

        intfs = self.vapi.cli("show interface").split("\n")
        count = 0
        for intf in intfs:
            if intf.startswith('pg2.'):
                count += 1
        self.assertEqual(count, clients)

        self.logger.info("FFP_TEST_FINISH_0001")


class P2PEthernetIPV6(VppTestCase):
    """P2P Ethernet IPv6 tests"""

    p2p_sub_ifs = []
    packets = []

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

        # Create pg interfaces
        cls.create_pg_interfaces(range(3))

        # Packet sizes
        cls.pg_if_packet_sizes = [64, 512, 1518, 9018]

        # Set up all interfaces
        for i in cls.pg_interfaces:
            i.admin_up()

        cls.pg0.generate_remote_hosts(3)
        cls.pg0.configure_ipv6_neighbors()

        cls.pg1.config_ip6()
        cls.pg1.generate_remote_hosts(3)
        cls.pg1.configure_ipv6_neighbors()
        cls.pg1.disable_ipv6_ra()

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

    def setUp(self):
        super(P2PEthernetIPV6, self).setUp()
        for p in self.packets:
            self.packets.remove(p)
        self.p2p_sub_ifs.append(
            self.create_p2p_ethernet(self.pg0, 1,
                                     self.pg0._remote_hosts[0].mac))
        self.p2p_sub_ifs.append(
            self.create_p2p_ethernet(self.pg0, 2,
                                     self.pg0._remote_hosts[1].mac))
        self.vapi.cli("trace add p2p-ethernet-input 50")

    def tearDown(self):
        while len(self.p2p_sub_ifs):
            p2p = self.p2p_sub_ifs.pop()
            self.delete_p2p_ethernet(p2p)

        super(P2PEthernetIPV6, self).tearDown()

    def create_p2p_ethernet(self, parent_if, sub_id, remote_mac):
        p2p = VppP2PSubint(self, parent_if, sub_id, mac_pton(remote_mac))
        p2p.admin_up()
        p2p.config_ip6()
        p2p.disable_ipv6_ra()
        return p2p

    def delete_p2p_ethernet(self, p2p):
        p2p.unconfig_ip6()
        p2p.admin_down()
        self.vapi.p2p_ethernet_del(p2p.parent.sw_if_index,
                                   p2p.p2p_remote_mac)

    def create_stream(self, src_mac=None, dst_mac=None,
                      src_ip=None, dst_ip=None, size=None):
        pkt_size = size
        if size is None:
            pkt_size = random.choice(self.pg_if_packet_sizes)
        p = Ether(src=src_mac, dst=dst_mac)
        p /= IPv6(src=src_ip, dst=dst_ip)
        p /= (UDP(sport=1234, dport=4321) / Raw(b'\xa5' * 20))
        self.extend_packet(p, pkt_size)
        return p

    def send_packets(self, src_if=None, dst_if=None, packets=None, count=None):
        self.pg_enable_capture([dst_if])
        if packets is None:
            packets = self.packets
        src_if.add_stream(packets)
        self.pg_start()
        if count is None:
            count = len(packets)
        return dst_if.get_capture(count)

    def test_no_p2p_subif(self):
        """standard routing without p2p subinterfaces"""
        self.logger.info("FFP_TEST_START_0001")

        route_8000 = VppIpRoute(self, "8000::", 64,
                                [VppRoutePath(self.pg0.remote_ip6,
                                              self.pg0.sw_if_index)])
        route_8000.add_vpp_config()

        self.packets = [(Ether(dst=self.pg1.local_mac,
                               src=self.pg1.remote_mac) /
                         IPv6(src="3001::1", dst="8000::100") /
                         UDP(sport=1234, dport=1234) /
                         Raw(b'\xa5' * 100))]
        self.send_packets(self.pg1, self.pg0)

        self.logger.info("FFP_TEST_FINISH_0001")

    def test_ip6_rx_p2p_subif(self):
        """receive ipv6 packet via p2p subinterface"""
        self.logger.info("FFP_TEST_START_0002")

        route_9001 = VppIpRoute(self, "9001::", 64,
                                [VppRoutePath(self.pg1.remote_ip6,
                                              self.pg1.sw_if_index)])
        route_9001.add_vpp_config()

        self.packets.append(
            self.create_stream(src_mac=self.pg0._remote_hosts[0].mac,
                               dst_mac=self.pg0.local_mac,
                               src_ip=self.p2p_sub_ifs[0].remote_ip6,
                               dst_ip="9001::100"))

        self.send_packets(self.pg0, self.pg1, self.packets)
        self.assert_packet_counter_equal('p2p-ethernet-input', 1)

        route_9001.remove_vpp_config()
        self.logger.info("FFP_TEST_FINISH_0002")

    def test_ip6_rx_p2p_subif_route(self):
        """route rx ip6 packet not matching p2p subinterface"""
        self.logger.info("FFP_TEST_START_0003")

        self.pg0.config_ip6()

        route_3 = VppIpRoute(self, "9000::", 64,
                             [VppRoutePath(self.pg1._remote_hosts[0].ip6,
                                           self.pg1.sw_if_index)])
        route_3.add_vpp_config()

        self.packets.append(
            self.create_stream(src_mac="02:03:00:00:ff:ff",
                               dst_mac=self.pg0.local_mac,
                               src_ip="a000::100",
                               dst_ip="9000::100"))

        self.send_packets(self.pg0, self.pg1)

        self.pg0.unconfig_ip6()

        route_3.remove_vpp_config()

        self.logger.info("FFP_TEST_FINISH_0003")

    def test_ip6_rx_p2p_subif_drop(self):
        """drop rx packet not matching p2p subinterface"""
        self.logger.info("FFP_TEST_START_0004")

        route_9001 = VppIpRoute(self, "9000::", 64,
                                [VppRoutePath(self.pg1._remote_hosts[0].ip6,
                                              self.pg1.sw_if_index)])
        route_9001.add_vpp_config()

        self.packets.append(
            self.create_stream(src_mac="02:03:00:00:ff:ff",
                               dst_mac=self.pg0.local_mac,
                               src_ip="a000::100",
                               dst_ip="9000::100"))

        # no packet received
        self.send_packets(self.pg0, self.pg1, count=0)
        self.logger.info("FFP_TEST_FINISH_0004")

    def test_ip6_tx_p2p_subif(self):
        """send packet via p2p subinterface"""
        self.logger.info("FFP_TEST_START_0005")

        route_8000 = VppIpRoute(self, "8000::", 64,
                                [VppRoutePath(self.pg0.remote_ip6,
                                              self.pg0.sw_if_index)])
        route_8000.add_vpp_config()
        route_8001 = VppIpRoute(self, "8001::", 64,
                                [VppRoutePath(
                                    self.p2p_sub_ifs[0].remote_ip6,
                                    self.p2p_sub_ifs[0].sw_if_index)])
        route_8001.add_vpp_config()
        route_8002 = VppIpRoute(self, "8002::", 64,
                                [VppRoutePath(
                                    self.p2p_sub_ifs[1].remote_ip6,
                                    self.p2p_sub_ifs[1].sw_if_index)])
        route_8002.add_vpp_config()

        for i in range(0, 3):
            self.packets.append(
                self.create_stream(src_mac=self.pg1.remote_mac,
                                   dst_mac=self.pg1.local_mac,
                                   src_ip=self.pg1.remote_ip6,
                                   dst_ip="800%d::100" % i))

        self.send_packets(self.pg1, self.pg0, count=3)

        route_8000.remove_vpp_config()
        route_8001.remove_vpp_config()
        route_8002.remove_vpp_config()

        self.logger.info("FFP_TEST_FINISH_0005")

    def test_ip6_tx_p2p_subif_drop(self):
        """drop tx ip6 packet not matching p2p subinterface"""
        self.logger.info("FFP_TEST_START_0006")

        self.packets.append(
            self.create_stream(src_mac="02:03:00:00:ff:ff",
                               dst_mac=self.pg0.local_mac,
                               src_ip="a000::100",
                               dst_ip="9000::100"))

        # no packet received
        self.send_packets(self.pg0, self.pg1, count=0)
        self.logger.info("FFP_TEST_FINISH_0006")


class P2PEthernetIPV4(VppTestCase):
    """P2P Ethernet IPv4 tests"""

    p2p_sub_ifs = []
    packets = []

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

        # Create pg interfaces
        cls.create_pg_interfaces(range(3))

        # Packet sizes
        cls.pg_if_packet_sizes = [64, 512, 1518, 9018]

        # Set up all interfaces
        for i in cls.pg_interfaces:
            i.admin_up()

        cls.pg0.config_ip4()
        cls.pg0.generate_remote_hosts(5)
        cls.pg0.configure_ipv4_neighbors()

        cls.pg1.config_ip4()
        cls.pg1.generate_remote_hosts(5)
        cls.pg1.configure_ipv4_neighbors()

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

    def setUp(self):
        super(P2PEthernetIPV4, self).setUp()
        for p in self.packets:
            self.packets.remove(p)
        self.p2p_sub_ifs.append(
            self.create_p2p_ethernet(self.pg0, 1,
                                     self.pg0._remote_hosts[0].mac))
        self.p2p_sub_ifs.append(
            self.create_p2p_ethernet(self.pg0, 2,
                                     self.pg0._remote_hosts[1].mac))
        self.vapi.cli("trace add p2p-ethernet-input 50")

    def tearDown(self):
        while len(self.p2p_sub_ifs):
            p2p = self.p2p_sub_ifs.pop()
            self.delete_p2p_ethernet(p2p)
        super(P2PEthernetIPV4, self).tearDown()

    def create_stream(self, src_mac=None, dst_mac=None,
                      src_ip=None, dst_ip=None, size=None):
        pkt_size = size
        if size is None:
            pkt_size = random.choice(self.pg_if_packet_sizes)
        p = Ether(src=src_mac, dst=dst_mac)
        p /= IP(src=src_ip, dst=dst_ip)
        p /= (UDP(sport=1234, dport=4321) / Raw(b'\xa5' * 20))
        self.extend_packet(p, pkt_size)
        return p

    def send_packets(self, src_if=None, dst_if=None, packets=None, count=None):
        self.pg_enable_capture([dst_if])
        if packets is None:
            packets = self.packets
        src_if.add_stream(packets)
        self.pg_start()
        if count is None:
            count = len(packets)
        return dst_if.get_capture(count)

    def create_p2p_ethernet(self, parent_if, sub_id, remote_mac):
        p2p = VppP2PSubint(self, parent_if, sub_id, mac_pton(remote_mac))
        p2p.admin_up()
        p2p.config_ip4()
        return p2p

    def delete_p2p_ethernet(self, p2p):
        p2p.unconfig_ip4()
        p2p.admin_down()
        self.vapi.p2p_ethernet_del(p2p.parent.sw_if_index,
                                   p2p.p2p_remote_mac)

    def test_ip4_rx_p2p_subif(self):
        """receive ipv4 packet via p2p subinterface"""
        self.logger.info("FFP_TEST_START_0002")

        route_9000 = VppIpRoute(self, "9.0.0.0", 16,
                                [VppRoutePath(self.pg1.remote_ip4,
                                              self.pg1.sw_if_index)])
        route_9000.add_vpp_config()

        self.packets.append(
            self.create_stream(src_mac=self.pg0._remote_hosts[0].mac,
                               dst_mac=self.pg0.local_mac,
                               src_ip=self.p2p_sub_ifs[0].remote_ip4,
                               dst_ip="9.0.0.100"))

        self.send_packets(self.pg0, self.pg1, self.packets)

        self.assert_packet_counter_equal('p2p-ethernet-input', 1)

        route_9000.remove_vpp_config()
        self.logger.info("FFP_TEST_FINISH_0002")

    def test_ip4_rx_p2p_subif_route(self):
        """route rx packet not matching p2p subinterface"""
        self.logger.info("FFP_TEST_START_0003")

        route_9001 = VppIpRoute(self, "9.0.0.0", 24,
                                [VppRoutePath(self.pg1.remote_ip4,
                                              self.pg1.sw_if_index)])
        route_9001.add_vpp_config()

        self.packets.append(
            self.create_stream(src_mac="02:01:00:00:ff:ff",
                               dst_mac=self.pg0.local_mac,
                               src_ip="8.0.0.100",
                               dst_ip="9.0.0.100"))

        self.send_packets(self.pg0, self.pg1)

        route_9001.remove_vpp_config()

        self.logger.info("FFP_TEST_FINISH_0003")

    def test_ip4_tx_p2p_subif(self):
        """send ip4 packet via p2p subinterface"""
        self.logger.info("FFP_TEST_START_0005")

        route_9100 = VppIpRoute(self, "9.1.0.100", 24,
                                [VppRoutePath(self.pg0.remote_ip4,
                                              self.pg0.sw_if_index,
                                              )])
        route_9100.add_vpp_config()
        route_9200 = VppIpRoute(self, "9.2.0.100", 24,
                                [VppRoutePath(self.p2p_sub_ifs[0].remote_ip4,
                                              self.p2p_sub_ifs[0].sw_if_index,
                                              )])
        route_9200.add_vpp_config()
        route_9300 = VppIpRoute(self, "9.3.0.100", 24,
                                [VppRoutePath(self.p2p_sub_ifs[1].remote_ip4,
                                              self.p2p_sub_ifs[1].sw_if_index
                                              )])
        route_9300.add_vpp_config()

        for i in range(0, 3):
            self.packets.append(
                self.create_stream(src_mac=self.pg1.remote_mac,
                                   dst_mac=self.pg1.local_mac,
                                   src_ip=self.pg1.remote_ip4,
                                   dst_ip="9.%d.0.100" % (i+1)))

        self.send_packets(self.pg1, self.pg0)

        # route_7000.remove_vpp_config()
        route_9100.remove_vpp_config()
        route_9200.remove_vpp_config()
        route_9300.remove_vpp_config()

        self.logger.info("FFP_TEST_FINISH_0005")

    def test_ip4_tx_p2p_subif_drop(self):
        """drop tx ip4 packet not matching p2p subinterface"""
        self.logger.info("FFP_TEST_START_0006")

        self.packets.append(
            self.create_stream(src_mac="02:01:00:00:ff:ff",
                               dst_mac=self.pg0.local_mac,
                               src_ip="8.0.0.100",
                               dst_ip="9.0.0.100"))

        # no packet received
        self.send_packets(self.pg0, self.pg1, count=0)
        self.logger.info("FFP_TEST_FINISH_0006")


if __name__ == '__main__':
    unittest.main(testRunner=VppTestRunner)