aboutsummaryrefslogtreecommitdiff
path: root/rumba/testbeds/qemu.py
blob: 0a2126f6fa54f7e28ccf595bffcb16bfeca59bf4 (plain)
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