Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion libs/net/traffic_generator.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import contextlib
Comment thread
nirdothan marked this conversation as resolved.
Comment thread
rnetser marked this conversation as resolved.
Comment thread
nirdothan marked this conversation as resolved.
Comment thread
nirdothan marked this conversation as resolved.
Comment thread
nirdothan marked this conversation as resolved.
import logging
from abc import ABC, abstractmethod
from typing import Final
from typing import Final, Generator

from ocp_resources.pod import Pod
from ocp_utilities.exceptions import CommandExecFailed
from timeout_sampler import retry

from libs.net.vmspec import IP_ADDRESS, lookup_iface_status
from libs.vm.vm import BaseVirtualMachine

_DEFAULT_CMD_TIMEOUT_SEC: Final[int] = 10
_IPERF_BIN: Final[str] = "iperf3"
IPERF_SERVER_PORT: Final[int] = 5201


LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -186,3 +189,41 @@ def _ensure_is_running(self) -> bool:

def is_tcp_connection(server: TcpServer, client: BaseTcpClient) -> bool:
return server.is_running() and client.is_running()


@contextlib.contextmanager
def client_server_active_connection(
client_vm: BaseVirtualMachine,
server_vm: BaseVirtualMachine,
spec_logical_network: str,
port: int = IPERF_SERVER_PORT,
maximum_segment_size: int = 0,
) -> Generator[tuple[VMTcpClient, TcpServer], None, None]:
"""Start iperf3 client-server connection with continuous TCP traffic flow.

Automatically starts an iperf3 server and client, with traffic flowing continuously
while inside the context. Both processes stop automatically on exit.

Args:
client_vm: VM running the iperf3 client (sends traffic).
server_vm: VM running the iperf3 server (receives traffic).
spec_logical_network: Network interface name on server VM for IP resolution.
port: TCP port for iperf3 connection.
maximum_segment_size: Define explicitly the TCP payload size (in bytes).
Use for jumbo frame testing.
Default value is 0 (do not change mss).

Yields:
tuple[VMTcpClient, TcpServer]: Client and server objects with active traffic flowing.

Note:
Traffic runs with infinite duration until context exits.
"""
with TcpServer(vm=server_vm, port=port) as server:
with VMTcpClient(
vm=client_vm,
server_ip=lookup_iface_status(vm=server_vm, iface_name=spec_logical_network)[IP_ADDRESS],
server_port=port,
maximum_segment_size=maximum_segment_size,
) as client:
yield client, server
Comment thread
nirdothan marked this conversation as resolved.
7 changes: 4 additions & 3 deletions libs/net/udn.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
from libs.vm.spec import Interface, NetBinding, Network
from utilities.infra import create_ns

UDN_BINDING_PLUGIN_NAME: Final[str] = "l2bridge"
UDN_BINDING_DEFAULT_PLUGIN_NAME: Final[str] = "l2bridge"
UDN_BINDING_PASST_PLUGIN_NAME: Final[str] = "passt"


def udn_primary_network(name: str) -> tuple[Interface, Network]:
return Interface(name=name, binding=NetBinding(name=UDN_BINDING_PLUGIN_NAME)), Network(name=name, pod={})
def udn_primary_network(name: str, binding: str) -> tuple[Interface, Network]:
return Interface(name=name, binding=NetBinding(name=binding)), Network(name=name, pod={})


def create_udn_namespace(
Expand Down
3 changes: 2 additions & 1 deletion tests/network/bgp/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from libs.net import netattachdef as libnad
from libs.net.traffic_generator import PodTcpClient as TcpClient
from libs.net.traffic_generator import TcpServer
from libs.net.udn import create_udn_namespace
from libs.net.udn import UDN_BINDING_DEFAULT_PLUGIN_NAME, create_udn_namespace
from libs.net.vmspec import IP_ADDRESS, lookup_iface_status, lookup_primary_network
from libs.vm.vm import BaseVirtualMachine
from tests.network.libs import cluster_user_defined_network as libcudn
Expand Down Expand Up @@ -210,6 +210,7 @@ def vm_cudn(
namespace_name=namespace_cudn.name,
name="vm-cudn-bgp",
client=admin_client,
binding=UDN_BINDING_DEFAULT_PLUGIN_NAME,
template_labels=EXTERNAL_FRR_POD_LABEL,
anti_affinity_namespaces=[frr_external_pod.pod.namespace],
) as vm:
Expand Down
3 changes: 2 additions & 1 deletion tests/network/libs/vm_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ def udn_vm(
namespace_name: str,
name: str,
client: DynamicClient,
binding: str,
template_labels: dict | None = None,
anti_affinity_namespaces: list[str] | None = None,
) -> BaseVirtualMachine:
spec = base_vmspec()
iface, network = udn_primary_network(name="udn-primary")
iface, network = udn_primary_network(name="udn-primary", binding=binding)
spec.template.spec.domain.devices.interfaces = [iface] # type: ignore
spec.template.spec.networks = [network]
if template_labels:
Expand Down
5 changes: 1 addition & 4 deletions tests/network/localnet/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from ocp_resources.namespace import Namespace

import tests.network.libs.nodenetworkconfigurationpolicy as libnncp
from libs.net.traffic_generator import TcpServer
from libs.net.traffic_generator import TcpServer, client_server_active_connection
from libs.net.traffic_generator import VMTcpClient as TcpClient
from libs.net.vmspec import lookup_iface_status
from libs.vm.spec import Interface, Multus, Network
Expand All @@ -14,7 +14,6 @@
from tests.network.libs import cluster_user_defined_network as libcudn
from tests.network.libs.ip import IPV4_HEADER_SIZE, TCP_HEADER_SIZE, random_ipv4_address
from tests.network.localnet.liblocalnet import (
_IPERF_SERVER_PORT,
LINK_STATE_DOWN,
LOCALNET_BR_EX_INTERFACE,
LOCALNET_BR_EX_INTERFACE_NO_VLAN,
Expand All @@ -23,7 +22,6 @@
LOCALNET_OVS_BRIDGE_INTERFACE,
LOCALNET_OVS_BRIDGE_NETWORK,
LOCALNET_TEST_LABEL,
client_server_active_connection,
create_nncp_localnet_on_secondary_node_nic,
create_traffic_client,
create_traffic_server,
Expand Down Expand Up @@ -469,7 +467,6 @@ def localnet_ovs_bridge_jumbo_frame_client_and_server_vms(
client_vm=ovs_bridge_localnet_running_jumbo_frame_vms[1],
server_vm=ovs_bridge_localnet_running_jumbo_frame_vms[0],
spec_logical_network=LOCALNET_OVS_BRIDGE_INTERFACE,
port=_IPERF_SERVER_PORT,
maximum_segment_size=cluster_hardware_mtu - IPV4_HEADER_SIZE - TCP_HEADER_SIZE,
) as (client, server):
yield client, server
45 changes: 3 additions & 42 deletions tests/network/localnet/liblocalnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from kubernetes.client import ApiException
from kubernetes.dynamic import DynamicClient

from libs.net.traffic_generator import TcpServer
from libs.net.traffic_generator import IPERF_SERVER_PORT, TcpServer
from libs.net.traffic_generator import VMTcpClient as TcpClient
from libs.net.vmspec import IP_ADDRESS, add_volume_disk, lookup_iface_status
from libs.vm.affinity import new_pod_anti_affinity
Expand All @@ -29,7 +29,6 @@
LINK_STATE_UP = "up"
LINK_STATE_DOWN = "down"
NNCP_INTERFACE_TYPE_ETHERNET = "ethernet"
_IPERF_SERVER_PORT = 5201
LOGGER = logging.getLogger(__name__)


Expand All @@ -48,7 +47,7 @@ def run_vms(vms: tuple[BaseVirtualMachine, ...]) -> tuple[BaseVirtualMachine, ..


def create_traffic_server(vm: BaseVirtualMachine) -> TcpServer:
return TcpServer(vm=vm, port=_IPERF_SERVER_PORT)
return TcpServer(vm=vm, port=IPERF_SERVER_PORT)


def create_traffic_client(
Expand All @@ -57,7 +56,7 @@ def create_traffic_client(
return TcpClient(
vm=client_vm,
server_ip=lookup_iface_status(vm=server_vm, iface_name=spec_logical_network)[IP_ADDRESS],
server_port=_IPERF_SERVER_PORT,
server_port=IPERF_SERVER_PORT,
)


Expand Down Expand Up @@ -183,44 +182,6 @@ def localnet_cudn(
)


@contextlib.contextmanager
def client_server_active_connection(
client_vm: BaseVirtualMachine,
server_vm: BaseVirtualMachine,
spec_logical_network: str,
port: int = _IPERF_SERVER_PORT,
maximum_segment_size: int = 0,
) -> Generator[tuple[TcpClient, TcpServer], None, None]:
"""Start iperf3 client-server connection with continuous TCP traffic flow.

Automatically starts an iperf3 server and client, with traffic flowing continuously
while inside the context. Both processes stop automatically on exit.

Args:
client_vm: VM running the iperf3 client (sends traffic).
server_vm: VM running the iperf3 server (receives traffic).
spec_logical_network: Network interface name on server VM for IP resolution.
port: TCP port for iperf3 connection.
maximum_segment_size: Define explicitly the TCP payload size (in bytes).
Use for jumbo frame testing.
Default value is 0 (do not change mss).

Yields:
tuple[TcpClient, TcpServer]: Client and server objects with active traffic flowing.

Note:
Traffic runs with infinite duration until context exits.
"""
with TcpServer(vm=server_vm, port=port) as server:
with TcpClient(
vm=client_vm,
server_ip=lookup_iface_status(vm=server_vm, iface_name=spec_logical_network)[IP_ADDRESS],
server_port=port,
maximum_segment_size=maximum_segment_size,
) as client:
yield client, server


@contextlib.contextmanager
def create_nncp_localnet_on_secondary_node_nic(
node_nic_name: str,
Expand Down
3 changes: 1 addition & 2 deletions tests/network/localnet/test_default_bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

import pytest

from libs.net.traffic_generator import is_tcp_connection
from libs.net.traffic_generator import client_server_active_connection, is_tcp_connection
from libs.net.vmspec import IP_ADDRESS, lookup_iface_status
from tests.network.localnet.liblocalnet import (
LOCALNET_BR_EX_INTERFACE,
LOCALNET_BR_EX_INTERFACE_NO_VLAN,
client_server_active_connection,
)
from utilities.virt import migrate_vm_and_verify

Expand Down
3 changes: 1 addition & 2 deletions tests/network/localnet/test_ovs_bridge.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import pytest

from libs.net.traffic_generator import is_tcp_connection
from libs.net.traffic_generator import client_server_active_connection, is_tcp_connection
from libs.net.vmspec import lookup_iface_status
from tests.network.localnet.liblocalnet import (
LINK_STATE_UP,
LOCALNET_OVS_BRIDGE_INTERFACE,
client_server_active_connection,
)
from utilities.constants import QUARANTINED
from utilities.virt import migrate_vm_and_verify
Expand Down
37 changes: 37 additions & 0 deletions tests/network/user_defined_network/conftest.py
Comment thread
nirdothan marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import pytest
from ocp_resources.user_defined_network import Layer2UserDefinedNetwork
Comment thread
nirdothan marked this conversation as resolved.

from libs.vm import affinity
from tests.network.libs.ip import random_ipv4_address
from utilities.infra import create_ns


@pytest.fixture(scope="module")
def udn_namespace(admin_client):
yield from create_ns(
admin_client=admin_client,
name="test-user-defined-network-ns",
labels={"k8s.ovn.org/primary-user-defined-network": ""},
)
Comment thread
nirdothan marked this conversation as resolved.


@pytest.fixture(scope="module")
def namespaced_layer2_user_defined_network(admin_client, udn_namespace):
with Layer2UserDefinedNetwork(
name="layer2-udn",
namespace=udn_namespace.name,
role="Primary",
subnets=[f"{random_ipv4_address(net_seed=0, host_address=0)}/24"],
ipam={"lifecycle": "Persistent"},
client=admin_client,
) as udn:
udn.wait_for_condition(
condition="NetworkAllocationSucceeded",
status=udn.Condition.Status.TRUE,
)
yield udn
Comment thread
nirdothan marked this conversation as resolved.


@pytest.fixture(scope="module")
def udn_affinity_label():
return affinity.new_label(key_prefix="udn")
Comment thread
nirdothan marked this conversation as resolved.
38 changes: 3 additions & 35 deletions tests/network/user_defined_network/test_user_defined_network.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,27 @@
import ipaddress

import pytest
from ocp_resources.user_defined_network import Layer2UserDefinedNetwork
from ocp_resources.utils.constants import TIMEOUT_1MINUTE

from libs.net.traffic_generator import TcpServer, is_tcp_connection
from libs.net.traffic_generator import VMTcpClient as TcpClient
from libs.net.udn import UDN_BINDING_DEFAULT_PLUGIN_NAME
from libs.net.vmspec import lookup_iface_status, lookup_primary_network
from libs.vm import affinity
from tests.network.libs.ip import random_ipv4_address
from tests.network.libs.vm_factory import udn_vm
from utilities.constants import PUBLIC_DNS_SERVER_IP, TIMEOUT_1MIN
from utilities.infra import create_ns
from utilities.virt import migrate_vm_and_verify

IP_ADDRESS = "ipAddress"
SERVER_PORT = 5201


@pytest.fixture(scope="module")
def udn_namespace(admin_client):
yield from create_ns(
admin_client=admin_client,
name="test-user-defined-network-ns",
labels={"k8s.ovn.org/primary-user-defined-network": ""},
)


@pytest.fixture(scope="module")
def namespaced_layer2_user_defined_network(admin_client, udn_namespace):
with Layer2UserDefinedNetwork(
name="layer2-udn",
namespace=udn_namespace.name,
role="Primary",
subnets=[f"{random_ipv4_address(net_seed=0, host_address=0)}/24"],
ipam={"lifecycle": "Persistent"},
client=admin_client,
) as udn:
udn.wait_for_condition(
condition="NetworkAllocationSucceeded",
status=udn.Condition.Status.TRUE,
)
yield udn


@pytest.fixture(scope="class")
def udn_affinity_label():
return affinity.new_label(key_prefix="udn")


@pytest.fixture(scope="class")
Comment thread
nirdothan marked this conversation as resolved.
def vma_udn(udn_namespace, namespaced_layer2_user_defined_network, udn_affinity_label, admin_client):
with udn_vm(
namespace_name=udn_namespace.name,
name="vma-udn",
client=admin_client,
binding=UDN_BINDING_DEFAULT_PLUGIN_NAME,
template_labels=dict((udn_affinity_label,)),
) as vm:
vm.start(wait=True)
Expand All @@ -68,6 +35,7 @@ def vmb_udn(udn_namespace, namespaced_layer2_user_defined_network, udn_affinity_
namespace_name=udn_namespace.name,
name="vmb-udn",
client=admin_client,
binding=UDN_BINDING_DEFAULT_PLUGIN_NAME,
template_labels=dict((udn_affinity_label,)),
) as vm:
vm.start(wait=True)
Expand Down
Loading