1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
#
# QEMU testbed for Rumba
#
# Vincenzo Maffione <v.maffione@nextworks.it>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA
import multiprocessing
import rumba.model as mod
# Fake testbed, useful for testing
class Testbed(mod.Testbed):
def __init__(self, exp_name, username, proj_name="ARCFIRE", password=""):
mod.Testbed.__init__(self, exp_name, username, password, proj_name)
def create_experiment(self, experiment):
"""
:type experiment mod.Experiment
:param experiment: The experiment running
"""
print("[QEMU testbed] swapping in")
command_str = ""
# Building bridges and taps
vms = {}
for shim in experiment.dif_ordering:
if not isinstance(shim, mod.ShimEthDIF):
# Nothing to do here
continue
command_str += 'sudo brctl addbr %(br)s\n' \
'sudo ip link set %(br)s up\n' \
'\n' % {'br': shim}
for node in shim.members: # type:mod.Node
# TODO ask: full_name or simply name?
name = node.full_name
vm = vms.setdefault(name, {'vm': node, 'ports': []})
port_id = len(vm['ports']) + 1
tap_id = '%s.%02x' % (name, port_id)
command_str += 'sudo ip tuntap add mode tap name %(tap)s\n' \
'sudo ip link set %(tap)s up\n' \
'sudo brctl addif %(br)s %(tap)s\n\n' \
% {'tap': tap_id, 'br': shim}
if shim.link_speed > 0:
speed = '%dbit/s' % shim.link_speed
# TODO see what to do here
# # Rate limit the traffic transmitted on the TAP interface
# netems[shim][vm]['args'] += ' rate %s' % (speed,)
#
# # Rate limit the traffic transmitted on the TAP interface
# outs += 'sudo tc qdisc add dev %(tap)s handle 1: root ' \
# 'htb default 11\n' \
# 'sudo tc class add dev %(tap)s parent 1: classid ' \
# '1:1 htb rate 10gbit\n' \
# 'sudo tc class add dev %(tap)s parent 1:1 classid ' \
# '1:11 htb rate %(speed)s\n' \
# % {'tap': tap, 'speed': speed}
vm['ports'].append({'tap_id': tap_id, 'shim': shim, 'port_id': port_id})
# TODO ask about IP address. Was there in demo.
# Building vms
boot_batch_size = max(1, multiprocessing.cpu_count() // 2)
booting_budget = boot_batch_size
boot_backoff = 12
base_port = 2222
vm_memory = 164
vm_frontend = 'virtio-net-pci'
vm_img_path = '########## TBD ############' # TODO
vhost = False # TODO
vmid = 1
for node in experiment.nodes:
name = node.full_name
vm = vms.setdefault(name, {'vm': node, 'ports': []})
fwdp = base_port + vmid
fwdc = fwdp + 10000
mac = '00:0a:0a:0a:%02x:%02x' % (vmid, 99)
vm['ssh'] = fwdp
vars_dict = {'fwdp': fwdp, 'id': vmid, 'mac': mac,
'vmimgpath': vm_img_path, 'fwdc': fwdc,
'memory': vm_memory, 'frontend': vm_frontend,
'vmname': name}
host_fwd_str = 'hostfwd=tcp::%(fwdp)s-:22' % vars_dict
# TODO: will we do this?
# if name in hostfwds:
# for fwdr in hostfwds[vmname]:
# hport, gport = fwdr.split(':')
# hostfwdstr += ',hostfwd=tcp::%s-:%s' % (hport, gport)
#
vars_dict['hostfwdstr'] = host_fwd_str
command_str += 'qemu-system-x86_64 '
# TODO non default images?
command_str += '-kernel buildroot/bzImage ' \
'-append "console=ttyS0" ' \
'-initrd %(vmimgpath)s ' % vars_dict
command_str += '-nographic ' \
'-display none ' \
'--enable-kvm ' \
'-smp 1 ' \
'-m %(memory)sM ' \
'-device %(frontend)s,mac=%(mac)s,netdev=mgmt ' \
'-netdev user,id=mgmt,%(hostfwdstr)s ' \
'-vga std ' \
'-pidfile rina-%(id)s.pid ' \
'-serial file:%(vmname)s.log ' \
% vars_dict
del vars_dict
for port in vm['ports']:
tap_id = port['tap_id']
mac = '00:0a:0a:0a:%02x:%02x' % (vmid, port['port_id'])
port['mac'] = mac
command_str += '-device %(frontend)s,mac=%(mac)s,netdev=data%(idx)s ' \
'-netdev tap,ifname=%(tap)s,id=data%(idx)s,script=no,' \
'downscript=no%(vhost)s ' \
% {'mac': mac, 'tap': tap_id, 'idx': port['port_id'],
'frontend': vm_frontend,
'vhost': ',vhost=on' if vhost else ''}
command_str += '&\n'
booting_budget -= 1
if booting_budget <= 0:
command_str += 'sleep %s\n' % boot_backoff
booting_budget = boot_batch_size
vmid += 1
def __del__(self):
# TODO
pass
|