provider network ping simulation
This workload creates a provider vlan network, boots a VM on this network and then pings this VM. Asumming this workload runs on undercloud and both undercloud and compute node use same interface for vlan provider network, for example, ens7f0 in both undercloud and compute nodes (through bridge-mappings) is used for vlan provider network. Ideally for each provider network rally is creating, one vlan interface on top of ens7f0 should be created on undercloud, so that undercloud can ping the VM which is on same provider vlan ip link add link ens7f0 name ens7f0.1 type vlan id 1 ip a a <ipadress_on_provider_net> dev ens7f0.1 However when we want to scale test vlan provider network, we can't create those many vlan interfaces on undercloud. This workload uses scapy to build the vlan packet with all the required content and sends (and receives) icmp packet on the undercloud's interface (i.e ens7f0 in this example) used for provider network. It also sends GARP reply so that VM should be able to resolve the ARP for provider network gateway. As scapy has to be run as a root user, we need to move scapy code to a separate python program. scapy_icmp.py will send the vlan ICMP packet using scapy library as a root user. Main workload will call this python program with required arguments. Change-Id: I2290b06e899b96a2a3f060ea6fedd3323978ebf3
This commit is contained in:
parent
f55cd6c8eb
commit
e01e264ff4
@ -458,6 +458,21 @@ workloads:
|
||||
num_subports: 1
|
||||
ext_net_id:
|
||||
file: ./rally/rally-plugins/netcreate-boot/trunk_network_simulation.yml
|
||||
# provider_phys_net should be provider physical network name.
|
||||
# Please don't create any vlan interfaces on the physical interface used with this provider type.
|
||||
# So use a dedicated interface with provider bridge mappings.
|
||||
# Provide the MAC address of this interface you find in the undercloud.
|
||||
# Workload will prepare a scapy packet using the interface name and mac.
|
||||
- name: provider-netcreate-boot-ping
|
||||
enabled: true
|
||||
enable_dhcp: true
|
||||
num_vms: 1
|
||||
image_name: custom-cirros
|
||||
flavor_name: m1.tiny-cirros
|
||||
provider_phys_net: "provider"
|
||||
iface_name: "ens7f0"
|
||||
iface_mac: "3c:fd:fe:c1:8c:70"
|
||||
file: rally/rally-plugins/netcreate-boot/provider_netcreate_nova_boot_ping.yml
|
||||
|
||||
- name: plugin-workloads
|
||||
enabled: false
|
||||
|
@ -0,0 +1,79 @@
|
||||
# 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.
|
||||
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from rally_openstack import consts
|
||||
from rally_openstack.scenarios.neutron import utils as neutron_utils
|
||||
from rally_openstack.scenarios.vm import utils as vm_utils
|
||||
from rally.task import atomic
|
||||
from rally.task import scenario
|
||||
from rally.task import types
|
||||
from rally.task import validation
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@types.convert(image={"type": "glance_image"}, flavor={"type": "nova_flavor"})
|
||||
@validation.add("image_valid_on_flavor", flavor_param="flavor", image_param="image")
|
||||
@validation.add("required_services", services=[consts.Service.NEUTRON, consts.Service.NOVA])
|
||||
@validation.add("required_platform", platform="openstack", admin=True)
|
||||
@scenario.configure(context={"cleanup@openstack": ["neutron", "nova"], "keypair@openstack": {},
|
||||
"allow_ssh@openstack": None},
|
||||
name="BrowbeatPlugin.create_provider_net_nova_boot_ping", platform="openstack")
|
||||
class CreateProviderNetNovaBootPing(vm_utils.VMScenario,
|
||||
neutron_utils.NeutronScenario):
|
||||
|
||||
def run(self, image, flavor, provider_phys_net, iface_name, iface_mac,
|
||||
num_vms=1, router_create_args=None,
|
||||
network_create_args=None, subnet_create_args=None, **kwargs):
|
||||
network = self._create_network(provider_phys_net)
|
||||
subnet = self._create_subnet(network, subnet_create_args or {})
|
||||
kwargs["nics"] = [{'net-id': network['network']['id']}]
|
||||
server = self._boot_server(image, flavor, **kwargs)
|
||||
|
||||
# ping server
|
||||
internal_network = list(server.networks)[0]
|
||||
server_ip = server.addresses[internal_network][0]["addr"]
|
||||
server_mac = server.addresses[internal_network][0]["OS-EXT-IPS-MAC:mac_addr"]
|
||||
gateway = subnet['subnet']['gateway_ip']
|
||||
vlan = network['network']['provider:segmentation_id']
|
||||
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
file_path = os.path.join(dir_path, "scapy_icmp.py")
|
||||
cmd = ["sudo", file_path, server_ip, server_mac, gateway, iface_mac, iface_name, str(vlan)]
|
||||
proc = subprocess.Popen(cmd)
|
||||
proc.wait()
|
||||
if proc.returncode == 0:
|
||||
LOG.info("Ping to {} is succesful".format(server_ip))
|
||||
else:
|
||||
LOG.info("Ping to {} is failed".format(server_ip))
|
||||
|
||||
@atomic.action_timer("neutron.create_network")
|
||||
def _create_network(self, provider_phys_net):
|
||||
"""Create neutron provider network.
|
||||
|
||||
:param provider_phys_net: provider physical network
|
||||
:returns: neutron network dict
|
||||
"""
|
||||
project_id = self.context["tenant"]["id"]
|
||||
body = {
|
||||
"name": self.generate_random_name(),
|
||||
"tenant_id": project_id,
|
||||
"provider:network_type": "vlan",
|
||||
"provider:physical_network": provider_phys_net
|
||||
}
|
||||
# provider network can be created by admin client only
|
||||
return self.admin_clients("neutron").create_network({"network": body})
|
@ -0,0 +1,46 @@
|
||||
{% set image_name = image_name or 'cirros' %}
|
||||
{% set flavor_name = flavor_name or 'm1.xtiny' %}
|
||||
{% set num_vms = num_vms or 1 %}
|
||||
{% set sla_max_avg_duration = sla_max_avg_duration or 60 %}
|
||||
{% set sla_max_failure = sla_max_failure or 0 %}
|
||||
{% set sla_max_seconds = sla_max_seconds or 60 %}
|
||||
---
|
||||
BrowbeatPlugin.create_provider_net_nova_boot_ping:
|
||||
-
|
||||
args:
|
||||
floating: True
|
||||
flavor:
|
||||
name: '{{flavor_name}}'
|
||||
image:
|
||||
name: '{{image_name}}'
|
||||
num_vms: {{num_vms}}
|
||||
provider_phys_net: '{{provider_phys_net}}'
|
||||
iface_name: '{{iface_name}}'
|
||||
iface_mac: '{{iface_mac}}'
|
||||
network_create_args: {}
|
||||
router_create_args: {}
|
||||
subnet_create_args: {}
|
||||
runner:
|
||||
concurrency: {{concurrency}}
|
||||
times: {{times}}
|
||||
type: "constant"
|
||||
context:
|
||||
users:
|
||||
tenants: 1
|
||||
users_per_tenant: 1
|
||||
quotas:
|
||||
neutron:
|
||||
network: -1
|
||||
port: -1
|
||||
router: -1
|
||||
subnet: -1
|
||||
floatingip: -1
|
||||
nova:
|
||||
instances: -1
|
||||
cores: -1
|
||||
ram: -1
|
||||
sla:
|
||||
max_avg_duration: {{sla_max_avg_duration}}
|
||||
max_seconds_per_iteration: {{sla_max_seconds}}
|
||||
failure_rate:
|
||||
max: {{sla_max_failure}}
|
64
rally/rally-plugins/netcreate-boot/scapy_icmp.py
Executable file
64
rally/rally-plugins/netcreate-boot/scapy_icmp.py
Executable file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/python3
|
||||
# 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.
|
||||
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
|
||||
from scapy.all import srp
|
||||
from scapy.all import Ether
|
||||
from scapy.all import ARP
|
||||
from scapy.all import sendp
|
||||
from scapy.all import Dot1Q
|
||||
from scapy.all import IP
|
||||
from scapy.all import ICMP
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _send_icmp(dst_ip, dst_mac, src_ip, src_mac, iface, vlan):
|
||||
# send 1 icmp packet so that dest VM can send ARP packet to resolve gateway
|
||||
sendp(Ether(dst=dst_mac, src=src_mac)/Dot1Q(vlan=int(vlan))/IP(dst=dst_ip)/ICMP(),
|
||||
iface=iface, verbose=0)
|
||||
bcast = "ff:ff:ff:ff:ff:ff"
|
||||
# Send GARP using ARP reply method
|
||||
sendp(Ether(dst=bcast,src=src_mac)/Dot1Q(vlan=int(vlan))/ARP(
|
||||
op=2,psrc=src_ip, hwsrc=src_mac, hwdst=src_mac, pdst=src_ip), iface=iface, verbose=0)
|
||||
# send ICMP and validate reply
|
||||
ans, unans = srp(Ether(dst=dst_mac, src=src_mac)/Dot1Q(vlan=int(vlan))/IP(dst=dst_ip)/ICMP(),
|
||||
iface=iface, timeout=5, verbose=0)
|
||||
if (str(ans).find('ICMP:0') == -1):
|
||||
for snd, rcv in ans:
|
||||
if (rcv.summary().find(dst_ip) != -1):
|
||||
LOG.info("Ping to {} is succesful".format(dst_ip))
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def main(args):
|
||||
dst_ip, dst_mac, src_ip, src_mac, iface, vlan = args[1:]
|
||||
attempts = 0
|
||||
max_attempts = 120
|
||||
while attempts < max_attempts:
|
||||
if _send_icmp(dst_ip, dst_mac, src_ip, src_mac, iface, vlan):
|
||||
LOG.info("Ping to {} is succesful".format(dst_ip))
|
||||
return 0
|
||||
LOG.info("Ping to {} is failed, attempt {}".format(dst_ip, attempts))
|
||||
attempts += 1
|
||||
time.sleep(5)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv)
|
Loading…
x
Reference in New Issue
Block a user