Exemplo n.º 1
0
class ShortLivedConnectionsRecipe(CommonHWSubConfigMixin, BaseEnrtRecipe):
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))

    perf_tests = Param(default=("TCP_RR", "TCP_CRR"))
    ip_versions = Param(default=("ipv4",))
    perf_parallel_streams = IntParam(default=2)
    perf_msg_sizes = ListParam(default=[1000, 5000, 7000, 10000, 12000])

    def test_wide_configuration(self):
        host1, host2 = self.matched.host1, self.matched.host2

        configuration = super().test_wide_configuration()
        configuration.test_wide_devices = [host1.eth0, host2.eth0]

        net_addr = "192.168.101"
        for i, host in enumerate([host1, host2], 10):
            host.eth0.down()
            host.eth0.ip_add(ipaddress(net_addr + "." + str(i) + "/24"))
            host.eth0.up()

        self.wait_tentative_ips(configuration.test_wide_devices)

        return configuration

    def generate_test_wide_description(self, config):
        host1, host2 = self.matched.host1, self.matched.host2
        desc = super().generate_test_wide_description(config)
        desc += [
            "\n".join([
                "Configured {}.{}.ips = {}".format(
                    dev.host.hostid, dev.name, dev.ips
                )
                for dev in config.test_wide_devices
            ])
        ]
        return desc

    def test_wide_deconfiguration(self, config):
        del config.test_wide_devices

        super().test_wide_deconfiguration(config)

    def generate_perf_endpoints(self, config):
        return [(self.matched.host1.eth0, self.matched.host2.eth0)]

    @property
    def mtu_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]
Exemplo n.º 2
0
class PingFloodRecipe(PingTestAndEvaluate):
    driver = StrParam(default='ixgbe')
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    src_addr = StrParam(default="192.168.1.1/24")
    dst_addr = StrParam(default="192.168.1.2/24")
    count = IntParam(default=100)
    interval = StrParam(default=0.2)
    size = IntParam(mandatory=False)
    mtu = IntParam(mandatory=False)

    def test(self):
        host1, host2 = self.matched.host1, self.matched.host2

        host1.eth0.ip_add(ipaddress(self.params.src_addr))
        host2.eth0.ip_add(ipaddress(self.params.dst_addr))

        if "mtu" in self.params:
            host1.eth0.mtu = self.params.mtu
            host2.eth0.mtu = self.params.mtu

        host1.eth0.up()
        host2.eth0.up()

        ip1 = host1.eth0.ips[0]
        ip2 = host2.eth0.ips[0]
        cn = self.params.count
        iv = self.params.interval
        if "size" in self.params:
            sz = self.params.size
        else:
            sz = None

        pcfg = PingConf(host1, ip1, host2, ip2, count=cn, interval=iv, size=sz)
        result = self.ping_test([pcfg])
        self.ping_evaluate_and_report(pcfg, result)
Exemplo n.º 3
0
class SitTunnelRecipe(MTUHWConfigMixin, PauseFramesHWConfigMixin,
                      BaseTunnelRecipe):
    """
    This class implements a recipe that configures a simple SIT tunnel between
    two hosts.

    .. code-block:: none

                        .--------.
                 .------| switch |-----.
                 |      '--------'     |
                 |                     |
         .-------|------.      .-------|------.
         |    .--'-.    |      |    .--'-.    |
         |    |eth0|    |      |    |eth0|    |
         |    '----'    |      |    '----'    |
         |      | |     |      |      | |     |
         |  ----' '---  |      |  ----' '---  |
         |  sit tunnel  |      |  sit tunnel  |
         |  ----------  |      |  ----------  |
         |              |      |              |
         |    host1     |      |    host2     |
         '--------------'      '--------------'

    The actual test machinery is implemented in the :any:`BaseEnrtRecipe` class.

    The test wide configuration is implemented in the :any:`BaseTunnelRecipe`
    class.

    The recipe provides additional parameter:

        :param tunnel_mode:
            this parameter specifies the mode of the SIT tunnel, can be any of
            the **any**, **ip6ip6**, **ipip** or **mplsip**
    """

    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    tunnel_mode = ChoiceParam(type=StrParam,
                              choices=set(["any", "ip6ip", "ipip", "mplsip"]),
                              mandatory=True)

    def configure_underlying_network(self, configuration):
        """
        The underlying network for the tunnel consists of the Ethernet
        devices on the matched hosts.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        for i, device in enumerate([host1.eth0, host2.eth0]):
            device.ip_add(ipaddress("192.168.101." + str(i + 1) + "/24"))
            device.up()
            configuration.test_wide_devices.append(device)

        configuration.tunnel_endpoints = (host1.eth0, host2.eth0)

    def create_tunnel(self, configuration):
        """
        The SIT tunnel devices are configured with IPv4 and IPv6 addresses
        of individual networks. Routes are configured accordingly.
        """
        endpoint1, endpoint2 = configuration.tunnel_endpoints
        m1 = endpoint1.netns
        m2 = endpoint2.netns
        ip_filter = {"family": AF_INET}
        endpoint1_ip = endpoint1.ips_filter(**ip_filter)[0]
        endpoint2_ip = endpoint2.ips_filter(**ip_filter)[0]

        a_ip4 = Ip4Address("192.168.6.2/24")
        a_net4 = "192.168.6.0/24"
        b_ip4 = Ip4Address("192.168.7.2/24")
        b_net4 = "192.168.7.0/24"

        a_ip6 = Ip6Address("6001:db8:ac10:fe01::2/64")
        a_net6 = "6001:db8:ac10:fe01::0/64"
        b_ip6 = Ip6Address("7001:db8:ac10:fe01::2/64")
        b_net6 = "7001:db8:ac10:fe01::0/64"

        m1.sit_tunnel = SitDevice(local=endpoint1_ip,
                                  remote=endpoint2_ip,
                                  mode=self.params.tunnel_mode)
        m2.sit_tunnel = SitDevice(local=endpoint2_ip,
                                  remote=endpoint1_ip,
                                  mode=self.params.tunnel_mode)

        # A
        m1.sit_tunnel.up()
        m1.sit_tunnel.ip_add(a_ip4)
        m1.sit_tunnel.ip_add(a_ip6)
        m1.run("ip -4 route add {} dev {}".format(b_net4, m1.sit_tunnel.name))
        m1.run("ip -6 route add {} dev {}".format(b_net6, m1.sit_tunnel.name))

        # B
        m2.sit_tunnel.up()
        m2.sit_tunnel.ip_add(b_ip4)
        m2.sit_tunnel.ip_add(b_ip6)
        m2.run("ip -4 route add {} dev {}".format(a_net4, m2.sit_tunnel.name))
        m2.run("ip -6 route add {} dev {}".format(a_net6, m2.sit_tunnel.name))

        configuration.tunnel_devices.extend([m1.sit_tunnel, m2.sit_tunnel])
        self.wait_tentative_ips(configuration.tunnel_devices)

    def generate_ping_endpoints(self, config):
        """
        The ping endpoints for this recipe are simply the tunnel endpoints

        Returned as::

            [PingEndpoints(self.matched.host1.sit_tunnel, self.matched.host2.sit_tunnel)]
        """
        return [
            PingEndpoints(self.matched.host1.sit_tunnel,
                          self.matched.host2.sit_tunnel)
        ]

    def get_packet_assert_config(self, ping_config):
        """
        The packet assert test configuration contains filter for ip6 protocol
        and grep patterns to match the ICMP or ICMP6 echo requests encapsulated
        by SIT.
        """
        ip_filter = {"family": AF_INET}
        m1_carrier = self.matched.host1.eth0
        m2_carrier = self.matched.host2.eth0
        m1_carrier_ip = m1_carrier.ips_filter(**ip_filter)[0]
        m2_carrier_ip = m2_carrier.ips_filter(**ip_filter)[0]

        ip1 = ping_config.client_bind
        ip2 = ping_config.destination_address

        pa_kwargs = {}
        pa_kwargs["p_filter"] = "ip host {}".format(m1_carrier_ip)

        # TODO: handle mplsip mode
        if isinstance(ip2, Ip4Address):
            grep_pattern = [
                "IP {} > {}: IP {} > {}: ICMP".format(m1_carrier_ip,
                                                      m2_carrier_ip, ip1, ip2)
            ]

        elif isinstance(ip2, Ip6Address):
            grep_pattern = [
                "IP {} > {}: IP6 {} > {}: ICMP6".format(
                    m1_carrier_ip, m2_carrier_ip, ip1, ip2)
            ]

        pa_kwargs["grep_for"] = grep_pattern

        if ping_config.count:
            pa_kwargs["p_min"] = ping_config.count
        m2 = ping_config.destination
        pa_config = PacketAssertConf(m2, m2_carrier, **pa_kwargs)

        return pa_config

    @property
    def pause_frames_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def mtu_hw_config_dev_list(self):
        return [self.matched.host1.sit_tunnel, self.matched.host2.sit_tunnel]
Exemplo n.º 4
0
class VlansOverBondRecipe(PerfReversibleFlowMixin, VlanPingEvaluatorMixin,
    CommonHWSubConfigMixin, OffloadSubConfigMixin,
    BaremetalEnrtRecipe):
    """
    This recipe implements Enrt testing for a network scenario that looks
    as follows

    .. code-block:: none

                              .--------.
                .-------------+ switch +--------.
                |         .---+        |        |
                |         |   '--------'        |
          .-----|---------|----.                |
          | .---'--.  .---'--. |             .--'---.
        .-|-| eth0 |--| eth1 |-|-.   .-------| eth0 |------.
        | | '------'  '------' | |   |       '------'      |
        | |        bond0       | |   |      /   |    \     |
        | '-------/--|--\------' |   | vlan0  vlan1  vlan2 |
        |        /   |   \       |   | id=10  id=20  id=30 |
        |   vlan0  vlan1  vlan2  |   |                     |
        |   id=10  id=20  id=30  |   |                     |
        |                        |   |                     |
        |          host1         |   |        host2        |
        '------------------------'   '---------------------'

    The recipe provides additional recipe parameters to configure the bonding
    device.

    :param bonding_mode:
        (mandatory test parameter) the bonding mode to be configured on
        the bond0 device
    :param miimon_value:
        (mandatory test parameter) the miimon interval to be configured
        on the bond0 device

    All sub configurations are included via Mixin classes.

    The actual test machinery is implemented in the :any:`BaseEnrtRecipe` class.
    """
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))
    host1.eth1 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    vlan0_id = IntParam(default=10)
    vlan1_id = IntParam(default=20)
    vlan2_id = IntParam(default=30)

    offload_combinations = Param(default=(
        dict(gro="on", gso="on", tso="on", tx="on"),
        dict(gro="off", gso="on", tso="on", tx="on"),
        dict(gro="on", gso="off", tso="off", tx="on"),
        dict(gro="on", gso="on", tso="off", tx="off")))

    bonding_mode = StrParam(mandatory=True)
    miimon_value = IntParam(mandatory=True)

    def test_wide_configuration(self):
        """
        Test wide configuration for this recipe involves creating one bonding
        device on the first host. This device bonds two NICs matched by the
        recipe. The bonding mode and miimon interval is configured on the
        bonding device according to the recipe parameters. Then three
        VLAN (802.1Q) tunnels are created on top of the bonding device on the
        first host and on the matched NIC on the second host. The tunnels are
        configured with VLAN ids from vlan0_id, vlan1_id and vlan2_id params (by
        default: 10, 20, 30).

        An IPv4 and IPv6 address is configured on each tunnel endpoint.

        | host1.vlan0 = 192.168.10.1/24 and fc00:0:0:1::1/64
        | host1.vlan1 = 192.168.20.1/24 and fc00:0:0:2::1/64
        | host1.vlan2 = 192.168.30.1/24 and fc00:0:0:3::1/64

        | host2.vlan0 = 192.168.10.2/24 and fc00:0:0:1::2/64
        | host2.vlan1 = 192.168.20.2/24 and fc00:0:0:2::2/64
        | host2.vlan2 = 192.168.30.2/24 and fc00:0:0:3::2/64
        """
        host1, host2 = self.matched.host1, self.matched.host2

        host1.bond0 = BondDevice(mode=self.params.bonding_mode,
            miimon=self.params.miimon_value)
        for dev in [host1.eth0, host1.eth1]:
            dev.down()
            host1.bond0.slave_add(dev)

        host1.vlan0 = VlanDevice(realdev=host1.bond0, vlan_id=self.params.vlan0_id)
        host1.vlan1 = VlanDevice(realdev=host1.bond0, vlan_id=self.params.vlan1_id)
        host1.vlan2 = VlanDevice(realdev=host1.bond0, vlan_id=self.params.vlan2_id)
        host2.vlan0 = VlanDevice(realdev=host2.eth0, vlan_id=self.params.vlan0_id)
        host2.vlan1 = VlanDevice(realdev=host2.eth0, vlan_id=self.params.vlan1_id)
        host2.vlan2 = VlanDevice(realdev=host2.eth0, vlan_id=self.params.vlan2_id)

        configuration = super().test_wide_configuration()
        configuration.test_wide_devices = []
        for host in [host1, host2]:
            configuration.test_wide_devices.extend([host.vlan0,
                host.vlan1, host.vlan2])
        configuration.test_wide_devices.append(host1.bond0)

        net_addr = "192.168"
        net_addr6 = "fc00:0:0"

        for i, host in enumerate([host1, host2]):
            host.vlan0.ip_add(ipaddress('{}.10.{}/24'.format(net_addr, i+1)))
            host.vlan1.ip_add(ipaddress('{}.20.{}/24'.format(net_addr, i+1)))
            host.vlan2.ip_add(ipaddress('{}.30.{}/24'.format(net_addr, i+1)))
            host.vlan0.ip_add(ipaddress('{}:1::{}/64'.format(net_addr6, i+1)))
            host.vlan1.ip_add(ipaddress('{}:2::{}/64'.format(net_addr6, i+1)))
            host.vlan2.ip_add(ipaddress('{}:3::{}/64'.format(net_addr6, i+1)))

        for dev in [host1.eth0, host1.eth1, host1.bond0, host1.vlan0,
            host1.vlan1, host1.vlan2, host2.eth0, host2.vlan0,
            host2.vlan1, host2.vlan2]:
            dev.up()

        self.wait_tentative_ips(configuration.test_wide_devices)

        return configuration

    def generate_test_wide_description(self, config):
        """
        Test wide description is extended with the configured VLAN tunnels,
        their IP addresses and the bonding device configuration.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        desc = super().generate_test_wide_description(config)
        desc += [
            "\n".join([
                "Configured {}.{}.ips = {}".format(
                    dev.host.hostid, dev.name, dev.ips
                )
                for dev in config.test_wide_devices if isinstance(dev,
                    Vlan)
            ]),
            "\n".join([
                "Configured {}.{}.vlan_id = {}".format(
                    dev.host.hostid, dev.name, dev.vlan_id
                )
                for dev in config.test_wide_devices if isinstance(dev,
                    Vlan)
            ]),
            "\n".join([
                "Configured {}.{}.realdev = {}".format(
                    dev.host.hostid, dev.name,
                    '.'.join([dev.host.hostid, dev.realdev.name])
                )
                for dev in config.test_wide_devices if isinstance(dev,
                    Vlan)
            ]),
            "Configured {}.{}.slaves = {}".format(
                host1.hostid, host1.bond0.name,
                ['.'.join([host1.hostid, slave.name])
                for slave in host1.bond0.slaves]
            ),
            "Configured {}.{}.mode = {}".format(
                host1.hostid, host1.bond0.name,
                host1.bond0.mode
            ),
            "Configured {}.{}.miimon = {}".format(
                host1.hostid, host1.bond0.name,
                host1.bond0.miimon
            )
        ]
        return desc

    def test_wide_deconfiguration(self, config):
        del config.test_wide_devices

        super().test_wide_deconfiguration(config)

    def generate_ping_endpoints(self, config):
        """
        The ping endpoints for this recipe are the matching VLAN tunnel
        endpoints of the hosts.

        Returned as::

            [PingEndpoints(host1.vlan0, host2.vlan0),
             PingEndpoints(host1.vlan1, host2.vlan1),
             PingEndpoints(host1.vlan2, host2.vlan2)]
        """
        host1, host2 = self.matched.host1, self.matched.host2

        return [PingEndpoints(host1.vlan0, host2.vlan0),
                PingEndpoints(host1.vlan1, host2.vlan1),
                PingEndpoints(host1.vlan2, host2.vlan2)]

    def generate_perf_endpoints(self, config):
        """
        The perf endpoints for this recipe are the VLAN tunnel endpoints with
        VLAN id from parameter vlan_ids[0] (by default: 10):

        host1.vlan0 and host2.vlan0

        Returned as::

            [(self.matched.host1.vlan0, self.matched.host2.vlan0)]
        """
        return [(self.matched.host1.vlan0, self.matched.host2.vlan0)]

    @property
    def offload_nics(self):
        """
        The `offload_nics` property value for this scenario is a list of the
        physical devices carrying data of the configured VLAN tunnels:

        host1.eth0, host1.eth1 and host2.eth0

        For detailed explanation of this property see :any:`OffloadSubConfigMixin`
        class and :any:`OffloadSubConfigMixin.offload_nics`.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        return [host1.eth0, host1.eth1, host2.eth0]

    @property
    def mtu_hw_config_dev_list(self):
        """
        The `mtu_hw_config_dev_list` property value for this scenario is a
        list of all configured VLAN tunnel devices and the underlying bonding
        or physical devices:

        | host1.bond0, host1.vlan0, host1.vlan1, host1.vlan2
        | host2.eth0, host2.vlan0, host2.vlan1, host2.vlan2

        For detailed explanation of this property see :any:`MTUHWConfigMixin`
        class and :any:`MTUHWConfigMixin.mtu_hw_config_dev_list`.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        result = []
        for host in [host1, host2]:
            for dev in [host.vlan0, host.vlan1, host.vlan2]:
                result.append(dev)
        result.extend([host1.bond0, host2.eth0])
        return result

    @property
    def coalescing_hw_config_dev_list(self):
        """
        The `coalescing_hw_config_dev_list` property value for this scenario
        is a list of the physical devices carrying data of the configured
        VLAN tunnels:

        host1.eth0, host1.eth1 and host2.eth0

        For detailed explanation of this property see :any:`CoalescingHWConfigMixin`
        class and :any:`CoalescingHWConfigMixin.coalescing_hw_config_dev_list`.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        return [host1.eth0, host1.eth1, host2.eth0]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        """
        The `dev_interrupt_hw_config_dev_list` property value for this scenario
        is a list of the physical devices carrying data of the configured
        VLAN tunnels:

        host1.eth0, host1.eth1 and host2.eth0

        For detailed explanation of this property see :any:`DevInterruptHWConfigMixin`
        class and :any:`DevInterruptHWConfigMixin.dev_interrupt_hw_config_dev_list`.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        return [host1.eth0, host1.eth1, host2.eth0]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        """
        The `parallel_stream_qdisc_hw_config_dev_list` property value for
        this scenario is a list of the physical devices carrying data of the
        configured VLAN tunnels:

        host1.eth0, host1.eth1 and host2.eth0

        For detailed explanation of this property see
        :any:`ParallelStreamQDiscHWConfigMixin` class and
        :any:`ParallelStreamQDiscHWConfigMixin.parallel_stream_qdisc_hw_config_dev_list`.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        return [host1.eth0, host1.eth1, host2.eth0]

    @property
    def pause_frames_dev_list(self):
        """
        The `pause_frames_dev_list` property value for this scenario is a list
        of the physical devices carrying data of the configured VLAN tunnels:

        host1.eth0, host1.eth1 and host2.eth0

        For detailed explanation of this property see
        :any:`PauseFramesHWConfigMixin` and
        :any:`PauseFramesHWConfigMixin.pause_frames_dev_list`.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        return [host1.eth0, host1.eth1, host2.eth0]
Exemplo n.º 5
0
class VxlanGpeTunnelRecipe(
    PauseFramesHWConfigMixin, OffloadSubConfigMixin, BaseTunnelRecipe
):
    """
    This class implements a recipe that configures a simple Vxlan GPE
    tunnel between two hosts.

    .. code-block:: none

                        .--------.
                 .------| switch |-----.
                 |      '--------'     |
                 |                     |
         .-------|------.      .-------|------.
         |    .--'-.    |      |    .--'-.    |
         |    |eth0|    |      |    |eth0|    |
         |    '----'    |      |    '----'    |
         |      | |     |      |      | |     |
         |  ----' '---  |      |  ----' '---  |
         | vxlan tunnel |      | vxlan tunnel |
         |  ----------  |      |  ----------  |
         |              |      |              |
         |    host1     |      |    host2     |
         '--------------'      '--------------'

    The actual test machinery is implemented in the :any:`BaseEnrtRecipe` class.

    The test wide configuration is implemented in the :any:`BaseTunnelRecipe`
    class.

    The recipe provides additional parameter:

        :param carrier_ipversion:
            This parameter specifies whether IPv4 or IPv6 addresses are
            used for the underlying (carrier) network. The value is either
            **ipv4** or **ipv6**
    """

    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    offload_combinations = Param(
        default=(
            dict(gro="on", gso="on", tso="on"),
            dict(gro="off", gso="on", tso="on"),
            dict(gro="on", gso="off", tso="off"),
            dict(gro="on", gso="on", tso="off"),
        )
    )

    # TODO: ping over IPv6 does not work yet
    ip_versions = Param(default=("ipv4",))
    # TODO: IPv6 does not work as carrier network
    carrier_ipversion = ChoiceParam(type=StrParam, choices=set(["ipv4"]))

    def configure_underlying_network(self, configuration):
        """
        The underlying network for the tunnel consists of the Ethernet
        devices on the matched hosts.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        for i, device in enumerate([host1.eth0, host2.eth0]):
            if self.params.carrier_ipversion == "ipv4":
                device.ip_add(ipaddress("192.168.101." + str(i + 1) + "/24"))
            else:
                device.ip_add(ipaddress("fc00::" + str(i + 1) + "/64"))
            device.up()
            configuration.test_wide_devices.append(device)

        self.wait_tentative_ips(configuration.test_wide_devices)
        configuration.tunnel_endpoints = (host1.eth0, host2.eth0)

    def create_tunnel(self, configuration):
        """
        The Vxlan tunnel devices are created with external flag specified
        so that the encapsulation can be defined externally by routes.

        The devices are configured to use VXLAN-GPE.

        Routes for IPv4 and IPv6 networks to be tunneled through the Vxlan are
        added.

        IPv4 and IPv6 addresses of the tunneled networks are configured on
        the loopback devices of the matched hosts.

        """
        endpoint1, endpoint2 = configuration.tunnel_endpoints
        m1 = endpoint1.netns
        m2 = endpoint2.netns
        if self.params.carrier_ipversion == "ipv4":
            ip_filter = {"family": AF_INET}
        else:
            ip_filter = {"family": AF_INET6, "is_link_local": False}

        endpoint1_ip = endpoint1.ips_filter(**ip_filter)[0]
        endpoint2_ip = endpoint2.ips_filter(**ip_filter)[0]

        m1_dummy_ip = ipaddress("172.16.10.1/32")
        m1_dummy_ip6 = ipaddress("fc00:a::1/128")
        m2_dummy_ip = ipaddress("172.16.20.1/32")
        m2_dummy_ip6 = ipaddress("fc00:b::1/128")

        m1.vxlan_tunnel = VxlanDevice(external=True, gpe=True, learning=0)
        m2.vxlan_tunnel = VxlanDevice(external=True, gpe=True, learning=0)
        m1.lo = LoopbackDevice()
        m2.lo = LoopbackDevice()

        # A
        m1.lo.ip_add(m1_dummy_ip)
        m1.lo.ip_add(m1_dummy_ip6)
        m1.vxlan_tunnel.mtu = 1400
        m1.vxlan_tunnel.up()

        # B
        m2.lo.ip_add(m2_dummy_ip)
        m2.lo.ip_add(m2_dummy_ip6)
        m2.vxlan_tunnel.mtu = 1400
        m2.vxlan_tunnel.up()

        tunnel_id = 1234
        encap = "ip" if self.params.carrier_ipversion == "ipv4" else "ip6"
        m1.run(
            "ip route add {} encap {} id {} dst {} dev {}".format(
                m2_dummy_ip, encap, tunnel_id, endpoint2_ip, m1.vxlan_tunnel.name
            )
        )
        m2.run(
            "ip route add {} encap {} id {} dst {} dev {}".format(
                m1_dummy_ip, encap, tunnel_id, endpoint1_ip, m2.vxlan_tunnel.name
            )
        )
        m1.run(
            "ip route add {} encap {} id {} dst {} dev {}".format(
                m2_dummy_ip6, encap, tunnel_id, endpoint2_ip, m1.vxlan_tunnel.name
            )
        )
        m2.run(
            "ip route add {} encap {} id {} dst {} dev {}".format(
                m1_dummy_ip6, encap, tunnel_id, endpoint1_ip, m2.vxlan_tunnel.name
            )
        )

        configuration.tunnel_devices.extend([m1.vxlan_tunnel, m2.vxlan_tunnel])
        self.wait_tentative_ips([m1.lo, m2.lo])

    def generate_ping_endpoints(self, config):
        """
        The ping endpoints for this recipe are the loopback devices that
        are configured with IP addresses of the tunnelled networks.

        Returned as::

            [PingEndpoints(self.matched.host1.lo, self.matched.host2.lo)]
        """
        return [PingEndpoints(self.matched.host1.lo, self.matched.host2.lo)]

    def get_packet_assert_config(self, ping_config):
        """
        The packet assert test configuration contains filter for source
        and destination addresses matching the carrier network with udp
        header bits specific to VXLAN tunneling. The grep patterns match
        the ICMP or ICMP6 echo requests encapsulated by Vxlan with
        VXLAN-GPE extension.
        """
        if self.params.carrier_ipversion == "ipv4":
            ip_filter = {"family": AF_INET}
        else:
            ip_filter = {"family": AF_INET6, "is_link_local": False}

        m1_carrier = self.matched.host1.eth0
        m2_carrier = self.matched.host2.eth0
        m1_carrier_ip = m1_carrier.ips_filter(**ip_filter)[0]
        m2_carrier_ip = m2_carrier.ips_filter(**ip_filter)[0]

        ip1 = ping_config.client_bind
        ip2 = ping_config.destination_address

        pa_kwargs = {}
        pa_kwargs["p_filter"] = "src {} and dst {}".format(m2_carrier_ip, m1_carrier_ip)

        if isinstance(ip2, Ip4Address):
            grep_pattern = "VXLAN-GPE.*IP {} > {}: ICMP echo reply".format(ip2, ip1)
        elif isinstance(ip2, Ip6Address):
            grep_pattern = "VXLAN-GPE.*IP6 {} > {}: ICMP6, echo reply".format(ip2, ip1)
        else:
            raise Exception("The destination address is nor IPv4 or IPv6 address")

        pa_kwargs["grep_for"] = [grep_pattern]

        if ping_config.count:
            pa_kwargs["p_min"] = ping_config.count
        m2 = ping_config.destination
        pa_config = PacketAssertConf(m2, m2_carrier, **pa_kwargs)

        return pa_config

    @property
    def offload_nics(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def pause_frames_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]
Exemplo n.º 6
0
class VlansRecipe(CommonHWSubConfigMixin, OffloadSubConfigMixin,
                  BaseEnrtRecipe):
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    offload_combinations = Param(
        default=(dict(gro="on", gso="on", tso="on", tx="on", rx="on"),
                 dict(gro="off", gso="on", tso="on", tx="on", rx="on"),
                 dict(gro="on", gso="off", tso="off", tx="on", rx="on"),
                 dict(gro="on", gso="on", tso="off", tx="off", rx="on"),
                 dict(gro="on", gso="on", tso="on", tx="on", rx="off")))

    def test_wide_configuration(self):
        host1, host2 = self.matched.host1, self.matched.host2

        host1.eth0.down()
        host2.eth0.down()

        host1.vlan0 = VlanDevice(realdev=host1.eth0, vlan_id=10)
        host1.vlan1 = VlanDevice(realdev=host1.eth0, vlan_id=20)
        host1.vlan2 = VlanDevice(realdev=host1.eth0, vlan_id=30)
        host2.vlan0 = VlanDevice(realdev=host2.eth0, vlan_id=10)
        host2.vlan1 = VlanDevice(realdev=host2.eth0, vlan_id=20)
        host2.vlan2 = VlanDevice(realdev=host2.eth0, vlan_id=30)

        configuration = super().test_wide_configuration()
        configuration.test_wide_devices = []
        for host in [host1, host2]:
            configuration.test_wide_devices.extend(
                [host.vlan0, host.vlan1, host.vlan2])

        net_addr = "192.168"
        net_addr6 = "fc00:0:0"

        for i, host in enumerate([host1, host2]):
            host.vlan0.ip_add(
                ipaddress(net_addr + '.10' + '.' + str(i + 1) + "/24"))
            host.vlan0.ip_add(
                ipaddress(net_addr6 + ":1::" + str(i + 1) + "/64"))
            host.vlan1.ip_add(
                ipaddress(net_addr + '.20' + '.' + str(i + 1) + "/24"))
            host.vlan1.ip_add(
                ipaddress(net_addr6 + ":2::" + str(i + 1) + "/64"))
            host.vlan2.ip_add(
                ipaddress(net_addr + '.30' + '.' + str(i + 1) + "/24"))
            host.vlan2.ip_add(
                ipaddress(net_addr6 + ":3::" + str(i + 1) + "/64"))
            for dev in [host.eth0, host.vlan0, host.vlan1, host.vlan2]:
                dev.up()

        self.wait_tentative_ips(configuration.test_wide_devices)

        return configuration

    def generate_test_wide_description(self, config):
        host1, host2 = self.matched.host1, self.matched.host2
        desc = super().generate_test_wide_description(config)
        desc += [
            "\n".join([
                "Configured {}.{}.ips = {}".format(dev.host.hostid, dev.name,
                                                   dev.ips)
                for dev in config.test_wide_devices
            ]), "\n".join([
                "Configured {}.{}.vlan_id = {}".format(dev.host.hostid,
                                                       dev.name, dev.vlan_id)
                for dev in config.test_wide_devices
            ]), "\n".join([
                "Configured {}.{}.realdev = {}".format(
                    dev.host.hostid, dev.name,
                    '.'.join([dev.host.hostid, dev.realdev.name]))
                for dev in config.test_wide_devices
            ])
        ]
        return desc

    def test_wide_deconfiguration(self, config):
        del config.test_wide_devices

        super().test_wide_deconfiguration(config)

    def generate_ping_endpoints(self, config):
        host1, host2 = self.matched.host1, self.matched.host2
        result = []
        for src in [host1.vlan0, host1.vlan1, host1.vlan2]:
            for dst in [host2.vlan0, host2.vlan1, host2.vlan2]:
                result += [(src, dst)]
        return result

    def generate_perf_endpoints(self, config):
        return [(self.matched.host1.vlan0, self.matched.host2.vlan0)]

    def wait_tentative_ips(self, devices):
        def condition():
            return all(
                [not ip.is_tentative for dev in devices for ip in dev.ips])

        self.ctl.wait_for_condition(condition, timeout=5)

    @property
    def offload_nics(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def mtu_hw_config_dev_list(self):
        result = []
        for host in [self.matched.host1, self.matched.host2]:
            for dev in [host.eth0, host.vlan0, host.vlan1, host.vlan2]:
                result.append(dev)
        return result

    @property
    def coalescing_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    def do_ping_tests(self, recipe_config):
        for ping_config in self.generate_ping_configurations(recipe_config):
            exp_fail = []
            for pconf in ping_config:
                cond = self.vlan_id_same(pconf.client_bind,
                                         pconf.destination_address)
                exp_fail.append(cond)
            result = self.ping_test(ping_config, exp_fail)
            self.ping_evaluate_and_report(ping_config, result)

    def ping_test(self, ping_config, exp_fail):
        results = {}

        running_ping_array = []
        for pingconf, fail in zip(ping_config, exp_fail):
            ping, client = self.ping_init(pingconf)
            running_ping = client.prepare_job(ping, fail=fail)
            running_ping.start(bg=True)
            running_ping_array.append((pingconf, running_ping))

        for _, pingjob in running_ping_array:
            try:
                pingjob.wait()
            finally:
                pingjob.kill()

        for pingconf, pingjob in running_ping_array:
            result = pingjob.result
            passed = pingjob.passed
            results[pingconf] = (result, passed)

        return results

    def single_ping_evaluate_and_report(self, ping_config, result):
        fmt = "From: <{0.client.hostid} ({0.client_bind})> To: " \
              "<{0.destination.hostid} ({0.destination_address})>"
        description = fmt.format(ping_config)
        if result[0].get("rate", 0) > 50:
            message = "Ping successful --- " + description
            self.add_result(result[1], message, result[0])
        else:
            message = "Ping unsuccessful --- " + description
            self.add_result(result[1], message, result[0])

    def vlan_id_same(self, src_addr, dst_addr):
        host1, host2 = self.matched.host1, self.matched.host2
        devs = []
        for dev in (host1.devices + host2.devices):
            if src_addr in dev.ips or dst_addr in dev.ips:
                devs.append(dev)
        try:
            return devs[0].vlan_id != devs[1].vlan_id
        except (IndexError, AttributeError):
            return False
Exemplo n.º 7
0
class BondRecipe(PerfReversibleFlowMixin, CommonHWSubConfigMixin,
                 OffloadSubConfigMixin, BaremetalEnrtRecipe):
    """
    This recipe implements Enrt testing for a network scenario that looks
    as follows

    .. code-block:: none

                                    .--------.
                   .----------------+        |
                   |        .-------+ switch +-------.
                   |        |       '--------'       |
             .-------------------.                   |
             |     | bond0  |    |                   |
             | .---'--. .---'--. |               .---'--.
        .----|-| eth0 |-| eth1 |-|----.     .----| eth0 |----.
        |    | '------' '------' |    |     |    '------'    |
        |    '-------------------'    |     |                |
        |                             |     |                |
        |            host1            |     |      host2     |
        '-----------------------------'     '----------------'

    The recipe provides additional recipe parameters to configure the bonding
    device.

        :param bonding_mode:
            (mandatory test parameter) the bonding mode to be configured on
            the bond0 device.
        :param miimon_value:
            (mandatory test parameter) the miimon interval to be configured
            on the bond0 device.

    All sub configurations are included via Mixin classes.

    The actual test machinery is implemented in the :any:`BaseEnrtRecipe` class.
    """
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))
    host1.eth1 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    offload_combinations = Param(
        default=(dict(gro="on", gso="on", tso="on", tx="on"),
                 dict(gro="off", gso="on", tso="on", tx="on"),
                 dict(gro="on", gso="off", tso="off", tx="on"),
                 dict(gro="on", gso="on", tso="off", tx="off")))

    bonding_mode = StrParam(mandatory=True)
    miimon_value = IntParam(mandatory=True)

    def test_wide_configuration(self):
        """
        Test wide configuration for this recipe involves creating a bonding
        device using the two matched physical devices as slaves on host1.
        The bonding mode and miimon interval is configured on the bonding device
        according to the recipe parameters. IPv4 and IPv6 addresses are added to
        the bonding device and to the matched ethernet device on host2.

        | host1.bond0 = 192.168.101.1/24 and fc00::1/64
        | host2.eth0 = 192.168.101.2/24 and fc00::2/64
        """

        host1, host2 = self.matched.host1, self.matched.host2
        host1.bond0 = BondDevice(mode=self.params.bonding_mode,
                                 miimon=self.params.miimon_value)
        configuration = super().test_wide_configuration()
        configuration.test_wide_devices = []

        for dev in [host1.eth0, host1.eth1]:
            dev.down()
            host1.bond0.slave_add(dev)

        net_addr = "192.168.101"
        net_addr6 = "fc00:0:0:0"
        for i, dev in enumerate([host1.bond0, host2.eth0]):
            dev.ip_add(ipaddress(net_addr + "." + str(i + 1) + "/24"))
            dev.ip_add(ipaddress(net_addr6 + "::" + str(i + 1) + "/64"))
            configuration.test_wide_devices.append(dev)

        for dev in [host1.eth0, host1.eth1, host1.bond0, host2.eth0]:
            dev.up()

        self.wait_tentative_ips(configuration.test_wide_devices)

        return configuration

    def generate_test_wide_description(self, config):
        """
        Test wide description is extended with the configured IP addresses, the
        configured bonding slave interfaces, bonding mode and the miimon interval.
        """

        host1, host2 = self.matched.host1, self.matched.host2
        desc = super().generate_test_wide_description(config)
        desc += [
            "\n".join([
                "Configured {}.{}.ips = {}".format(dev.host.hostid, dev.name,
                                                   dev.ips)
                for dev in config.test_wide_devices
            ]), "Configured {}.{}.slaves = {}".format(
                host1.hostid, host1.bond0.name, [
                    '.'.join([host1.hostid, slave.name])
                    for slave in host1.bond0.slaves
                ]),
            "Configured {}.{}.mode = {}".format(host1.hostid, host1.bond0.name,
                                                host1.bond0.mode),
            "Configured {}.{}.miimon = {}".format(host1.hostid,
                                                  host1.bond0.name,
                                                  host1.bond0.miimon)
        ]
        return desc

    def test_wide_deconfiguration(self, config):
        del config.test_wide_devices

        super().test_wide_deconfiguration(config)

    def generate_ping_endpoints(self, config):
        """
        The ping endpoints for this recipe are the configured bonding device on
        host1 and the matched ethernet device on host2.

        Returned as::

            [PingEndpoints(self.matched.host1.bond0, self.matched.host2.eth0)
        """
        return [
            PingEndpoints(self.matched.host1.bond0, self.matched.host2.eth0)
        ]

    def generate_perf_endpoints(self, config):
        """
        The perf endpoints for this recipe are the configured bonding device on
        host1 and the matched ethernet device on host2. The traffic egresses
        the bonding device.

        | host1.bond0
        | host2.eth0

        Returned as::

            [(self.matched.host1.bond0, self.matched.host2.eth0)]

        """
        return [(self.matched.host1.bond0, self.matched.host2.eth0)]

    @property
    def offload_nics(self):
        """
        The `offload_nics` property value for this scenario is a list containing
        the configured bonding device on host1 and the matched ethernet device
        on host2.

        | host1.bond0
        | host2.eth0

        For detailed explanation of this property see :any:`OffloadSubConfigMixin`
        class and :any:`OffloadSubConfigMixin.offload_nics`.
        """
        return [self.matched.host1.bond0, self.matched.host2.eth0]

    @property
    def mtu_hw_config_dev_list(self):
        """
        The `mtu_hw_config_dev_list` property value for this scenario is a list
        containing the configured bonding device on host1 and the matched ethernet
        device on host2.

        | host1.bond0
        | host2.eth0

        For detailed explanation of this property see :any:`MTUHWConfigMixin`
        class and :any:`MTUHWConfigMixin.mtu_hw_config_dev_list`.
        """
        return [self.matched.host1.bond0, self.matched.host2.eth0]

    @property
    def coalescing_hw_config_dev_list(self):
        """
        The `coalescing_hw_config_dev_list` property value for this scenario is a
        list containing the matched physical devices used to create the bonding
        device on host1 and the matched ethernet device on host2.

        | host1.eth0, host.eth1
        | host2.eth0

        For detailed explanation of this property see :any:`CoalescingHWConfigMixin`
        class and :any:`CoalescingHWConfigMixin.coalescing_hw_config_dev_list`.
        """
        return [
            self.matched.host1.eth0, self.matched.host1.eth1,
            self.matched.host2.eth0
        ]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        """
        The `dev_interrupt_hw_config_dev_list` property value for this scenario
        is a list containing the matched physical devices used to create the
        bonding device on host1 and the matched ethernet device on host2.

        | host1.eth0, host1.eth1
        | host2.eth0

        For detailed explanation of this property see
        :any:`DevInterruptHWConfigMixin` class and
        :any:`CoalescingHWConfigMixin.coalescing_hw_config_dev_list`.
        """
        return [
            self.matched.host1.eth0, self.matched.host1.eth1,
            self.matched.host2.eth0
        ]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        """
        The `parallel_stream_qdisc_hw_config_dev_list` property value for this
        scenario is a list containing the matched physical devices used to create
        the bonding device on host1 and the matched ethernet device on host2.

        | host1.eth0, host.eth1
        | host2.eth0

        For detailed explanation of this property see
        :any:`ParallelStreamQDiscHWConfigMixin` class and
        :any:`ParallelStreamQDiscHWConfigMixin.parallel_stream_qdisc_hw_config_dev_list`.
        """
        return [
            self.matched.host1.eth0, self.matched.host1.eth1,
            self.matched.host2.eth0
        ]

    @property
    def pause_frames_dev_list(self):
        """
        The `pause_frames_dev_list` property value for this scenario is a list
        containing the matched physical devices used to create the bonding
        device on host1 and the matched ethernet device on host2.

        | host1.eth0, host.eth1
        | host2.eth0

        For detailed explanation of this property see
        :any:`PauseFramesHWConfigMixin` and
        :any:`PauseFramesHWConfigMixin.pause_frames_dev_list`.
        """
        return [
            self.matched.host1.eth0, self.matched.host1.eth1,
            self.matched.host2.eth0
        ]
Exemplo n.º 8
0
class GreOvsTunnelRecipe(PauseFramesHWConfigMixin, OffloadSubConfigMixin,
                         BaseTunnelRecipe):
    """
    This class implements a recipe that configures a simple GRE tunnel using
    OpenVSwitch between two hosts.

    .. code-block:: none

                            .--------.
                 .----------| switch |-------.
                 |          '--------'       |
                 |                           |
         .-------|----------.        .-------|----------.
         |    .--'-.        |        |    .--'-.        |
         |    |eth0|        |        |    |eth0|        |
         |    '----'        |        |    '----'        |
         | .----| |-------. |        | .----| |-------. |
         | |    | |   OvS | |        | |    | |   OvS | |
         | |    | |       | |        | |    | |       | |
         | | ---' '---    | |        | | ---' '---    | |
         | | gre tunnel   | |        | | gre tunnel   | |
         | | ----------   | |        | | ----------   | |
         | '--------------' |        | '--------------' |
         |                  |        |                  |
         |      host1       |        |       host2      |
         '------------------'        '------------------'

    The actual test machinery is implemented in the :any:`BaseEnrtRecipe` class.

    The test wide configuration is implemented in the :any:`BaseTunnelRecipe`
    class.
    """

    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    offload_combinations = Param(default=(
        dict(gro="on", gso="on", tso="on"),
        dict(gro="off", gso="on", tso="on"),
        dict(gro="on", gso="off", tso="off"),
        dict(gro="on", gso="on", tso="off"),
    ))

    def configure_underlying_network(self, configuration):
        """
        The underlying network for the tunnel consists of the Ethernet
        devices on the matched hosts.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        for i, device in enumerate([host1.eth0, host2.eth0]):
            device.ip_add(ipaddress("192.168.101." + str(i + 1) + "/24"))
            device.up()
            configuration.test_wide_devices.append(device)

        self.wait_tentative_ips(configuration.test_wide_devices)
        configuration.tunnel_endpoints = (host1.eth0, host2.eth0)

    def create_tunnel(self, configuration):
        """
        OvS bridges are created on each of the matched hosts with two ports.
        One port as an integration port and another port of type GRE acting
        as a tunnel interface connecting tunneled networks.

        Integration ports are configured with IPv4 and IPv6 addresses
        of the tunneled networks.
        """
        endpoint1, endpoint2 = configuration.tunnel_endpoints
        m1 = endpoint1.netns
        m2 = endpoint2.netns
        ip_filter = {"family": AF_INET}

        for i, (host, endpoint) in enumerate([(m1, endpoint2),
                                              (m2, endpoint1)]):
            remote_ip = endpoint.ips_filter(**ip_filter)[0]
            host.br0 = OvsBridgeDevice()
            host.int0 = host.br0.port_add(
                interface_options={"type": "internal"})
            configuration.tunnel_devices.append(host.int0)
            host.int0.ip_add(ipaddress("192.168.200." + str(i + 1) + "/24"))
            host.int0.ip_add(ipaddress("fc00::" + str(i + 1) + "/64"))

            host.br0.tunnel_add("gre", {"options:remote_ip": remote_ip})

            host.br0.up()
            host.int0.up()

        self.wait_tentative_ips(configuration.tunnel_devices)

    def generate_ping_endpoints(self, config):
        """
        The ping endpoints for this recipe are simply the tunnel endpoints

        Returned as::

            [PingEndpoints(self.matched.host1.int0, self.matched.host2.int0)]
        """
        return [
            PingEndpoints(self.matched.host1.int0, self.matched.host2.int0)
        ]

    def get_packet_assert_config(self, ping_config):
        """
        The packet assert test configuration contains filter for gre protocol
        and grep patterns to match the ICMP or ICMP6 echo requests.
        """
        ip_filter = {"family": AF_INET}
        m1_carrier = self.matched.host1.eth0
        m2_carrier = self.matched.host2.eth0
        m1_carrier_ip = m1_carrier.ips_filter(**ip_filter)[0]
        m2_carrier_ip = m2_carrier.ips_filter(**ip_filter)[0]

        ip1 = ping_config.client_bind
        ip2 = ping_config.destination_address

        pa_kwargs = {}
        pa_kwargs["p_filter"] = "proto gre"

        if isinstance(ip2, Ip4Address):
            pat1 = "{} > {}: GREv0, .* IP {} > {}: ICMP echo request".format(
                m1_carrier_ip, m2_carrier_ip, ip1, ip2)
            pat2 = "{} > {}: GREv0 \| {} > {}: ICMP echo request".format(
                m1_carrier_ip, m2_carrier_ip, ip1, ip2)
            grep_pattern = ["({})|({})".format(pat1, pat2)]
        elif isinstance(ip2, Ip6Address):
            pat1 = "{} > {}: GREv0, .* IP6 {} > {}: ICMP6, echo request".format(
                m1_carrier_ip, m2_carrier_ip, ip1, ip2)
            pat2 = "{} > {}: GREv0 \| {} > {}: ICMP6, echo request".format(
                m1_carrier_ip, m2_carrier_ip, ip1, ip2)
            grep_pattern = ["({})|({})".format(pat1, pat2)]
        else:
            raise Exception(
                "The destination address is nor IPv4 or IPv6 address")

        pa_kwargs["grep_for"] = grep_pattern

        if ping_config.count:
            pa_kwargs["p_min"] = ping_config.count
        m2 = ping_config.destination
        pa_config = PacketAssertConf(m2, m2_carrier, **pa_kwargs)

        return pa_config

    @property
    def offload_nics(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def pause_frames_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]
Exemplo n.º 9
0
class VirtualBridgeVlanInGuestRecipe(CommonHWSubConfigMixin,
                                     OffloadSubConfigMixin, BaseEnrtRecipe):
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))
    host1.tap0 = DeviceReq(label="to_guest")

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))

    guest1 = HostReq()
    guest1.eth0 = DeviceReq(label="to_guest")

    offload_combinations = Param(
        default=(dict(gro="on", gso="on", tso="on", tx="on", rx="on"),
                 dict(gro="off", gso="on", tso="on", tx="on", rx="on"),
                 dict(gro="on", gso="off", tso="off", tx="on", rx="on"),
                 dict(gro="on", gso="on", tso="off", tx="off", rx="on"),
                 dict(gro="on", gso="on", tso="on", tx="on", rx="off")))

    def test_wide_configuration(self):
        host1, host2, guest1 = (self.matched.host1, self.matched.host2,
                                self.matched.guest1)

        host1.br0 = BridgeDevice()
        for dev in [host1.eth0, host1.tap0]:
            dev.down()
            host1.br0.slave_add(dev)

        host2.eth0.down()
        guest1.eth0.down()

        host2.vlan0 = VlanDevice(realdev=host2.eth0, vlan_id=10)
        guest1.vlan0 = VlanDevice(realdev=guest1.eth0, vlan_id=10)

        configuration = super().test_wide_configuration()
        configuration.test_wide_devices = [
            guest1.vlan0, host1.br0, host2.vlan0
        ]

        net_addr_1 = "192.168.10"
        net_addr6_1 = "fc00:0:0:1"

        host1.br0.ip_add(ipaddress(net_addr_1 + ".1/24"))
        for i, machine in enumerate([host2, guest1]):
            machine.vlan0.ip_add(
                ipaddress(net_addr_1 + "." + str(i + 2) + "/24"))
            machine.vlan0.ip_add(
                ipaddress(net_addr6_1 + "::" + str(i + 2) + "/64"))

        for dev in [
                host1.eth0, host1.tap0, host1.br0, host2.eth0, host2.vlan0,
                guest1.eth0, guest1.vlan0
        ]:
            dev.up()

        self.wait_tentative_ips(configuration.test_wide_devices)

        return configuration

    def generate_test_wide_description(self, config):
        host1, host2 = self.matched.host1, self.matched.host2
        desc = super().generate_test_wide_description(config)
        desc += [
            "\n".join([
                "Configured {}.{}.ips = {}".format(dev.host.hostid, dev.name,
                                                   dev.ips)
                for dev in config.test_wide_devices
            ]), "\n".join([
                "Configured {}.{}.vlan_id = {}".format(dev.host.hostid,
                                                       dev.name, dev.vlan_id)
                for dev in config.test_wide_devices if isinstance(dev, Vlan)
            ]), "\n".join([
                "Configured {}.{}.realdev = {}".format(
                    dev.host.hostid, dev.name,
                    '.'.join([dev.host.hostid, dev.realdev.name]))
                for dev in config.test_wide_devices if isinstance(dev, Vlan)
            ]), "Configured {}.{}.slaves = {}".format(
                host1.hostid, host1.br0.name, [
                    '.'.join([host1.hostid, slave.name])
                    for slave in host1.br0.slaves
                ])
        ]
        return desc

    def test_wide_deconfiguration(self, config):
        del config.test_wide_devices

        super().test_wide_deconfiguration(config)

    def generate_ping_endpoints(self, config):
        return [(self.matched.guest1.vlan0, self.matched.host2.vlan0)]

    def generate_perf_endpoints(self, config):
        return [(self.matched.guest1.vlan0, self.matched.host2.vlan0)]

    def wait_tentative_ips(self, devices):
        def condition():
            return all(
                [not ip.is_tentative for dev in devices for ip in dev.ips])

        self.ctl.wait_for_condition(condition, timeout=5)

    @property
    def offload_nics(self):
        return [
            self.matched.host1.eth0, self.matched.host2.eth0,
            self.matched.guest1.eth0
        ]

    @property
    def mtu_hw_config_dev_list(self):
        host1, host2, guest1 = (self.matched.host1, self.matched.host2,
                                self.matched.guest1)
        return [
            host1.eth0, host1.tap0, host1.br0, guest1.eth0, host2.eth0,
            host2.vlan0, guest1.vlan0
        ]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]
Exemplo n.º 10
0
class VxlanRemoteRecipe(CommonHWSubConfigMixin, BaseEnrtRecipe):
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))

    def test_wide_configuration(self):
        host1, host2 = self.matched.host1, self.matched.host2

        for host in [host1, host2]:
            host.eth0.down()

        net_addr = "192.168.0"
        vxlan_net_addr = "192.168.100"
        vxlan_net_addr6 = "fc00:0:0:0"

        for i, host in enumerate([host1, host2]):
            host.eth0.ip_add(ipaddress(net_addr + "." + str(i + 1) + "/24"))
            host.vxlan0 = VxlanDevice(vxlan_id='1',
                                      remote=net_addr + "." + str(2 - i))

        configuration = super().test_wide_configuration()
        configuration.test_wide_devices = [
            host1.eth0, host1.vxlan0, host2.eth0, host2.vxlan0
        ]

        for i, host in enumerate([host1, host2]):
            host.vxlan0.realdev = host.eth0
            host.vxlan0.ip_add(
                ipaddress(vxlan_net_addr + "." + str(i + 1) + "/24"))
            host.vxlan0.ip_add(
                ipaddress(vxlan_net_addr6 + "::" + str(i + 1) + "/64"))

        for host in [host1, host2]:
            host.eth0.up()
            host.vxlan0.up()

        self.wait_tentative_ips(configuration.test_wide_devices)

        return configuration

    def generate_test_wide_description(self, config):
        host1, host2 = self.matched.host1, self.matched.host2
        desc = super().generate_test_wide_description(config)
        desc += [
            "\n".join([
                "Configured {}.{}.ips = {}".format(dev.host.hostid, dev.name,
                                                   dev.ips)
                for dev in config.test_wide_devices
            ]), "\n".join([
                "Configured {}.{}.vxlan_id = {}".format(
                    dev.host.hostid, dev.name, dev.vxlan_id)
                for dev in [host1.vxlan0, host2.vxlan0]
            ]), "\n".join([
                "Configured {}.{}.remote = {}".format(dev.host.hostid,
                                                      dev.name, dev.remote)
                for dev in [host1.vxlan0, host2.vxlan0]
            ]), "\n".join([
                "Configured {}.{}.realdev = {}".format(
                    dev.host.hostid, dev.name,
                    '.'.join([dev.host.hostid, dev.realdev.name]))
                for dev in [host1.vxlan0, host2.vxlan0]
            ])
        ]
        return desc

    def test_wide_deconfiguration(self, config):
        del config.test_wide_devices

        super().test_wide_deconfiguration(config)

    def generate_ping_endpoints(self, config):
        return [
            PingEndpoints(self.matched.host1.vxlan0, self.matched.host2.vxlan0)
        ]

    def generate_perf_endpoints(self, config):
        return [(self.matched.host1.vxlan0, self.matched.host2.vxlan0)]

    @property
    def mtu_hw_config_dev_list(self):
        return [self.matched.host1.vxlan0, self.matched.host2.vxlan0]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]
Exemplo n.º 11
0
class GeneveTunnelRecipe(PauseFramesHWConfigMixin, OffloadSubConfigMixin,
                         BaseTunnelRecipe):
    """
    This class implements a recipe that configures a simple Geneve tunnel
    between two hosts.

    .. code-block:: none

                        .--------.
                 .------| switch |-----.
                 |      '--------'     |
                 |                     |
         .-------|------.      .-------|------.
         |    .--'-.    |      |    .--'-.    |
         |    |eth0|    |      |    |eth0|    |
         |    '----'    |      |    '----'    |
         |      | |     |      |      | |     |
         |  ----' '---  |      |  ----' '---  |
         |  gnv tunnel  |      |  gnv tunnel  |
         |  ----------  |      |  ----------  |
         |              |      |              |
         |    host1     |      |    host2     |
         '--------------'      '--------------'

    The actual test machinery is implemented in the :any:`BaseEnrtRecipe` class.

    The test wide configuration is implemented in the :any:`BaseTunnelRecipe`
    class.

    The recipe provides additional parameter:

        :param carrier_ipversion:
            This parameter specifies whether IPv4 or IPv6 addresses are
            used for the underlying (carrier) network. The value is either
            **ipv4** or **ipv6**
    """

    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    offload_combinations = Param(default=(
        dict(gro="on", gso="on", tso="on"),
        dict(gro="off", gso="on", tso="on"),
        dict(gro="on", gso="off", tso="off"),
        dict(gro="on", gso="on", tso="off"),
    ))

    carrier_ipversion = ChoiceParam(type=StrParam,
                                    choices=set(["ipv4", "ipv6"]))

    def configure_underlying_network(self, configuration):
        """
        The underlying network for the tunnel consists of the Ethernet
        devices on the matched hosts.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        for i, device in enumerate([host1.eth0, host2.eth0]):
            if self.params.carrier_ipversion == "ipv4":
                device.ip_add(ipaddress("192.168.101." + str(i + 1) + "/24"))
            else:
                device.ip_add(ipaddress("fc00::" + str(i + 1) + "/64"))
            device.up()
            configuration.test_wide_devices.append(device)

        self.wait_tentative_ips(configuration.test_wide_devices)
        configuration.tunnel_endpoints = (host1.eth0, host2.eth0)

    def create_tunnel(self, configuration):
        """
        The Geneve tunnel devices are configured with IPv4 and IPv6 addresses.
        """
        endpoint1, endpoint2 = configuration.tunnel_endpoints
        m1 = endpoint1.netns
        m2 = endpoint2.netns
        if self.params.carrier_ipversion == "ipv4":
            ip_filter = {"family": AF_INET}
        else:
            ip_filter = {"family": AF_INET6, "is_link_local": False}

        endpoint1_ip = endpoint1.ips_filter(**ip_filter)[0]
        endpoint2_ip = endpoint2.ips_filter(**ip_filter)[0]

        a_ip4 = Ip4Address("20.0.0.10/8")
        b_ip4 = Ip4Address("20.0.0.20/8")

        a_ip6 = Ip6Address("fee0::10/64")
        b_ip6 = Ip6Address("fee0::20/64")

        m1.gnv_tunnel = GeneveDevice(remote=endpoint2_ip, id=1234)
        m2.gnv_tunnel = GeneveDevice(remote=endpoint1_ip, id=1234)

        # A
        m1.gnv_tunnel.mtu = 1400
        m1.gnv_tunnel.up()
        m1.gnv_tunnel.ip_add(a_ip4)
        m1.gnv_tunnel.ip_add(a_ip6)

        # B
        m2.gnv_tunnel.mtu = 1400
        m2.gnv_tunnel.up()
        m2.gnv_tunnel.ip_add(b_ip4)
        m2.gnv_tunnel.ip_add(b_ip6)

        configuration.tunnel_devices.extend([m1.gnv_tunnel, m2.gnv_tunnel])
        self.wait_tentative_ips(configuration.tunnel_devices)

    def generate_ping_endpoints(self, config):
        """
        The ping endpoints for this recipe are simply the tunnel endpoints

        Returned as::

            [PingEndpoints(self.matched.host1.gnv_tunnel, self.matched.host2.gnv_tunnel)]
        """
        return [
            PingEndpoints(self.matched.host1.gnv_tunnel,
                          self.matched.host2.gnv_tunnel)
        ]

    def get_packet_assert_config(self, ping_config):
        """
        The packet assert test configuration contains filter for ip6 protocol
        and grep patterns to match the ICMP or ICMP6 echo requests encapsulated
        by Geneve.
        """
        if self.params.carrier_ipversion == "ipv4":
            ip_filter = {"family": AF_INET}
        else:
            ip_filter = {"family": AF_INET6, "is_link_local": False}

        m1_carrier = self.matched.host1.eth0
        m2_carrier = self.matched.host2.eth0
        m1_carrier_ip = m1_carrier.ips_filter(**ip_filter)[0]
        m2_carrier_ip = m2_carrier.ips_filter(**ip_filter)[0]

        ip1 = ping_config.client_bind
        ip2 = ping_config.destination_address

        pa_kwargs = {}
        if self.params.carrier_ipversion == "ipv4":
            pa_kwargs["p_filter"] = "ip host {}".format(m1_carrier_ip)
            grep_pattern = "IP "
        else:
            pa_kwargs["p_filter"] = "ip6"
            grep_pattern = "IP6 "

        grep_pattern += "{}\.[0-9]+ > {}\.[0-9]+: Geneve.*vni 0x4d2: ".format(
            m1_carrier_ip, m2_carrier_ip)

        if isinstance(ip2, Ip4Address):
            grep_pattern += "IP {} > {}: ICMP".format(ip1, ip2)
        elif isinstance(ip2, Ip6Address):
            grep_pattern += "IP6 {} > {}: ICMP6".format(ip1, ip2)

        pa_kwargs["grep_for"] = [grep_pattern]

        if ping_config.count:
            pa_kwargs["p_min"] = ping_config.count
        m2 = ping_config.destination
        pa_config = PacketAssertConf(m2, m2_carrier, **pa_kwargs)

        return pa_config

    @property
    def offload_nics(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def pause_frames_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]
Exemplo n.º 12
0
class VxlanOvsTunnelRecipe(
    PauseFramesHWConfigMixin, OffloadSubConfigMixin, BaseTunnelRecipe
):
    """
    This class implements a recipe that configures a simple Vxlan tunnel using
    OpenVSwitch between two hosts.

    .. code-block:: none

                            .--------.
                 .----------| switch |-------.
                 |          '--------'       |
                 |                           |
         .-------|----------.        .-------|----------.
         |    .--'-.        |        |    .--'-.        |
         |    |eth0|        |        |    |eth0|        |
         |    '----'        |        |    '----'        |
         | .----| |-------. |        | .----| |-------. |
         | |    | |   OvS | |        | |    | |   OvS | |
         | |    | |       | |        | |    | |       | |
         | | ---' '------ | |        | | ---' '------ | |
         | | vxlan tunnel | |        | | vxlan tunnel | |
         | | ------------ | |        | | ------------ | |
         | '--------------' |        | '--------------' |
         |                  |        |                  |
         |      host1       |        |       host2      |
         '------------------'        '------------------'

    The actual test machinery is implemented in the :any:`BaseEnrtRecipe` class.

    The test wide configuration is implemented in the :any:`BaseTunnelRecipe`
    class.
    """

    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    offload_combinations = Param(
        default=(
            dict(gro="on", gso="on", tso="on"),
            dict(gro="off", gso="on", tso="on"),
            dict(gro="on", gso="off", tso="off"),
            dict(gro="on", gso="on", tso="off"),
        )
    )

    def configure_underlying_network(self, configuration):
        """
        The underlying network for the tunnel consists of the Ethernet
        devices on the matched hosts.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        for i, device in enumerate([host1.eth0, host2.eth0]):
            device.ip_add(ipaddress("192.168.101." + str(i + 1) + "/24"))
            device.up()
            configuration.test_wide_devices.append(device)

        self.wait_tentative_ips(configuration.test_wide_devices)
        configuration.tunnel_endpoints = (host1.eth0, host2.eth0)

    def create_tunnel(self, configuration):
        """
        OvS bridges are created on each of the matched hosts with two ports.
        One port as an integration port and another port of type VXLAN acting
        as a tunnel interface connecting tunneled networks.

        Integration ports are configured with IPv4 and IPv6 addresses
        of the tunneled networks.
        """
        endpoint1, endpoint2 = configuration.tunnel_endpoints
        m1 = endpoint1.netns
        m2 = endpoint2.netns
        ip_filter = {"family": AF_INET}

        for i, (host, endpoint) in enumerate([(m1, endpoint2), (m2, endpoint1)]):
            remote_ip = endpoint.ips_filter(**ip_filter)[0]
            host.br0 = OvsBridgeDevice()
            host.int0 = host.br0.port_add(
                interface_options={"type": "internal", "ofport_request": 5}
            )
            configuration.tunnel_devices.append(host.int0)
            host.int0.ip_add(ipaddress("192.168.200." + str(i + 1) + "/24"))
            host.int0.ip_add(ipaddress("fc00::" + str(i + 1) + "/64"))

            host.br0.tunnel_add(
                "vxlan",
                {
                    "options:remote_ip": remote_ip,
                    "options:key": "flow",
                    "ofport_request": 10,
                },
            )

            host.br0.flows_add(
                [
                    "table=0,in_port=5,actions=set_field:1234->tun_id,output:10",
                    "table=0,in_port=10,tun_id=1234,actions=output:5",
                    "table=0,priority=100,actions=drop",
                ]
            )

            host.br0.up()
            host.int0.up()

        self.wait_tentative_ips(configuration.tunnel_devices)

    def generate_ping_endpoints(self, config):
        """
        The ping endpoints for this recipe are simply the tunnel endpoints

        Returned as::

            [PingEndpoints(self.matched.host1.int0, self.matched.host2.int0)]
        """
        return [PingEndpoints(self.matched.host1.int0, self.matched.host2.int0)]

    def get_packet_assert_config(self, ping_config):
        """
        The packet assert test configuration contains filter for source
        and destination addresses matching the carrier network with udp
        header bits specific to VXLAN tunneling. The grep patterns match
        the ICMP or ICMP6 echo requests encapsulated by Vxlan.
        """
        ip_filter = {"family": AF_INET}
        m1_carrier = self.matched.host1.eth0
        m2_carrier = self.matched.host2.eth0
        m1_carrier_ip = m1_carrier.ips_filter(**ip_filter)[0]
        m2_carrier_ip = m2_carrier.ips_filter(**ip_filter)[0]

        ip1 = ping_config.client_bind
        ip2 = ping_config.destination_address

        pa_kwargs = {}
        pa_kwargs["p_filter"] = (
            "src {} and dst {} "
            "and udp[8:2] = 0x0800 & 0x0800 "
            "and udp[11:4] = 1234 & 0x00FFFFFF".format(m2_carrier_ip, m1_carrier_ip)
        )

        if isinstance(ip2, Ip4Address):
            grep_pattern = "IP {} > {}: ICMP echo reply".format(ip2, ip1)
        elif isinstance(ip2, Ip6Address):
            grep_pattern = "IP6 {} > {}: ICMP6, echo reply".format(ip2, ip1)
        else:
            raise Exception("The destination address is nor IPv4 or IPv6 address")

        pa_kwargs["grep_for"] = [grep_pattern]

        if ping_config.count:
            pa_kwargs["p_min"] = ping_config.count
        m2 = ping_config.destination
        pa_config = PacketAssertConf(m2, m2_carrier, **pa_kwargs)

        return pa_config

    @property
    def offload_nics(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def pause_frames_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]
Exemplo n.º 13
0
class VhostNetPvPRecipe(BasePvPRecipe):
    generator_req = HostReq()
    generator_req.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))
    generator_req.eth1 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host_req = HostReq(with_guest="yes")
    host_req.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))
    host_req.eth1 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host1_dpdk_cores = StrParam(mandatory=True)

    vhost_cpus = StrParam(
        mandatory=True)  # The CPUs used by vhost-net kernel threads

    # TODO: Study the possibility of adding more forwarding engines
    # like xdp or tc
    guest_fwd = StrParam(default='bridge')
    host_fwd = StrParam(default='bridge')

    guest_macs = Param(default=['02:fa:fe:fa:fe:01', '02:fa:fe:fa:fe:02'])

    generator_dpdk_cores = StrParam(mandatory=True)

    cpu_perf_tool = Param(default=StatCPUMeasurement)

    def test(self):
        self.check_params()
        self.warmup(self.gen_ping_config())

        config = VhostPvPTestConf()
        self.pvp_test(config)

    def check_params(self):
        # Check emulatorpin range contains vhost cores
        emulator_min, emulator_max = self.params.guest_emulatorpin_cpu.split(
            '-')
        vhost_cpus = self.params.vhost_cpus.split(',')
        for vcpu in vhost_cpus:
            if vcpu > emulator_max or vcpu < emulator_min:
                raise ParamError("Emulator pin must contain vhost cpus")

    def gen_ping_config(self):
        return [(self.matched.generator_req, self.matched.generator_req.eth0,
                 self.matched.host_req.eth0),
                (self.matched.generator_req, self.matched.generator_req.eth1,
                 self.matched.host_req.eth1),
                (self.matched.host_req, self.matched.host_req.eth0,
                 self.matched.generator_req.eth0),
                (self.matched.host_req, self.matched.host_req.eth1,
                 self.matched.host_req.eth1)]

    def test_wide_configuration(self, config):

        config.generator.host = self.matched.generator_req
        config.generator.nics.append(self.matched.generator_req.eth0)
        config.generator.nics.append(self.matched.generator_req.eth1)

        self.matched.generator_req.eth0.ip_add(ipaddress("192.168.1.1/24"))
        self.matched.generator_req.eth1.ip_add(ipaddress("192.168.1.2/24"))
        self.matched.generator_req.eth0.up()
        self.matched.generator_req.eth1.up()

        self.base_dpdk_configuration(config.generator)

        config.dut.host = self.matched.host_req
        config.dut.nics.append(self.matched.host_req.eth0)
        config.dut.nics.append(self.matched.host_req.eth1)
        self.matched.host_req.eth0.up()
        self.matched.host_req.eth1.up()

        self.host_forwarding_configuration(config.dut)

        self.init_guest_virtctl(config.dut, config.guest)
        self.shutdown_guest(config.guest)
        self.configure_guest_xml(config.dut, config.guest)

        self.create_guest(config.dut, config.guest)
        self.guest_forwarding(config.guest)

        self.host_forwarding_vm_configuration(config.dut, config.guest)

        return config

    def generate_perf_config(self, config):
        flows = []
        for i in range(0,
                       min(len(config.generator.nics),
                           len(config.guest.nics))):
            src_nic = config.generator.nics[i]
            src_ip = src_nic.ips[0]
            dst_nic = config.guest.nics[i]
            dst_ip = config.generator.nics[((i + 1) %
                                            len(config.generator.nics))].ips[0]

            src_bind = dict(mac_addr=src_nic.hwaddr,
                            pci_addr=src_nic.bus_info,
                            ip_addr=src_ip)
            dst_bind = dict(mac_addr=dst_nic.hwaddr,
                            pci_addr=dst_nic.bus_info,
                            ip_addr=dst_ip)
            flows.append(
                PerfFlow(type="pvp_loop_rate",
                         generator=config.generator.host,
                         generator_bind=src_bind,
                         receiver=config.guest.host,
                         receiver_bind=dst_bind,
                         msg_size=self.params.perf_msg_size,
                         duration=self.params.perf_duration,
                         parallel_streams=self.params.perf_streams,
                         cpupin=None))

        return PerfRecipeConf(
            measurements=[
                self.params.cpu_perf_tool([
                    config.generator.host, config.dut.host, config.guest.host
                ]),
                TRexFlowMeasurement(
                    flows,
                    self.params.trex_dir,
                    self.params.host1_dpdk_cores.split(","),
                ),
            ],
            iterations=self.params.perf_iterations,
        )

    def test_wide_deconfiguration(self, config):
        try:
            self.guest_deconfigure(config.guest)
        except:
            log_exc_traceback()

        try:
            self.host_forwarding_vm_deconfiguration(config.dut, config.guest)
        except:
            log_exc_traceback()

        try:
            self.host_forwarding_deconfiguration(config.dut)
        except:
            log_exc_traceback()

        try:
            self.base_dpdk_deconfiguration(config.generator)
        except:
            log_exc_traceback()

        try:
            #returning the guest to the original running state
            self.shutdown_guest(config.guest)
            if config.guest.virtctl:
                config.guest.virtctl.vm_start(config.guest.name)
        except:
            log_exc_traceback()

        try:
            config.generator.host.run("service irqbalance start")
        except:
            log_exc_traceback()

    def host_forwarding_vm_configuration(self, host_conf, guest_conf):
        """
        VM - specific forwarding configuration
        Pin vhost-net kernel threads to the cpus specfied by vhost_cpus param
        """
        # Get a comma separated list of the vhost-net kernel threads' PIDs
        vhost_pids = host_conf.host.run(
            """ ps --ppid 2 | grep "vhost-$(pidof qemu-kvm)" """
            """ | awk '{if (length(pidstring) == 0) { """
            """     pidstring=$1 """
            """ } else { """
            """     pidstring = sprintf("%s,%s", pidstring, $1) """
            """ }}; """
            """ END{ print pidstring }'""")
        for pid, cpu in zip(vhost_pids.stdout.strip().split(','),
                            self.params.vhost_cpus.split(',')):
            mask = 1 << int(cpu)
            host_conf.host.run('taskset -p {:x} {}'.format(mask, pid))

    def host_forwarding_vm_deconfiguration(self, host_conf, guest_conf):
        """
        VM - specific forwarding deconfiguration
        """
        pass

    def host_forwarding_configuration(self, host_conf):
        if (self.params.host_fwd == 'bridge'):
            host_conf.bridges = []
            host_conf.host.br0 = BridgeDevice()
            host_conf.host.br1 = BridgeDevice()

            host_conf.host.br0.slave_add(host_conf.nics[0])
            host_conf.host.br1.slave_add(host_conf.nics[1])

            host_conf.host.br0.up()
            host_conf.host.br1.up()

            host_conf.bridges.append(host_conf.host.br0)
            host_conf.bridges.append(host_conf.host.br1)

        else:
            # TBD
            return

    def host_forwarding_deconfiguration(self, host_conf):
        if (self.params.host_fwd == 'bridge'):
            if host_conf.host.br0:
                host_conf.host.br0.slave_del(host_conf.nics[0])
            if host_conf.host.br1:
                host_conf.host.br1.slave_del(host_conf.nics[1])
        else:
            # TBD
            return

    def configure_guest_xml(self, host_conf, guest_conf):
        guest_xml = self.init_guest_xml(guest_conf)

        virtctl = guest_conf.virtctl
        guest_xml = ET.fromstring(virtctl.vm_XMLDesc(guest_conf.name))
        guest_conf.libvirt_xml = guest_xml

        guest_conf.virtio_devs = []
        for i, nic in enumerate(host_conf.nics):
            self._xml_add_vhostnet_dev(guest_xml, "vhostnet-{i}".format(i=i),
                                       host_conf.bridges[i],
                                       self.params.guest_macs[i])

            vhost_device = VirtioDevice(
                VirtioType.VHOST_NET,
                self.params.guest_macs[i],
                config={"bridge": host_conf.bridges[i]})
            guest_conf.virtio_devs.append(vhost_device)

        return guest_xml

    def guest_forwarding(self, guest_conf):
        guest = guest_conf.host
        if (self.params.guest_fwd == 'bridge'):
            guest.bridge = BridgeDevice()
            guest.bridge.name = 'guestbr0'
            for nic in guest_conf.nics:
                guest.bridge.slave_add(nic)
                nic.up()

        guest.run("echo 1 > /proc/sys/net/ipv4/ip_forward")

    def guest_deconfigure(self, guest_conf):
        if guest_conf.host:
            guest_conf.host.run("echo 0 > /proc/sys/net/ipv4/ip_forward")

    def _xml_add_vhostnet_dev(self, guest_xml, name, bridge, mac_addr):
        devices = guest_xml.find("devices")

        interface = ET.SubElement(devices, 'interface', type='bridge')
        ET.SubElement(interface, 'source', bridge=str(bridge.name))
        ET.SubElement(interface, 'mac', address=str(mac_addr))
        ET.SubElement(interface, 'model', type='virtio')
        ET.SubElement(interface, 'driver', name='vhost')
        # TODO: Add driver suboptions
        return guest_xml
Exemplo n.º 14
0
class TeamVsBondRecipe(PerfReversibleFlowMixin, CommonHWSubConfigMixin,
    OffloadSubConfigMixin, BaremetalEnrtRecipe):
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="tnet", driver=RecipeParam("driver"))
    host1.eth1 = DeviceReq(label="tnet", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="tnet", driver=RecipeParam("driver"))
    host2.eth1 = DeviceReq(label="tnet", driver=RecipeParam("driver"))

    offload_combinations = Param(default=(
        dict(gro="on", gso="on", tso="on", tx="on"),
        dict(gro="off", gso="on", tso="on", tx="on"),
        dict(gro="on", gso="off", tso="off", tx="on"),
        dict(gro="on", gso="on", tso="off", tx="off")))

    runner_name = StrParam(mandatory = True)
    bonding_mode = StrParam(mandatory = True)
    miimon_value = IntParam(mandatory = True)

    def test_wide_configuration(self):
        host1, host2 = self.matched.host1, self.matched.host2

        host1.team0 = TeamDevice(config={'runner': {'name': self.params.runner_name}})

        host2.bond0 = BondDevice(mode=self.params.bonding_mode,
            miimon=self.params.miimon_value)

        configuration = super().test_wide_configuration()
        configuration.test_wide_devices = [host1.team0, host2.bond0]

        net_addr_1 = "192.168.10"
        net_addr6_1 = "fc00:0:0:1"

        for i, (host, dev) in enumerate([(host1, host1.team0), (host2,
            host2.bond0)]):
            host.eth0.down()
            host.eth1.down()
            dev.slave_add(host.eth0)
            dev.slave_add(host.eth1)
            dev.ip_add(ipaddress(net_addr_1 + "." + str(i+1) + "/24"))
            dev.ip_add(ipaddress(net_addr6_1 + "::" + str(i+1) + "/64"))

        for host, dev in [(host1, host1.team0), (host2, host2.bond0)]:
            host.eth0.up()
            host.eth1.up()
            dev.up()

        self.wait_tentative_ips(configuration.test_wide_devices)

        return configuration

    def generate_test_wide_description(self, config):
        host1, host2 = self.matched.host1, self.matched.host2
        desc = super().generate_test_wide_description(config)
        desc += [
            "\n".join([
                "Configured {}.{}.ips = {}".format(
                    dev.host.hostid, dev.name, dev.ips
                )
                for dev in config.test_wide_devices
            ]),
            "\n".join([
                "Configured {}.{}.slaves = {}".format(
                    dev.host.hostid, dev.name,
                    ['.'.join([dev.host.hostid, slave.name])
                    for slave in dev.slaves]
                )
                for dev in config.test_wide_devices
            ]),
            "Configured {}.{}.runner_name = {}".format(
                host1.hostid, host1.team0.name,
                host1.team0.config
            ),
            "Configured {}.{}.mode = {}".format(
                host2.hostid, host2.bond0.name,
                host2.bond0.mode
            ),
            "Configured {}.{}.miimon = {}".format(
                host2.hostid, host2.bond0.name,
                host2.bond0.miimon
            )
        ]
        return desc

    def test_wide_deconfiguration(self, config):
        del config.test_wide_devices

        super().test_wide_deconfiguration(config)

    def generate_ping_endpoints(self, config):
        return [
            PingEndpoints(self.matched.host1.team0, self.matched.host2.bond0),
            PingEndpoints(self.matched.host2.bond0, self.matched.host1.team0)
        ]

    def generate_perf_endpoints(self, config):
        return [(self.matched.host1.team0, self.matched.host2.bond0)]

    @property
    def offload_nics(self):
        return [self.matched.host1.team0, self.matched.host2.bond0]

    @property
    def mtu_hw_config_dev_list(self):
        return [self.matched.host1.team0, self.matched.host2.bond0]

    @property
    def coalescing_hw_config_dev_list(self):
        host1, host2 = self.matched.host1, self.matched.host2
        return [host1.eth0, host1.eth1, host2.eth0, host2.eth1]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        host1, host2 = self.matched.host1, self.matched.host2
        return [host1.eth0, host1.eth1, host2.eth0, host2.eth1]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        host1, host2 = self.matched.host1, self.matched.host2
        return [host1.eth0, host1.eth1, host2.eth0, host2.eth1]
Exemplo n.º 15
0
class VxlanMulticastRecipe(CommonHWSubConfigMixin, BaseEnrtRecipe):
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))
    host1.tap0 = DeviceReq(label="to_guest1")

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))

    guest1 = HostReq()
    guest1.eth0 = DeviceReq(label="to_guest1")

    def test_wide_configuration(self):
        host1, host2, guest1 = (self.matched.host1, self.matched.host2,
                                self.matched.guest1)

        for dev in [host1.eth0, host2.eth0, guest1.eth0, host1.tap0]:
            dev.down()

        net_addr = "192.168.0"
        vxlan_net_addr = "192.168.100"
        vxlan_net_addr6 = "fc00:0:0:0"
        #TODO: Enable usage of a proper address (like 239.1.1.1)
        vxlan_group_ip = "192.168.0.3"

        host1.br0 = BridgeDevice()
        host1.br0.slave_add(host1.eth0)
        host1.br0.slave_add(host1.tap0)

        for machine in [host1, guest1, host2]:
            machine.vxlan0 = VxlanDevice(vxlan_id=1, group=vxlan_group_ip)

        configuration = super().test_wide_configuration()
        configuration.test_wide_devices = [
            host1.br0, host1.vxlan0, guest1.eth0, guest1.vxlan0, host2.eth0,
            host2.vxlan0
        ]

        for i, (machine, dev) in enumerate([(host1, host1.br0),
                                            (guest1, guest1.eth0),
                                            (host2, host2.eth0)]):
            dev.ip_add(ipaddress(net_addr + "." + str(i + 1) + "/24"))
            machine.vxlan0.realdev = dev
            machine.vxlan0.ip_add(
                ipaddress(vxlan_net_addr + "." + str(i + 1) + "/24"))
            machine.vxlan0.ip_add(
                ipaddress(vxlan_net_addr6 + "::" + str(i + 1) + "/64"))

        for dev in [
                host1.eth0, host2.eth0, guest1.eth0, host1.tap0, host1.br0,
                host1.vxlan0, host2.vxlan0, guest1.vxlan0
        ]:
            dev.up()

        self.wait_tentative_ips(configuration.test_wide_devices)

        return configuration

    def generate_test_wide_description(self, config):
        host1, host2, guest1 = (self.matched.host1, self.matched.host2,
                                self.matched.guest1)
        desc = super().generate_test_wide_description(config)
        desc += [
            "\n".join([
                "Configured {}.{}.ips = {}".format(dev.host.hostid, dev.name,
                                                   dev.ips)
                for dev in config.test_wide_devices
            ]), "\n".join([
                "Configured {}.{}.vxlan_id = {}".format(
                    dev.host.hostid, dev.name, dev.vxlan_id)
                for dev in [host1.vxlan0, host2.vxlan0, guest1.vxlan0]
            ]), "\n".join([
                "Configured {}.{}.group = {}".format(dev.host.hostid, dev.name,
                                                     dev.group)
                for dev in [host1.vxlan0, host2.vxlan0, guest1.vxlan0]
            ]), "\n".join([
                "Configured {}.{}.realdev = {}".format(
                    dev.host.hostid, dev.name,
                    '.'.join([dev.host.hostid, dev.realdev.name]))
                for dev in [host1.vxlan0, host2.vxlan0, guest1.vxlan0]
            ])
        ]
        return desc

    def test_wide_deconfiguration(self, config):
        del config.test_wide_devices

        super().test_wide_deconfiguration(config)

    def generate_ping_endpoints(self, config):
        host1, host2, guest1 = (self.matched.host1, self.matched.host2,
                                self.matched.guest1)
        devs = [host1.vxlan0, host2.vxlan0, guest1.vxlan0]
        dev_permutations = permutations(devs, 2)
        return [
            PingEndpoints(dev_permutation[0], dev_permutation[1])
            for dev_permutation in dev_permutations
        ]

    def generate_perf_endpoints(self, config):
        host1, host2, guest1 = (self.matched.host1, self.matched.host2,
                                self.matched.guest1)
        return [(self.matched.host1.vxlan0, self.matched.host2.vxlan0)]

    @property
    def mtu_hw_config_dev_list(self):
        host1, host2, guest1 = (self.matched.host1, self.matched.host2,
                                self.matched.guest1)
        return [host1.vxlan0, host2.vxlan0, guest1.vxlan0]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        host1, host2 = (self.matched.host1, self.matched.host2)
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        host1, host2 = (self.matched.host1, self.matched.host2)
        return [self.matched.host1.eth0, self.matched.host2.eth0]
Exemplo n.º 16
0
class MPTCPRecipe(
    CommonHWSubConfigMixin, OffloadSubConfigMixin, BaremetalEnrtRecipe
):
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net", driver=RecipeParam("driver"))
    host1.eth1 = DeviceReq(label="net", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net", driver=RecipeParam("driver"))
    host2.eth1 = DeviceReq(label="net", driver=RecipeParam("driver"))

    offload_combinations = Param(default=(
        dict(gro="on", gso="on", tso="on", tx="on", rx="on"),
        dict(gro="off", gso="on", tso="on", tx="on", rx="on"),
        dict(gro="on", gso="off", tso="off", tx="on", rx="on"),
        dict(gro="on", gso="on", tso="off", tx="off", rx="on"),
        dict(gro="on", gso="on", tso="on", tx="on", rx="off")))

    #Only use mptcp
    perf_tests = Param(default=("mptcp_stream",))

    def init_mptcp_control(self, hosts: List[Host]):
        """
        Initialize MPTCP RPC by sending the `MPTCPManager` to each host.
        In the future this might be moved to some sort of `MPTCPMixin`
        :param hosts:
        :return:
        """
        for host in hosts:
            host.mptcp = host.init_class(MPTCPManager)

    def test_wide_configuration(self):
        """
        Test wide configuration for this recipe involves just adding an IPv4 and
        IPv6 address to the matched eth0 nics on both hosts.

        host1.eth0 = 192.168.101.1/24 and fc00::1/64
        host1.eth1 = 192.168.102.1/24 and fc01::1/64


        host2.eth0 = 192.168.101.2/24 and fc00::2/64
        host2.eth1 = 192.168.102.2/24 and fc01::2/64
        """
        host1, host2 = self.matched.host1, self.matched.host2
        config = super().test_wide_configuration()
        config.test_wide_devices = []
        config.mptcp_endpoints = [host1.eth1]
        hosts = [host1, host2]

        self.init_mptcp_control(hosts)

        for i, host in enumerate(hosts):
            host.run("sysctl -w /net/mptcp/enabled=1")
            host.eth0.ip_add(ipaddress("192.168.101." + str(i+1) + "/24"))
            host.eth1.ip_add(ipaddress("192.168.102." + str(i+1) + "/24"))
            host.eth0.ip_add(ipaddress("fc00::" + str(i+1) + "/64"))
            host.eth1.ip_add(ipaddress("fc01::" + str(i+1) + "/64"))
            host.eth0.up()
            host.eth1.up()
            config.test_wide_devices.append(host.eth0)
            config.test_wide_devices.append(host.eth1)

        # Configure endpoints only host1.eth1
        if "ipv4" in self.params.ip_versions:
            host1.mptcp.add_endpoints(host1.eth1.ips_filter(family=AF_INET), flags=MPTCPFlags.MPTCP_PM_ADDR_FLAG_SUBFLOW)
            # Need route on client side to populate forwarding table
            host1.run(f"ip route add 192.168.101.0/24 dev {host1.eth1.name} via 192.168.102.2 prio 10000")
            # Need to disable rp_filter on server side
            host2.run("sysctl -w net.ipv4.conf.all.rp_filter=0")

        if "ipv6" in self.params.ip_versions:
            host1.mptcp.add_endpoints(host1.eth1.ips_filter(family=AF_INET6), flags=MPTCPFlags.MPTCP_PM_ADDR_FLAG_SUBFLOW)
            host1.run(f"ip route add fc00::/64 dev {host1.eth1.name} via fc01::2 prio 10000")
            # ipv6 doesnt have rp_filter

        # Configure limits
        host1.mptcp.subflows = 1
        host2.mptcp.subflows = 1

        self.wait_tentative_ips(config.test_wide_devices)

        return config


    def generate_test_wide_description(self, config):
        """
        Test wide description is extended with the configured addresses
        """
        desc = super().generate_test_wide_description(config)
        desc += [
            f"Configured {dev.host.hostid}.{dev.name}.ips = {dev.ips}"
            for dev in config.test_wide_devices
        ]

        desc += [f"Configured {dev.host.hostid}.mptcp_endpoints = {dev.ips}"
                 for dev in config.mptcp_endpoints]

        return desc

    def test_wide_deconfiguration(self, config):
        """

        :param config:
        :return:
        """
        for ep_dev in config.test_wide_devices:
            ep_dev.netns.mptcp.delete_all()

        del config.test_wide_devices

        #reset rp_filter
        self.matched.host2.run("sysctl -w net.ipv4.conf.all.rp_filter=1")

        super().test_wide_deconfiguration(config)

    def generate_ping_endpoints(self, config):
        """
        The ping endpoints are all ports in their respective pairs
        """
        return [PingEndpoints(self.matched.host1.eth0, self.matched.host2.eth0),
                PingEndpoints(self.matched.host1.eth1, self.matched.host2.eth1)]

    def generate_perf_endpoints(self, config):
        """
        Due to the way MPTCP works, the the perf endpoints will be the 2 "primary" ports/flows
        """
        return [(self.matched.host1.eth0, self.matched.host2.eth0)]

    #TODO MPTCP Devs would like it to have:
    # eth0.mtu = default
    # eth1.mtu = 8k.
    @property
    def pause_frames_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host1.eth1,
                self.matched.host2.eth0, self.matched.host2.eth1]

    @property
    def offload_nics(self):
        return [self.matched.host1.eth0, self.matched.host1.eth1,
                self.matched.host2.eth0, self.matched.host2.eth1]

    @property
    def mtu_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host1.eth1,
                self.matched.host2.eth0, self.matched.host2.eth1]

    @property
    def coalescing_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host1.eth1,
                self.matched.host2.eth0, self.matched.host2.eth1]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host1.eth1,
                self.matched.host2.eth0, self.matched.host2.eth1]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host1.eth1,
                self.matched.host2.eth0, self.matched.host2.eth1]
Exemplo n.º 17
0
class VlansRecipe(VlanPingEvaluatorMixin, CommonHWSubConfigMixin,
                  OffloadSubConfigMixin, BaremetalEnrtRecipe):
    """
    This recipe implements Enrt testing for a network scenario that looks
    as follows

    .. code-block:: none

                             .--------.
                    .--------+ switch +-------.
                    |        '--------'       |
                .---'--.                   .--'---.
        .-------| eth0 |------.    .-------| eth0 |------.
        |       '------'      |    |       '------'      |
        |      /   |    \     |    |      /   |    \     |
        | vlan0  vlan1  vlan2 |    | vlan0  vlan1  vlan2 |
        | id=10  id=20  id=30 |    | id=10  id=20  id=30 |
        |                     |    |                     |
        |        host1        |    |        host2        |
        '---------------------'    '---------------------'

    All sub configurations are included via Mixin classes.

    The actual test machinery is implemented in the :any:`BaseEnrtRecipe` class.
    """
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    vlan0_id = IntParam(default=10)
    vlan1_id = IntParam(default=20)
    vlan2_id = IntParam(default=30)

    offload_combinations = Param(
        default=(dict(gro="on", gso="on", tso="on", tx="on", rx="on"),
                 dict(gro="off", gso="on", tso="on", tx="on", rx="on"),
                 dict(gro="on", gso="off", tso="off", tx="on", rx="on"),
                 dict(gro="on", gso="on", tso="off", tx="off", rx="on"),
                 dict(gro="on", gso="on", tso="on", tx="on", rx="off")))

    def test_wide_configuration(self):
        """
        Test wide configuration for this recipe involves creating three
        VLAN (802.1Q) tunnels on top of the matched host's NIC with vlan
        ids from parameters vlan0_id, vlan1_id and vlan2_id (by default: 10, 20,
        30). The same tunnels are configured on the second host.

        An IPv4 and IPv6 address is configured on each tunnel endpoint.

        | host1.vlan0 = 192.168.10.1/24 and fc00:0:0:1::1/64
        | host1.vlan1 = 192.168.20.1/24 and fc00:0:0:2::1/64
        | host1.vlan2 = 192.168.30.1/24 and fc00:0:0:3::1/64

        | host2.vlan0 = 192.168.10.2/24 and fc00:0:0:1::2/64
        | host2.vlan1 = 192.168.20.2/24 and fc00:0:0:2::2/64
        | host2.vlan2 = 192.168.30.2/24 and fc00:0:0:3::2/64

        """
        host1, host2 = self.matched.host1, self.matched.host2

        host1.eth0.down()
        host2.eth0.down()

        host1.vlan0 = VlanDevice(realdev=host1.eth0,
                                 vlan_id=self.params.vlan0_id)
        host1.vlan1 = VlanDevice(realdev=host1.eth0,
                                 vlan_id=self.params.vlan1_id)
        host1.vlan2 = VlanDevice(realdev=host1.eth0,
                                 vlan_id=self.params.vlan2_id)
        host2.vlan0 = VlanDevice(realdev=host2.eth0,
                                 vlan_id=self.params.vlan0_id)
        host2.vlan1 = VlanDevice(realdev=host2.eth0,
                                 vlan_id=self.params.vlan1_id)
        host2.vlan2 = VlanDevice(realdev=host2.eth0,
                                 vlan_id=self.params.vlan2_id)

        configuration = super().test_wide_configuration()
        configuration.test_wide_devices = []
        for host in [host1, host2]:
            configuration.test_wide_devices.extend(
                [host.vlan0, host.vlan1, host.vlan2])

        net_addr = "192.168"
        net_addr6 = "fc00:0:0"

        for i, host in enumerate([host1, host2]):
            host.vlan0.ip_add(ipaddress('{}.10.{}/24'.format(net_addr, i + 1)))
            host.vlan1.ip_add(ipaddress('{}.20.{}/24'.format(net_addr, i + 1)))
            host.vlan2.ip_add(ipaddress('{}.30.{}/24'.format(net_addr, i + 1)))
            host.vlan0.ip_add(ipaddress('{}:1::{}/64'.format(net_addr6,
                                                             i + 1)))
            host.vlan1.ip_add(ipaddress('{}:2::{}/64'.format(net_addr6,
                                                             i + 1)))
            host.vlan2.ip_add(ipaddress('{}:3::{}/64'.format(net_addr6,
                                                             i + 1)))
            for dev in [host.eth0, host.vlan0, host.vlan1, host.vlan2]:
                dev.up()

        self.wait_tentative_ips(configuration.test_wide_devices)

        return configuration

    def generate_test_wide_description(self, config):
        """
        Test wide description is extended with the configured VLAN tunnels
        and their IP addresses
        """
        host1, host2 = self.matched.host1, self.matched.host2
        desc = super().generate_test_wide_description(config)
        desc += [
            "\n".join([
                "Configured {}.{}.ips = {}".format(dev.host.hostid, dev.name,
                                                   dev.ips)
                for dev in config.test_wide_devices
            ]), "\n".join([
                "Configured {}.{}.vlan_id = {}".format(dev.host.hostid,
                                                       dev.name, dev.vlan_id)
                for dev in config.test_wide_devices
            ]), "\n".join([
                "Configured {}.{}.realdev = {}".format(
                    dev.host.hostid, dev.name,
                    '.'.join([dev.host.hostid, dev.realdev.name]))
                for dev in config.test_wide_devices
            ])
        ]
        return desc

    def test_wide_deconfiguration(self, config):
        ""  # overriding the parent docstring
        del config.test_wide_devices

        super().test_wide_deconfiguration(config)

    def generate_ping_endpoints(self, config):
        """
        The ping endpoints for this recipe are the matching VLAN tunnel
        endpoints of the hosts.

        Returned as::

            [PingEndpoints(host1.vlan0, host2.vlan0),
             PingEndpoints(host1.vlan1, host2.vlan1),
             PingEndpoints(host1.vlan2, host2.vlan2)]
        """
        host1, host2 = self.matched.host1, self.matched.host2

        return [
            PingEndpoints(host1.vlan0, host2.vlan0),
            PingEndpoints(host1.vlan1, host2.vlan1),
            PingEndpoints(host1.vlan2, host2.vlan2)
        ]

    def generate_perf_endpoints(self, config):
        """
        The perf endpoints for this recipe are the VLAN tunnel endpoints with
        VLAN id from parameter vlan0_id (by default: 10):

        host1.vlan0 and host2.vlan0

        Returned as::

            [(self.matched.host1.vlan0, self.matched.host2.vlan0)]
        """
        return [(self.matched.host1.vlan0, self.matched.host2.vlan0)]

    @property
    def offload_nics(self):
        """
        The `offload_nics` property value for this scenario is a list of the
        physical devices carrying data of the configured VLAN tunnels:

        host1.eth0 and host2.eth0

        For detailed explanation of this property see :any:`OffloadSubConfigMixin`
        class and :any:`OffloadSubConfigMixin.offload_nics`.
        """
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def mtu_hw_config_dev_list(self):
        """
        The `mtu_hw_config_dev_list` property value for this scenario is a
        list of all configured VLAN tunnel devices and the underlying physical
        devices:

        | host1.eth0, host1.vlan0, host1.vlan1, host1.vlan2
        | host2.eth0, host2.vlan0, host2.vlan1, host2.vlan2

        For detailed explanation of this property see :any:`MTUHWConfigMixin`
        class and :any:`MTUHWConfigMixin.mtu_hw_config_dev_list`.
        """
        result = []
        for host in [self.matched.host1, self.matched.host2]:
            for dev in [host.eth0, host.vlan0, host.vlan1, host.vlan2]:
                result.append(dev)
        return result

    @property
    def coalescing_hw_config_dev_list(self):
        """
        The `coalescing_hw_config_dev_list` property value for this scenario
        is a list of the physical devices carrying data of the configured
        VLAN tunnels:

        host1.eth0 and host2.eth0

        For detailed explanation of this property see :any:`CoalescingHWConfigMixin`
        class and :any:`CoalescingHWConfigMixin.coalescing_hw_config_dev_list`.
        """
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        """
        The `dev_interrupt_hw_config_dev_list` property value for this scenario
        is a list of the physical devices carrying data of the configured
        VLAN tunnels:

        host1.eth0 and host2.eth0

        For detailed explanation of this property see :any:`DevInterruptHWConfigMixin`
        class and :any:`DevInterruptHWConfigMixin.dev_interrupt_hw_config_dev_list`.
        """
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        """
        The `parallel_stream_qdisc_hw_config_dev_list` property value for
        this scenario is a list of the physical devices carrying data of the
        configured VLAN tunnels:

        host1.eth0 and host2.eth0

        For detailed explanation of this property see
        :any:`ParallelStreamQDiscHWConfigMixin` class and
        :any:`ParallelStreamQDiscHWConfigMixin.parallel_stream_qdisc_hw_config_dev_list`.
        """
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def pause_frames_dev_list(self):
        """
        The `pause_frames_dev_list` property value for this scenario is a list
        of the physical devices carrying data of the configured VLAN tunnels:

        host1.eth0 and host2.eth0

        For detailed explanation of this property see
        :any:`PauseFramesHWConfigMixin` and
        :any:`PauseFramesHWConfigMixin.pause_frames_dev_list`.
        """
        return [self.matched.host1.eth0, self.matched.host2.eth0]
Exemplo n.º 18
0
class NoVirtOvsVxlanRecipe(CommonHWSubConfigMixin, BaremetalEnrtRecipe):
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))

    def test_wide_configuration(self):
        host1, host2 = self.matched.host1, self.matched.host2

        net_addr = "192.168.2"
        vxlan_net_addr = "192.168.100"
        vxlan_net_addr6 = "fc00:0:0:0"

        flow_entries = []
        flow_entries.append("table=0,in_port=5,actions=set_field:100->"
                            "tun_id,output:10")
        flow_entries.append("table=0,in_port=10,tun_id=100,actions="
                            "output:5")
        flow_entries.append("table=0,priority=100,actions=drop")

        for i, host in enumerate([host1, host2]):
            host.eth0.down()
            host.eth0.ip_add(ipaddress(net_addr + "." + str(i + 1) + "/24"))
            host.br0 = OvsBridgeDevice()
            host.int0 = host.br0.port_add(interface_options={
                'type': 'internal',
                'ofport_request': 5,
                'name': 'int0'
            })
            host.int0.ip_add(
                ipaddress(vxlan_net_addr + "." + str(i + 1) + "/24"))
            host.int0.ip_add(
                ipaddress(vxlan_net_addr6 + "::" + str(i + 1) + "/64"))
            tunnel_opts = {
                "option:remote_ip": net_addr + "." + str(2 - i),
                "option:key": "flow",
                "ofport_request": "10"
            }
            host.br0.tunnel_add("vxlan", tunnel_opts)
            host.br0.flows_add(flow_entries)
            host.eth0.up()
            host.int0.up()
            host.br0.up()

        configuration = super().test_wide_configuration()
        configuration.test_wide_devices = [
            host1.eth0, host1.int0, host2.eth0, host2.int0
        ]

        self.wait_tentative_ips(configuration.test_wide_devices)

        return configuration

    def generate_test_wide_description(self, config):
        host1, host2 = self.matched.host1, self.matched.host2
        desc = super().generate_test_wide_description(config)
        desc += [
            "\n".join([
                "Configured {}.{}.ips = {}".format(dev.host.hostid, dev.name,
                                                   dev.ips)
                for dev in config.test_wide_devices
            ]), "\n".join([
                "Configured {}.{}.ports = {}".format(dev.host.hostid, dev.name,
                                                     dev.ports)
                for dev in [host1.br0, host2.br0]
            ]), "\n".join([
                "Configured {}.{}.tunnels = {}".format(dev.host.hostid,
                                                       dev.name, dev.tunnels)
                for dev in [host1.br0, host2.br0]
            ]), "\n".join([
                "Configured {}.{}.flows = {}".format(dev.host.hostid, dev.name,
                                                     dev.flows_str)
                for dev in [host1.br0, host2.br0]
            ])
        ]
        return desc

    def test_wide_deconfiguration(self, config):
        del config.test_wide_devices

        super().test_wide_deconfiguration(config)

    def generate_ping_endpoints(self, config):
        return [
            PingEndpoints(self.matched.host1.int0, self.matched.host2.int0)
        ]

    def generate_perf_endpoints(self, config):
        return [(self.matched.host1.int0, self.matched.host2.int0)]

    @property
    def mtu_hw_config_dev_list(self):
        return [self.matched.host1.int0, self.matched.host2.int0]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]
Exemplo n.º 19
0
class VirtOvsVxlanRecipe(VlanPingEvaluatorMixin, CommonHWSubConfigMixin,
                         VirtualEnrtRecipe):
    host1 = HostReq()
    host1.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))
    host1.tap0 = DeviceReq(label="to_guest1")
    host1.tap1 = DeviceReq(label="to_guest2")

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="to_switch", driver=RecipeParam("driver"))
    host2.tap0 = DeviceReq(label="to_guest3")
    host2.tap1 = DeviceReq(label="to_guest4")

    guest1 = HostReq()
    guest1.eth0 = DeviceReq(label="to_guest1")

    guest2 = HostReq()
    guest2.eth0 = DeviceReq(label="to_guest2")

    guest3 = HostReq()
    guest3.eth0 = DeviceReq(label="to_guest3")

    guest4 = HostReq()
    guest4.eth0 = DeviceReq(label="to_guest4")

    def test_wide_configuration(self):
        host1, host2, guest1, guest2, guest3, guest4 = (self.matched.host1,
                                                        self.matched.host2,
                                                        self.matched.guest1,
                                                        self.matched.guest2,
                                                        self.matched.guest3,
                                                        self.matched.guest4)

        for host in [host1, host2]:
            host.eth0.down()
            host.tap0.down()
            host.tap1.down()
        for guest in [guest1, guest2, guest3, guest4]:
            guest.eth0.down()

        net_addr = "192.168.2"
        vxlan_net_addr = "192.168.100"
        vxlan_net_addr6 = "fc00:0:0:0"

        flow_entries = []
        flow_entries.append("table=0,in_port=5,actions=set_field:100->"
                            "tun_id,output:10")
        flow_entries.append("table=0,in_port=6,actions=set_field:200->"
                            "tun_id,output:10")
        flow_entries.append("table=0,in_port=10,tun_id=100,actions="
                            "output:5")
        flow_entries.append("table=0,in_port=10,tun_id=200,actions="
                            "output:6")
        flow_entries.append("table=0,priority=100,actions=drop")

        configuration = super().test_wide_configuration()
        configuration.test_wide_devices = [
            host1.eth0, host2.eth0, guest1.eth0, guest2.eth0, guest3.eth0,
            guest4.eth0
        ]

        for i, host in enumerate([host1, host2]):
            host.eth0.ip_add(ipaddress(net_addr + "." + str(i + 1) + "/24"))
            host.br0 = OvsBridgeDevice()
            for dev, ofport_r in [(host.tap0, '5'), (host.tap1, '6')]:
                host.br0.port_add(
                    device=dev, interface_options={'ofport_request': ofport_r})
            tunnel_opts = {
                "option:remote_ip": net_addr + "." + str(2 - i),
                "option:key": "flow",
                "ofport_request": '10'
            }
            host.br0.tunnel_add("vxlan", tunnel_opts)
            host.br0.flows_add(flow_entries)
            for dev in [host.eth0, host.tap0, host.tap1, host.br0]:
                dev.up()

        for i, guest in enumerate([guest1, guest2, guest3, guest4]):
            guest.eth0.ip_add(
                ipaddress(vxlan_net_addr + "." + str(i + 1) + "/24"))
            guest.eth0.ip_add(
                ipaddress(vxlan_net_addr6 + "::" + str(i + 1) + "/64"))
            guest.eth0.up()

        self.wait_tentative_ips(configuration.test_wide_devices)

        return configuration

    def generate_test_wide_description(self, config):
        host1, host2 = self.matched.host1, self.matched.host2
        desc = super().generate_test_wide_description(config)
        desc += [
            "\n".join([
                "Configured {}.{}.ips = {}".format(dev.host.hostid, dev.name,
                                                   dev.ips)
                for dev in config.test_wide_devices
            ]), "\n".join([
                "Configured {}.{}.ports = {}".format(dev.host.hostid, dev.name,
                                                     dev.ports)
                for dev in [host1.br0, host2.br0]
            ]), "\n".join([
                "Configured {}.{}.tunnels = {}".format(dev.host.hostid,
                                                       dev.name, dev.tunnels)
                for dev in [host1.br0, host2.br0]
            ]), "\n".join([
                "Configured {}.{}.flows = {}".format(dev.host.hostid, dev.name,
                                                     dev.flows_str)
                for dev in [host1.br0, host2.br0]
            ])
        ]
        return desc

    def test_wide_deconfiguration(self, config):
        del config.test_wide_devices

        super().test_wide_deconfiguration(config)

    def generate_ping_endpoints(self, config):
        guest1, guest2, guest3, guest4 = (self.matched.guest1,
                                          self.matched.guest2,
                                          self.matched.guest3,
                                          self.matched.guest4)
        devs = [guest1.eth0, guest2.eth0, guest3.eth0, guest4.eth0]
        dev_combinations = combinations(devs, 2)

        return [
            PingEndpoints(comb[0],
                          comb[1],
                          reachable=((comb[0].host, comb[1].host)
                                     in [(guest1, guest3), (guest2, guest4)]))
            for comb in dev_combinations
        ]

    def generate_perf_endpoints(self, config):
        return [(self.matched.guest1.eth0, self.matched.guest3.eth0)]

    @property
    def pause_frames_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def mtu_hw_config_dev_list(self):
        return [
            self.matched.guest1.eth0, self.matched.guest2.eth0,
            self.matched.guest3.eth0, self.matched.guest4.eth0
        ]

    @property
    def dev_interrupt_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def parallel_stream_qdisc_hw_config_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]
Exemplo n.º 20
0
class IpIpTunnelRecipe(MTUHWConfigMixin, PauseFramesHWConfigMixin,
                       BaseTunnelRecipe):
    """
    This class implements a recipe that configures a simple IpIp tunnel between
    two hosts.

    .. code-block:: none

                        .--------.
                 .------| switch |-----.
                 |      '--------'     |
                 |                     |
         .-------|------.      .-------|------.
         |    .--'-.    |      |    .--'-.    |
         |    |eth0|    |      |    |eth0|    |
         |    '----'    |      |    '----'    |
         |      | |     |      |      | |     |
         |  ----' '---  |      |  ----' '---  |
         |  ipip tunnel |      |  ipip tunnel |
         |  ----------  |      |  ----------  |
         |              |      |              |
         |    host1     |      |    host2     |
         '--------------'      '--------------'

    The actual test machinery is implemented in the :any:`BaseEnrtRecipe` class.

    The test wide configuration is implemented in the :any:`BaseTunnelRecipe`
    class.

    The recipe provides additional parameter:

        :param tunnel_mode:
            this parameter specifies the mode of the IPIP tunnel, can be any
            of the **any**, **ipip** or **mplsip**
    """

    host1 = HostReq()
    host1.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    host2 = HostReq()
    host2.eth0 = DeviceReq(label="net1", driver=RecipeParam("driver"))

    tunnel_mode = ChoiceParam(type=StrParam,
                              choices=set(["any", "ipip", "mplsip"]),
                              mandatory=True)

    def configure_underlying_network(self, configuration):
        """
        The underlying network for the tunnel consists of the Ethernet
        devices on the matched hosts.
        """
        host1, host2 = self.matched.host1, self.matched.host2
        for i, device in enumerate([host1.eth0, host2.eth0]):
            device.ip_add(ipaddress("172.16.200." + str(i + 1) + "/16"))
            device.up()
            configuration.test_wide_devices.append(device)

        configuration.tunnel_endpoints = (host1.eth0, host2.eth0)

    def create_tunnel(self, configuration):
        """
        The ipip tunnel devices are configured with IPv4 addresses.
        """
        endpoint1, endpoint2 = configuration.tunnel_endpoints
        m1 = endpoint1.netns
        m2 = endpoint2.netns
        ip_filter = {"family": AF_INET}
        endpoint1_ip = endpoint1.ips_filter(**ip_filter)[0]
        endpoint2_ip = endpoint2.ips_filter(**ip_filter)[0]

        a_ip4 = ipaddress("192.168.200.1/24")
        b_ip4 = ipaddress("192.168.200.2/24")

        m1.ipip_tunnel = IpIpDevice(
            local=endpoint1_ip,
            remote=endpoint2_ip,
            mode=self.params.tunnel_mode,
            ttl=64,
        )
        m2.ipip_tunnel = IpIpDevice(
            local=endpoint2_ip,
            remote=endpoint1_ip,
            mode=self.params.tunnel_mode,
            ttl=64,
        )

        # A
        m1.ipip_tunnel.up()
        m1.ipip_tunnel.ip_add(a_ip4)

        # B
        m2.ipip_tunnel.up()
        m2.ipip_tunnel.ip_add(b_ip4)

        configuration.tunnel_devices.extend([m1.ipip_tunnel, m2.ipip_tunnel])

    def generate_ping_endpoints(self, config):
        """
        The ping endpoints for this recipe are simply the tunnel endpoints

        Returned as::

            [PingEndpoints(self.matched.host1.ipip_tunnel, self.matched.host2.ipip_tunnel)]
        """
        return [
            PingEndpoints(self.matched.host1.ipip_tunnel,
                          self.matched.host2.ipip_tunnel)
        ]

    def get_packet_assert_config(self, ping_config):
        """
        The packet assert test configuration contains filter for ip protocol
        and grep patterns to match the ICMP echo requests encapsulated
        by IPIP.
        """
        ip_filter = {"family": AF_INET}
        m1_carrier = self.matched.host1.eth0
        m2_carrier = self.matched.host2.eth0
        m1_carrier_ip = m1_carrier.ips_filter(**ip_filter)[0]
        m2_carrier_ip = m2_carrier.ips_filter(**ip_filter)[0]

        ip1 = ping_config.client_bind
        ip2 = ping_config.destination_address

        pa_kwargs = {}
        pa_kwargs["p_filter"] = "ip host {}".format(m1_carrier_ip)

        # TODO: handle mplsip mode
        grep_pattern = [
            "IP {} > {}: IP {} > {}: ICMP".format(m1_carrier_ip, m2_carrier_ip,
                                                  ip1, ip2)
        ]

        pa_kwargs["grep_for"] = grep_pattern

        if ping_config.count:
            pa_kwargs["p_min"] = ping_config.count
        m2 = ping_config.destination
        pa_config = PacketAssertConf(m2, m2_carrier, **pa_kwargs)

        return pa_config

    @property
    def pause_frames_dev_list(self):
        return [self.matched.host1.eth0, self.matched.host2.eth0]

    @property
    def mtu_hw_config_dev_list(self):
        return [self.matched.host1.ipip_tunnel, self.matched.host2.ipip_tunnel]