Support dataplane subnet mask & latency histogram
[samplevnf.git] / VNFs / DPPD-PROX / helper-scripts / start_vm.py
1 #!/bin/env python2.7
2
3 ##
4 ## Copyright (c) 2010-2017 Intel Corporation
5 ##
6 ## Licensed under the Apache License, Version 2.0 (the "License");
7 ## you may not use this file except in compliance with the License.
8 ## You may obtain a copy of the License at
9 ##
10 ##     http://www.apache.org/licenses/LICENSE-2.0
11 ##
12 ## Unless required by applicable law or agreed to in writing, software
13 ## distributed under the License is distributed on an "AS IS" BASIS,
14 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ## See the License for the specific language governing permissions and
16 ## limitations under the License.
17 ##
18
19 from os import system
20 from os import fork, _exit
21 from subprocess import check_output
22 import socket
23 from time import sleep
24 import json
25 import sys
26
27 # This script starts qemu with the CPU layout specified by the cores
28 # array below. Each element in the array represents a core. To enable
29 # hyper-threading (i.e. two logical cores per core), each element in
30 # the array should be an array of length two. The values stored inside
31 # the array define to which host cores the guest cores should be
32 # affinitized. All arguments of this script are passed to qemu
33 # directly. Porting an existing qemu command line setup to make use of
34 # this script requires removing the -smp parameters and -qmp
35 # parameters if those were used. These are built by the script based
36 # on the cores array.
37
38 # After successfully starting qemu, this script will connect through
39 # QMP and affinitize all cores within the VM to match cores on the
40 # host.
41
42 execfile("./vm-cores.py")
43
44 def build_mask(cores):
45     ret = 0;
46     for core in cores:
47         for thread in core:
48             ret += 1 << thread;
49     return ret;
50
51 n_cores = len(cores);
52 n_threads = len(cores[0]);
53
54 mask = str(hex((build_mask(cores))))
55
56 smp_str = str(n_cores*n_threads)
57 smp_str += ",cores=" + str(n_cores)
58 smp_str += ",sockets=1"
59 smp_str += ",threads=" + str(n_threads)
60
61 try:
62     qmp_sock = check_output(["mktemp", "--tmpdir", "qmp-sock-XXXX"]).strip()
63 except:
64     qmp_sock = "/tmp/qmp-sock"
65
66 qemu_cmdline = ""
67 qemu_cmdline += "taskset " + mask + " qemu-system-x86_64 -smp " + smp_str
68 qemu_cmdline += " -qmp unix:" + qmp_sock + ",server,nowait"
69 qemu_cmdline += " -daemonize"
70
71 for a in sys.argv[1:]:
72     qemu_cmdline += " " + a
73
74 try:
75     pid = fork()
76 except OSError, e:
77     sys.exit("Failed to fork: " + e.strerror)
78
79 if (pid != 0):
80     # In the parent process
81     ret = system(qemu_cmdline)
82     if (ret != 0):
83         sys.exit("Failed to run QEMU: exit status " + str(ret) + ". Command line was:\n" + qemu_cmdline)
84     # Parent process done
85     sys.exit(0)
86
87 # In the child process: use _exit to terminate
88 retry = 0
89 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
90 while (retry < 10):
91     sleep(1);
92     try:
93         s.connect(qmp_sock)
94         print "Connected to QMP"
95         break;
96     except:
97         pass
98     retry = retry + 1
99     print "Failed to connect to QMP, attempt " + str(retry)
100 if (retry >= 10):
101     print "Failed to connect to QMP"
102     _exit(1)
103
104 # skip info about protocol
105 dat = s.recv(100000)
106 # need to run qmp_capabilities before next command works
107 s.send("{\"execute\" : \"qmp_capabilities\" }")
108 dat = s.recv(100000)
109 # Get the PID for each guest core
110 s.send("{\"execute\" : \"query-cpus\"}")
111 dat = s.recv(100000)
112 a = json.loads(dat)["return"];
113
114 if (len(a) != n_cores*n_threads):
115     print "Configuration mismatch: " + str(len(a)) + " vCPU reported by QMP, instead of expected " + str(n_cores*n_threads)
116     _exit(1)
117 print "QMP reported " + str(len(a)) + " vCPU, as expected"
118
119 if (n_threads == 1):
120     idx = 0;
121     for core in a:
122         cm  = str(hex(1 << cores[idx][0]))
123         pid = str(core["thread_id"])
124         system("taskset -p " + cm + " " + pid + " > /dev/null")
125         idx = idx + 1
126 elif (n_threads == 2):
127     idx = 0;
128     prev = 0;
129     for core in a:
130         cm  = str(hex(1 << cores[idx][prev]))
131         pid = str(core["thread_id"])
132         system("taskset -p " + cm + " " + pid + " > /dev/null")
133         prev = prev + 1;
134         if (prev == 2):
135             idx = idx + 1;
136             prev = 0
137 else:
138     print "Not implemented yet: more than 2 threads per core"
139     _exit(1)
140
141 print "Core affinitization completed"
142 _exit(0)
143