From 18479deef4bc6fba143492f538cd4139c38e44ab Mon Sep 17 00:00:00 2001 From: "haiyanX1.zhang" Date: Tue, 17 Sep 2019 03:00:26 +0000 Subject: Add vpp loadbalancer maglev mode test suite Change-Id: I61555ba566efef0a2151db9a30bf7f5d9ccad1df Signed-off-by: haiyanx1.zhang --- resources/api/vpp/supported_crcs.yaml | 18 +++ resources/libraries/python/LoadBalancerUtil.py | 176 +++++++++++++++++++++ resources/libraries/robot/lb/load_balancer.robot | 64 ++++++++ resources/libraries/robot/shared/default.robot | 1 + .../trex/trex-sl-2n-ethip4udp-lb.py | 106 +++++++++++++ 5 files changed, 365 insertions(+) create mode 100644 resources/libraries/python/LoadBalancerUtil.py create mode 100644 resources/libraries/robot/lb/load_balancer.robot create mode 100755 resources/traffic_profiles/trex/trex-sl-2n-ethip4udp-lb.py (limited to 'resources') diff --git a/resources/api/vpp/supported_crcs.yaml b/resources/api/vpp/supported_crcs.yaml index 33a1349393..5fb16c42d1 100644 --- a/resources/api/vpp/supported_crcs.yaml +++ b/resources/api/vpp/supported_crcs.yaml @@ -254,6 +254,15 @@ policer_classify_set_interface: '0xe09537b0' # dev policer_classify_set_interface_reply: '0xe8d4e804' # dev # 4x^ tc01-64B-ethip4-ip4base-ipolicemarkbase-dev + # ^^ tc01-64B-1c-ethip4-loadbalancer-maglev/l3dsr/nat4-mrr + lb_conf: '0x22ddb739' # perf + lb_conf_reply: '0xe8d4e804' # perf + lb_add_del_vip: '0xd15b7ddc' # perf + lb_add_del_vip_reply: '0xe8d4e804' # perf + lb_add_del_as: '0x78628987' # perf + lb_add_del_as_reply: '0xe8d4e804' # perf + lb_add_del_intf_nat4: '0x47d6e753' # perf + lb_add_del_intf_nat4_reply: '0xe8d4e804' # perf # https://gerrit.fd.io/r/c/vpp/+/21490 @@ -480,6 +489,15 @@ policer_classify_set_interface: '0xe09537b0' # dev policer_classify_set_interface_reply: '0xe8d4e804' # dev # 4x^ tc01-64B-ethip4-ip4base-ipolicemarkbase-dev + # ^^ tc01-64B-1c-ethip4-loadbalancer-maglev/l3dsr/nat4-mrr + lb_conf: '0x22ddb739' # perf + lb_conf_reply: '0xe8d4e804' # perf + lb_add_del_vip: '0xd15b7ddc' # perf + lb_add_del_vip_reply: '0xe8d4e804' # perf + lb_add_del_as: '0x78628987' # perf + lb_add_del_as_reply: '0xe8d4e804' # perf + lb_add_del_intf_nat4: '0x47d6e753' # perf + lb_add_del_intf_nat4_reply: '0xe8d4e804' # perf # Hint to see the currently used command messages: diff --git a/resources/libraries/python/LoadBalancerUtil.py b/resources/libraries/python/LoadBalancerUtil.py new file mode 100644 index 0000000000..26bf965c39 --- /dev/null +++ b/resources/libraries/python/LoadBalancerUtil.py @@ -0,0 +1,176 @@ +# Copyright (c) 2019 Intel and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Loadbalancer util library.""" + +from socket import htonl +from ipaddress import ip_address +from resources.libraries.python.topology import NodeType +from resources.libraries.python.PapiExecutor import PapiSocketExecutor + +class LoadBalancerUtil(object): + """Basic Loadbalancer parameter configuration.""" + + @staticmethod + def vpp_lb_conf(node, **kwargs): + """Config global parameters for loadbalancer. + + :param node: Node where the interface is. + :param kwargs: Optional key-value arguments: + + ip4_src_addr: IPv4 address to be used as source for IPv4 traffic. + (str) + ip6_src_addr: IPv6 address to be used as source for IPv6 traffic. + (str) + flow_timeout: Time in seconds after which, if no packet is received + for a given flow, the flow is removed from the + established flow table. (int) + buckets_per_core: Number of buckets *per worker thread* in the + established flow table (int) + + :type node: dict + :type kwargs: dict + :returns: Nothing. + :raises ValueError: If the node has an unknown node type. + """ + if node['type'] == NodeType.DUT: + ip4_src_addr = ip_address(unicode(kwargs.pop('ip4_src_addr', + '255.255.255.255'))) + ip6_src_addr = ip_address(unicode(kwargs.pop('ip6_src_addr',\ + 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'))) + flow_timeout = kwargs.pop('flow_timeout', 40) + sticky_buckets_per_core = kwargs.pop('buckets_per_core', 1024) + + cmd = 'lb_conf' + err_msg = 'Failed to set lb conf on host {host}'.format( + host=node['host']) + + args = dict(ip4_src_address=str(ip4_src_addr), + ip6_src_address=str(ip6_src_addr), + sticky_buckets_per_core=sticky_buckets_per_core, + flow_timeout=flow_timeout) + + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args).get_reply(err_msg) + else: + raise ValueError('Node {host} has unknown NodeType: "{type}"' + .format(host=node['host'], type=node['type'])) + + @staticmethod + def vpp_lb_add_del_vip(node, **kwargs): + """Config vip for loadbalancer. + + :param node: Node where the interface is. + :param kwargs: Optional key-value arguments: + + vip_addr: IPv4 address to be used as source for IPv4 traffic. (str) + protocol: tcp or udp. (int) + port: destination port. (int) + encap: encap is ip4 GRE(0) or ip6 (1GRE) or L3DSR(2) or NAT4(3) or + NAT6(4). (int) + dscp: dscp bit corresponding to VIP + type: service type + target_port: Pod's port corresponding to specific service + node_port: Node's port + new_len: Size of the new connections flow table used + for this VIP + is_del: 1 if the VIP should be removed otherwise 0. + + :type node: dict + :type kwargs: dict + :returns: Nothing. + :raises ValueError: If the node has an unknown node type. + """ + if node['type'] == NodeType.DUT: + vip_addr = kwargs.pop('vip_addr', '0.0.0.0') + protocol = kwargs.pop('protocol', 255) + port = kwargs.pop('port', 0) + encap = kwargs.pop('encap', 0) + dscp = kwargs.pop('dscp', 0) + srv_type = kwargs.pop('srv_type', 0) + target_port = kwargs.pop('target_port', 0) + node_port = kwargs.pop('node_port', 0) + new_len = kwargs.pop('new_len', 1024) + is_del = kwargs.pop('is_del', 0) + + cmd = 'lb_add_del_vip' + err_msg = 'Failed to add vip on host {host}'.format( + host=node['host']) + + vip_addr = ip_address(unicode(vip_addr)).packed + args = dict(pfx={'len': 128, + 'address': {'un': {'ip4': vip_addr}, 'af': 0}}, + protocol=protocol, + port=port, + encap=htonl(encap), + dscp=dscp, + type=srv_type, + target_port=target_port, + node_port=node_port, + new_flows_table_length=int(new_len), + is_del=is_del) + + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args).get_reply(err_msg) + else: + raise ValueError('Node {host} has unknown NodeType: "{type}"' + .format(host=node['host'], type=node['type'])) + + @staticmethod + def vpp_lb_add_del_as(node, **kwargs): + """Config AS for Loadbalancer. + + :param node: Node where the interface is. + :param kwargs: Optional key-value arguments: + + vip_addr: IPv4 address to be used as source for IPv4 traffic. (str) + protocol: tcp or udp. (int) + port: destination port. (int) + as_addr: The application server address. (str) + is_del: 1 if the VIP should be removed otherwise 0. (int) + is_flush: 1 if the sessions related to this AS should be flushed + otherwise 0. (int) + + :type node: dict + :type kwargs: dict + :returns: Nothing. + :raises ValueError: If the node has an unknown node type. + """ + if node['type'] == NodeType.DUT: + cmd = 'lb_add_del_as' + err_msg = 'Failed to add lb as on host {host}'.format( + host=node['host']) + + vip_addr = kwargs.pop('vip_addr', '0.0.0.0') + protocol = kwargs.pop('protocol', 255) + port = kwargs.pop('port', 0) + as_addr = kwargs.pop('as_addr', '0.0.0.0') + is_del = kwargs.pop('is_del', 0) + is_flush = kwargs.pop('is_flush', 0) + + vip_addr = ip_address(unicode(vip_addr)).packed + as_addr = ip_address(unicode(as_addr)).packed + + args = dict(pfx={'len': 128, + 'address': {'un': {'ip4': vip_addr}, 'af': 0}}, + protocol=protocol, + port=port, + as_address={'un': {'ip4': as_addr}, 'af': 0}, + is_del=is_del, + is_flush=is_flush) + + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args).get_reply(err_msg) + else: + raise ValueError('Node {host} has unknown NodeType: "{type}"' + .format(host=node['host'], type=node['type'])) diff --git a/resources/libraries/robot/lb/load_balancer.robot b/resources/libraries/robot/lb/load_balancer.robot new file mode 100644 index 0000000000..4dc66447d2 --- /dev/null +++ b/resources/libraries/robot/lb/load_balancer.robot @@ -0,0 +1,64 @@ +# Copyright (c) 2019 Intel and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +*** Settings *** +| Library | Collections +| Library | String + +| Library | resources.libraries.python.InterfaceUtil +| Library | resources.libraries.python.IPUtil +| Library | resources.libraries.python.topology.Topology +| Library | resources.libraries.python.LoadBalancerUtil +| Library | resources.libraries.python.NodePath +| ... +| Resource | resources/libraries/robot/shared/interfaces.robot +| ... +| Documentation | LoadBalancer suite keywords - configuration + +*** Keywords *** +| Initialize loadbalancer maglev +| | [Documentation] +| | ... | Set UP state on VPP interfaces in path on nodes in 2-node +| | ... | circular topology. Get the interface MAC addresses and setup ARP on +| | ... | all VPP interfaces. Setup IPv4 addresses with /24 prefix on DUT-TG +| | ... | links. +| | ... +| | Set interfaces in path up +| | ... +| | ${fib_table}= | Set Variable | ${0} +| | Add Fib Table | ${dut1} | ${fib_table} +| | Assign Interface To Fib Table | ${dut1} | ${dut1_if1} | ${fib_table} +| | Assign Interface To Fib Table | ${dut1} | ${dut1_if2} | ${fib_table} +| | ... +| | VPP Interface Set IP Address | ${dut1} | ${dut1_if1} +| | ... | 192.168.50.72 | 24 +| | VPP Interface Set IP Address | ${dut1} | ${dut1_if2} +| | ... | 192.168.60.73 | 24 +| | ... +| | VPP Add IP Neighbor | ${dut1} | ${dut1_if2} | 192.168.60.74 | ${tg_if2_mac} +| | VPP Add IP Neighbor | ${dut1} | ${dut1_if2} | 192.168.60.75 | ${tg_if2_mac} +| | VPP Add IP Neighbor | ${dut1} | ${dut1_if2} | 192.168.60.76 | ${tg_if2_mac} +| | VPP Add IP Neighbor | ${dut1} | ${dut1_if2} | 192.168.60.77 | ${tg_if2_mac} +| | VPP Add IP Neighbor | ${dut1} | ${dut1_if2} | 192.168.60.78 | ${tg_if2_mac} +| | VPP Add IP Neighbor | ${dut1} | ${dut1_if2} | 192.168.60.79 | ${tg_if2_mac} +| | ... +| | Vpp Route Add | ${dut1} | 192.168.60.0 | 24 | interface=${dut1_if2} +| | ... +| | Vpp Lb Conf | ${dut1} | ip4_src_addr=192.168.60.73 | buckets_per_core=${128} +| | Vpp Lb Add Del Vip | ${dut1} | vip_addr=90.1.2.1 | encap=${0} | new_len=${1024} +| | Vpp Lb Add Del As | ${dut1} | vip_addr=90.1.2.1 | as_addr=192.168.60.74 +| | Vpp Lb Add Del As | ${dut1} | vip_addr=90.1.2.1 | as_addr=192.168.60.75 +| | Vpp Lb Add Del As | ${dut1} | vip_addr=90.1.2.1 | as_addr=192.168.60.76 +| | Vpp Lb Add Del As | ${dut1} | vip_addr=90.1.2.1 | as_addr=192.168.60.77 +| | Vpp Lb Add Del As | ${dut1} | vip_addr=90.1.2.1 | as_addr=192.168.60.78 +| | Vpp Lb Add Del As | ${dut1} | vip_addr=90.1.2.1 | as_addr=192.168.60.79 diff --git a/resources/libraries/robot/shared/default.robot b/resources/libraries/robot/shared/default.robot index c560dcf8c2..36460d1ab9 100644 --- a/resources/libraries/robot/shared/default.robot +++ b/resources/libraries/robot/shared/default.robot @@ -41,6 +41,7 @@ | Library | resources.libraries.python.VppCounters | Library | resources.libraries.python.VPPUtil | ... +| Resource | resources/libraries/robot/lb/load_balancer.robot | Resource | resources/libraries/robot/crypto/ipsec.robot | Resource | resources/libraries/robot/features/acl.robot | Resource | resources/libraries/robot/features/gbp.robot diff --git a/resources/traffic_profiles/trex/trex-sl-2n-ethip4udp-lb.py b/resources/traffic_profiles/trex/trex-sl-2n-ethip4udp-lb.py new file mode 100755 index 0000000000..bcd5328edd --- /dev/null +++ b/resources/traffic_profiles/trex/trex-sl-2n-ethip4udp-lb.py @@ -0,0 +1,106 @@ +# Copyright (c) 2019 Intel and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Stream profile for T-rex traffic generator. + +Stream profile: + - Packet: ETH / IP / UDP + - Direction 0 --> 1: + - Source IP address range: 192.168.50.74 - 192.168.50.79 + - Destination IP address range: 90.1.2.1 + - Direction 1 --> 0: + - Source IP address range: 192.168.60.74 - 192.168.60.79 + - Destination IP address range: 192.168.50.74 - 192.168.50.79 +""" + +from trex.stl.api import * +from profile_trex_stateless_base_class import TrafficStreamsBaseClass + + +class TrafficStreams(TrafficStreamsBaseClass): + """Stream profile.""" + + def __init__(self): + """Initialization and setting of streams' parameters.""" + + super(TrafficStreamsBaseClass, self).__init__() + + # IPs used in packet headers. + self.p1_src_start_ip = '192.168.50.74' + self.p1_src_end_ip = '192.168.50.79' + self.p1_dst_start_ip = '90.1.2.1' + + self.p2_src_start_ip = '192.168.60.74' + self.p2_src_end_ip = '192.168.60.79' + self.p2_dst_start_ip = '192.168.50.74' + self.p2_dst_end_ip = '192.168.50.79' + + # UDP ports used in packet headers. + self.p1_src_udp_port = 63 + self.p1_dst_udp_port = 20000 + + self.p2_src_udp_port = 3307 + self.p2_dst_udp_port = 63 + + def define_packets(self): + """Defines the packets to be sent from the traffic generator. + + Packet definition: | ETH | IP | UDP + + :returns: Packets to be sent from the traffic generator. + :rtype: tuple + """ + + # Direction 0 --> 1 + base_pkt_a = Ether() / IP(src=self.p1_src_start_ip, + dst=self.p1_dst_start_ip, + proto=17) / UDP(sport=self.p1_src_udp_port, + dport=self.p1_dst_udp_port) + # Direction 1 --> 0 + base_pkt_b = Ether() / IP(src=self.p2_src_start_ip, + dst=self.p2_dst_start_ip, + proto=17) / UDP(sport=self.p2_src_udp_port, + dport=self.p2_dst_udp_port) + + # Direction 0 --> 1 + vm1 = STLScVmRaw([STLVmFlowVar(name="src", + min_value=self.p1_src_start_ip, + max_value=self.p1_src_end_ip, + size=4, op="inc"), + STLVmWrFlowVar(fv_name="src", pkt_offset="IP.src"), + STLVmFixIpv4(offset="IP")]) + # Direction 1 --> 0 + vm2 = STLScVmRaw([STLVmFlowVar(name="src", + min_value=self.p2_src_start_ip, + max_value=self.p2_src_end_ip, + size=4, op="inc"), + STLVmWrFlowVar(fv_name="src", pkt_offset="IP.src"), + STLVmFlowVar(name="dst", + min_value=self.p2_dst_start_ip, + max_value=self.p2_dst_end_ip, + size=4, op="inc"), + STLVmWrFlowVar(fv_name="dst", pkt_offset="IP.dst"), + STLVmFixIpv4(offset="IP")]) + + return base_pkt_a, base_pkt_b, vm1, vm2 + + +def register(): + """Register this traffic profile to T-rex. + + Do not change this function. + + :return: Traffic streams. + :rtype: Object + """ + return TrafficStreams() -- cgit 1.2.3-korg