From: Amos Kong <akong@redhat.com>
To: autotest@vger.kernel.org
Cc: lmr@redhat.com, kvm@vger.kernel.org
Subject: [PATCH v2 01/17] KVM-test: Add a new macaddress pool algorithm
Date: Mon, 23 Aug 2010 16:51:55 +0800 [thread overview]
Message-ID: <20100823085155.19173.55699.stgit@190> (raw)
In-Reply-To: <20100823084745.19173.61655.stgit@190>
Old method uses the addresses in the config files which could lead serious
problem when multiple tests running in different hosts.
This patch adds a new macaddress pool algorithm, it generates the mac prefix
based on mac address of the host, and fix it to correspond to IEEE802.
When user have set the mac_prefix in the config file, we should use it instead
of the dynamic generated mac prefix.
Add a parameter like 'preserve_mac', to preserve the original mac address, for
things like migration.
MAC addresses are recorded into a dictionary 'address_pool' in following
format: {{'20100310-165222-Wt7l:0' : 'AE:9D:94:6A:9b:f9'},...}
20100310-165222-Wt7l : instance attribute of VM
0 : index of NIC
AE:9D:94:6A:9b:f9 : mac address
Use 'vm instance' + 'nic index' as the key, macaddress is the value.
Changs from v1:
- Use 'vm instance' + 'nic index' as the key of address_pool, address is value.
- Put 'mac_lock' and 'address_pool' to '/tmp', for sharing them to other
autotest instances running on the same host.
- Change function names for less confusion.
- Do not copy 'vm.instance' in vm.clone()
- Split 'adding get_ifname function' to another patch
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Feng Yang <fyang@redhat.com>
Signed-off-by: Amos Kong <akong@redhat.com>
---
0 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/client/tests/kvm/kvm_utils.py b/client/tests/kvm/kvm_utils.py
index fb2d1c2..b019fc5 100644
--- a/client/tests/kvm/kvm_utils.py
+++ b/client/tests/kvm/kvm_utils.py
@@ -5,6 +5,7 @@ KVM test utility functions.
"""
import time, string, random, socket, os, signal, re, logging, commands, cPickle
+import fcntl, shelve
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error, logging_config
import kvm_subprocess
@@ -82,6 +83,79 @@ def get_sub_dict_names(dict, keyword):
# Functions related to MAC/IP addresses
+def generate_mac_address(root_dir, instance_vm, nic_index, prefix='00:11:22:33:'):
+ """
+ Random generate a MAC address and add it to the MAC pool.
+
+ Try to generate macaddress based on the mac address prefix, add it to a
+ dictionary 'address_pool'.
+ key = VM instance + nic index, value = mac address
+ {['20100310-165222-Wt7l:0'] : 'AE:9D:94:6A:9b:f9'}
+
+ @param root_dir: Root dir for kvm
+ @param instance_vm: Here we use instance of vm
+ @param nic_index: The index of nic
+ @param prefix: Prefix of mac address
+ @Return: Return mac address.
+ """
+ lock_file = open("/tmp/mac_lock", 'w')
+ fcntl.lockf(lock_file.fileno() ,fcntl.LOCK_EX)
+ mac_pool = shelve.open("/tmp/address_pool", writeback=False)
+ found = False
+ key = "%s:%s" % (instance_vm, nic_index)
+
+ if mac_pool.get(key):
+ found = True
+ mac = mac_pool.get(key)
+
+ while not found:
+ suffix = "%02x:%02x" % (random.randint(0x00,0xfe),
+ random.randint(0x00,0xfe))
+ mac = prefix + suffix
+ mac_list = mac.split(":")
+ # Clear multicast bit
+ mac_list[0] = int(mac_list[0],16) & 0xfe
+ # Set local assignment bit (IEEE802)
+ mac_list[0] = mac_list[0] | 0x02
+ mac_list[0] = "%02x" % mac_list[0]
+ mac = ":".join(mac_list)
+ if mac in [mac_pool.get(k) for k in mac_pool.keys()]:
+ continue
+ mac_pool[key] = mac
+ found = True
+ logging.debug("Generated mac addr %s " % mac)
+
+ mac_pool.close()
+ fcntl.lockf(lock_file.fileno(), fcntl.LOCK_UN)
+ lock_file.close()
+ return mac
+
+
+def free_mac_address(root_dir, instance_vm, nic_index):
+ """
+ Free mac address from address pool
+
+ @param root_dir: Root dir for kvm
+ @param instance_vm: Here we use instance attribute of vm
+ @param nic_index: The index of nic
+ """
+ lock_file = open("/tmp/mac_lock", 'w')
+ fcntl.lockf(lock_file.fileno() ,fcntl.LOCK_EX)
+ mac_pool = shelve.open("/tmp/address_pool", writeback=False)
+ key = "%s:%s" % (instance_vm, nic_index)
+ if not mac_pool or (not key in mac_pool.keys()):
+ logging.debug("Nic not present in the MAC pool, not modifying pool")
+ logging.debug("Key : %s" % key)
+ logging.debug("pool is %s" % mac_pool)
+ else:
+ logging.debug("Freeing mac addr %s" % mac_pool[key])
+ mac_pool.pop(key)
+
+ mac_pool.close()
+ fcntl.lockf(lock_file.fileno(), fcntl.LOCK_UN)
+ lock_file.close()
+
+
def mac_str_to_int(addr):
"""
Convert MAC address string to integer.
diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
index bdc9aab..6812c98 100755
--- a/client/tests/kvm/kvm_vm.py
+++ b/client/tests/kvm/kvm_vm.py
@@ -5,7 +5,7 @@ Utility classes and functions to handle Virtual Machine creation using qemu.
@copyright: 2008-2009 Red Hat Inc.
"""
-import time, socket, os, logging, fcntl, re, commands, glob
+import time, socket, os, logging, fcntl, re, commands, shelve, glob
import kvm_utils, kvm_subprocess, kvm_monitor, rss_file_transfer
from autotest_lib.client.common_lib import error
from autotest_lib.client.bin import utils
@@ -117,6 +117,7 @@ class VM:
self.params = params
self.root_dir = root_dir
self.address_cache = address_cache
+ self.mac_prefix = params.get('mac_prefix')
self.netdev_id = []
# Find a unique identifier for this VM
@@ -126,8 +127,15 @@ class VM:
if not glob.glob("/tmp/*%s" % self.instance):
break
+ if self.mac_prefix is None:
+ s, o = commands.getstatusoutput("ifconfig eth0")
+ if s == 0:
+ mac = re.findall("HWaddr (\S*)", o)[0]
+ self.mac_prefix = '00' + mac[8:] + ':'
+
- def clone(self, name=None, params=None, root_dir=None, address_cache=None):
+ def clone(self, name=None, params=None, root_dir=None,
+ address_cache=None, preserve_mac=True):
"""
Return a clone of the VM object with optionally modified parameters.
The clone is initially not alive and needs to be started using create().
@@ -138,6 +146,7 @@ class VM:
@param params: Optional new VM creation parameters
@param root_dir: Optional new base directory for relative filenames
@param address_cache: A dict that maps MAC addresses to IP addresses
+ @param preserve_mac: Clone mac address or not.
"""
if name is None:
name = self.name
@@ -147,7 +156,20 @@ class VM:
root_dir = self.root_dir
if address_cache is None:
address_cache = self.address_cache
- return VM(name, params, root_dir, address_cache)
+ vm = VM(name, params, root_dir, address_cache)
+ if preserve_mac:
+ vlan = 0
+ for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
+ nic_params = kvm_utils.get_sub_dict(params, nic_name)
+ vm.set_macaddr(self.get_macaddr(vlan), vlan, True)
+ vlan += 1
+ return vm
+
+
+ def free_mac_addresses(self):
+ nic_num = len(kvm_utils.get_sub_dict_names(self.params, "nics"))
+ for i in range(nic_num):
+ kvm_utils.free_mac_address(self.root_dir, self.instance, i)
def make_qemu_command(self, name=None, params=None, root_dir=None):
@@ -386,6 +408,13 @@ class VM:
mac = None
if "address_index" in nic_params:
mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
+ self.set_macaddr(mac=mac, nic_index=vlan)
+ else:
+ mac = kvm_utils.generate_mac_address(self.root_dir,
+ self.instance,
+ vlan,
+ self.mac_prefix)
+
qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
self.netdev_id[vlan])
# Handle the '-net tap' or '-net user' part
@@ -749,11 +778,15 @@ class VM:
logging.debug("Shutdown command sent; waiting for VM "
"to go down...")
if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
- logging.debug("VM is down")
+ logging.debug("VM is down, freeing mac address.")
+ self.free_mac_addresses()
return
finally:
session.close()
+ # Free mac addresses
+ self.free_mac_addresses()
+
if self.monitor:
# Try to destroy with a monitor command
logging.debug("Trying to kill VM with monitor command...")
@@ -879,10 +912,13 @@ class VM:
nic_name = nics[index]
nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
if nic_params.get("nic_mode") == "tap":
- mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
+ mac = self.get_macaddr(index)
if not mac:
logging.debug("MAC address unavailable")
return None
+ mac = mac.lower()
+ ip = None
+
if not ip or nic_params.get("always_use_tcpdump") == "yes":
# Get the IP address from the cache
ip = self.address_cache.get(mac)
@@ -895,6 +931,7 @@ class VM:
for nic in nics]
macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
for dict in nic_dicts]
+ macs.append(mac)
if not kvm_utils.verify_ip_address_ownership(ip, macs):
logging.debug("Could not verify MAC-IP address mapping: "
"%s ---> %s" % (mac, ip))
@@ -923,6 +960,42 @@ class VM:
"redirected" % port)
return self.redirs.get(port)
+ def get_macaddr(self, nic_index=0):
+ """
+ Return the macaddr of guest nic.
+
+ @param nic_index: Index of the NIC
+ """
+ mac_pool = shelve.open("/tmp/address_pool", writeback=False)
+ key = "%s:%s" % (self.instance, nic_index)
+ if key in mac_pool.keys():
+ return mac_pool[key]
+ else:
+ return None
+
+ def set_macaddr(self, mac, nic_index=0, shareable=False):
+ """
+ Set mac address for guest. Note: It just update address pool.
+
+ @param mac: address will set to guest
+ @param nic_index: Index of the NIC
+ @param shareable: Where VM can share mac with other VM or not.
+ """
+ lock_file = open("/tmp/mac_lock", 'w')
+ fcntl.lockf(lock_file.fileno() ,fcntl.LOCK_EX)
+ mac_pool = shelve.open("/tmp/address_pool", writeback=False)
+ key = "%s:%s" % (self.instance, nic_index)
+
+ if not mac in [mac_pool[i] for i in mac_pool.keys()]:
+ mac_pool[key] = mac
+ else:
+ if shareable:
+ mac_pool[key] = mac
+ else:
+ logging.error("Mac address already be used!")
+ mac_pool.close()
+ fcntl.lockf(lock_file.fileno(), fcntl.LOCK_UN)
+ lock_file.close()
def get_pid(self):
"""
diff --git a/client/tests/kvm/tests_base.cfg.sample b/client/tests/kvm/tests_base.cfg.sample
index cb35f5e..26760f6 100644
--- a/client/tests/kvm/tests_base.cfg.sample
+++ b/client/tests/kvm/tests_base.cfg.sample
@@ -54,7 +54,7 @@ guest_port_remote_shell = 22
nic_mode = user
#nic_mode = tap
nic_script = scripts/qemu-ifup
-address_index = 0
+#address_index = 0
run_tcpdump = yes
# Misc
next prev parent reply other threads:[~2010-08-23 8:48 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-08-23 8:51 [PATCH v2 00/17] Patchset of network related subtests Amos Kong
2010-08-23 8:51 ` Amos Kong [this message]
2010-08-23 8:52 ` [PATCH v2 02/17] Add a get_ifname function Amos Kong
2010-08-23 8:52 ` [PATCH v2 03/17] KVM Test: Add a function get_interface_name() to kvm_test_utils.py Amos Kong
2010-08-23 8:52 ` [PATCH v2 04/17] KVM Test: Add a common ping module for network related tests Amos Kong
2010-08-23 8:52 ` [PATCH v2 05/17] KVM-test: Add a new subtest ping Amos Kong
2010-08-23 8:52 ` [PATCH v2 06/17] KVM-test: Add a subtest jumbo Amos Kong
2010-08-23 8:52 ` [PATCH v2 07/17] KVM-test: Add basic file transfer test Amos Kong
2010-08-23 8:52 ` [PATCH v2 08/17] KVM-test: Add a subtest of load/unload nic driver Amos Kong
2010-08-23 8:53 ` [PATCH v2 09/17] KVM-test: Add a subtest of nic promisc Amos Kong
2010-08-23 8:53 ` [PATCH v2 10/17] KVM-test: Add a subtest of multicast Amos Kong
2010-08-23 8:53 ` [PATCH v2 11/17] KVM-test: Add a subtest of pxe Amos Kong
2010-08-23 8:53 ` [PATCH v2 12/17] KVM-test: Add a subtest of changing mac address Amos Kong
2010-08-23 8:53 ` [PATCH v2 13/17] KVM-test: Add a subtest of netperf Amos Kong
2010-08-23 8:53 ` [PATCH v2 14/17] Add support of check if remote port free Amos Kong
2010-08-23 8:53 ` [PATCH v2 15/17] KVM-test: Improve vlan subtest Amos Kong
2010-08-23 8:54 ` [PATCH v2 16/17] Vlan: Replace extra_params '-snapshot' with image_snapshot Amos Kong
2010-08-23 8:54 ` [PATCH v2 17/17] KVM-test: Add subtest of testing offload by ethtool Amos Kong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100823085155.19173.55699.stgit@190 \
--to=akong@redhat.com \
--cc=autotest@vger.kernel.org \
--cc=kvm@vger.kernel.org \
--cc=lmr@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.