| # SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) |
| # Copyright (c) 2020 Nvidia All rights reserved. See COPYING file |
| """ |
| Test module for pyverbs' flow module. |
| """ |
| from tests.base import RDMATestCase, RawResources, PyverbsRDMAError |
| from pyverbs.spec import EthSpec, Ipv4ExtSpec, Ipv6Spec, TcpUdpSpec |
| from tests.utils import requires_cap_net_raw, PacketConsts, requires_eth |
| from pyverbs.flow import FlowAttr, Flow |
| from pyverbs.libibverbs_enums import ibv_flow_spec_type |
| import tests.utils as u |
| import unittest |
| import socket |
| import errno |
| |
| |
| class FlowRes(RawResources): |
| def __init__(self, dev_name, ib_port, gid_index): |
| """ |
| Initialize Flow resources based on Raw resources that include Raw QP. |
| :param dev_name: Device name to be used |
| :param ib_port: IB port of the device to use |
| :param gid_index: Which GID index to use |
| """ |
| super().__init__(dev_name=dev_name, ib_port=ib_port, |
| gid_index=gid_index) |
| |
| @requires_cap_net_raw() |
| @requires_eth() |
| def create_qps(self): |
| super().create_qps() |
| |
| @staticmethod |
| def create_eth_spec(ether_type=PacketConsts.ETHER_TYPE_IPV4): |
| """ |
| Creates ethernet spec that matches on ethertype, source and destination |
| macs. |
| :param ether_type: IPv4 or IPv6 |
| :return: created ethernet spec |
| """ |
| eth_spec = EthSpec(ether_type=ether_type, dst_mac=PacketConsts.DST_MAC) |
| eth_spec.src_mac = PacketConsts.SRC_MAC |
| eth_spec.src_mac_mask = PacketConsts.SRC_MAC |
| return eth_spec |
| |
| def create_ip_spec(self, ver=PacketConsts.IP_V4, |
| next_hdr=socket.IPPROTO_UDP): |
| """ |
| Creates IPv4 or IPv6 spec that matches on source and destination ips. |
| :param ver: IP version |
| :param next_hdr: Next header type |
| :return: created IPv4 or IPv6 spec |
| """ |
| if ver == PacketConsts.IP_V4: |
| ip_spec = Ipv4ExtSpec(src_ip=PacketConsts.SRC_IP, |
| dst_ip=PacketConsts.DST_IP, proto=next_hdr) |
| else: |
| ip_spec = Ipv6Spec(src_ip=PacketConsts.SRC_IP6, |
| dst_ip=PacketConsts.DST_IP6, next_hdr=next_hdr) |
| return ip_spec |
| |
| @staticmethod |
| def create_tcp_udp_spec(spec_type): |
| """ |
| Creates TcpUdp spec that matches on ethertype, source and destination |
| macs. |
| :param spec_type: Spec type TCP or UDP |
| :return: TCP or UDP spec |
| """ |
| spec = TcpUdpSpec(spec_type, src_port=PacketConsts.SRC_PORT, |
| dst_port=PacketConsts.DST_PORT) |
| return spec |
| |
| def create_flow(self, specs=None): |
| """ |
| Creates flow to match on provided specs. |
| :param specs: list of specs to match on |
| :return: created flow |
| """ |
| specs = [] if specs is None else specs |
| flow_attr = FlowAttr(num_of_specs=len(specs), port=self.ib_port) |
| for spec in specs: |
| flow_attr.specs.append(spec) |
| try: |
| flow = self._create_flow(flow_attr) |
| except PyverbsRDMAError as ex: |
| if ex.error_code == errno.EOPNOTSUPP: |
| raise unittest.SkipTest('Flow creation is not supported') |
| raise ex |
| return flow |
| |
| def _create_flow(self, flow_attr): |
| return Flow(self.qp, flow_attr) |
| |
| |
| class FlowTest(RDMATestCase): |
| """ |
| Test various functionalities of the Flow class. |
| """ |
| def setUp(self): |
| super().setUp() |
| self.iters = 10 |
| self.server = None |
| self.client = None |
| |
| def flow_traffic(self, specs, l3=PacketConsts.IP_V4, |
| l4=PacketConsts.UDP_PROTO): |
| """ |
| Execute raw ethernet traffic with given specs flow. |
| :param specs: list of specs |
| :param l3: Packet layer 3 type: 4 for IPv4 or 6 for IPv6 |
| :param l4: Packet layer 4 type: 'tcp' or 'udp' |
| :return: None |
| """ |
| self.flow = self.server.create_flow(specs) |
| u.raw_traffic(self.client, self.server, self.iters, l3, l4) |
| |
| def test_eth_spec_flow_traffic(self): |
| self.create_players(FlowRes) |
| self.flow_traffic([self.server.create_eth_spec()]) |
| |
| def test_ipv4_spec_flow_traffic(self): |
| self.create_players(FlowRes) |
| if self.is_eth_and_has_roce_hw_bug(): |
| raise unittest.SkipTest(f'Device {self.dev_name} doesn\'t support Ipv4ExtSpec') |
| self.flow_traffic([self.server.create_ip_spec()]) |
| |
| def test_ipv6_spec_flow_traffic(self): |
| self.create_players(FlowRes) |
| eth_spec = self.server.create_eth_spec(PacketConsts.ETHER_TYPE_IPV6) |
| if self.is_eth_and_has_roce_hw_bug(): |
| raise unittest.SkipTest(f'Device {self.dev_name} doesn\'t support Ipv6Spec') |
| ip_spec = self.server.create_ip_spec(PacketConsts.IP_V6) |
| self.flow_traffic([eth_spec, ip_spec], PacketConsts.IP_V6) |
| |
| def test_udp_spec_flow_traffic(self): |
| self.create_players(FlowRes) |
| eth_spec = self.server.create_eth_spec() |
| if self.is_eth_and_has_roce_hw_bug(): |
| raise unittest.SkipTest(f'Device {self.dev_name} doesn\'t support Ipv4ExtSpec') |
| ip_spec = self.server.create_ip_spec() |
| udp_spec = self.server.create_tcp_udp_spec(ibv_flow_spec_type.IBV_FLOW_SPEC_UDP) |
| self.flow_traffic([eth_spec, ip_spec, udp_spec], PacketConsts.IP_V4, |
| PacketConsts.UDP_PROTO) |
| |
| def test_tcp_spec_flow_traffic(self): |
| self.create_players(FlowRes) |
| eth_spec = self.server.create_eth_spec(PacketConsts.ETHER_TYPE_IPV6) |
| if self.is_eth_and_has_roce_hw_bug(): |
| raise unittest.SkipTest(f'Device {self.dev_name} doesn\'t support Ipv6Spec') |
| ip_spec = self.server.create_ip_spec(PacketConsts.IP_V6, |
| socket.IPPROTO_TCP) |
| tcp_spec = self.server.create_tcp_udp_spec(ibv_flow_spec_type.IBV_FLOW_SPEC_TCP) |
| self.flow_traffic([eth_spec, ip_spec, tcp_spec], PacketConsts.IP_V6, |
| PacketConsts.TCP_PROTO) |