├── .gitignore ├── AUTHORS ├── LICENSE ├── Makefile ├── README.md ├── binding.gyp ├── doc ├── api.md └── cli.md ├── etc ├── bash_completion ├── click │ ├── pingresponder.click │ ├── rx.click │ └── wire.click ├── env.sh └── xen │ ├── example.cfg │ └── scripts │ └── vif-vale ├── include ├── clickos.h └── xcl │ ├── xcl.h │ └── xcl_util.h ├── src ├── clickos.c ├── cosmos.i ├── domain_none.c ├── domain_xcl.c ├── domain_xl.c ├── main.c └── xcl │ ├── xcl_dom.c │ └── xcl_net.c └── tests ├── api.js ├── api.py └── bootperf.py /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | *~ 3 | *.o 4 | *.pyc 5 | build/ 6 | dist/ 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | ClickOS was first launched in April, at NSDI 2014 conference. 2 | 3 | The PRIMARY AUTHORS are (and/or have been): 4 | 5 | * Joao Martins 6 | * Filipe Manco 7 | * Mohammed Ahmed 8 | * Felipe Huici 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, NEC Europe Ltd., NEC Corporation All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. Neither the name of the copyright holder nor the names of its 13 | contributors may be used to endorse or promote products derived from 14 | this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Basic configurations 3 | ################################################################################ 4 | verbose ?= n 5 | debug ?= n 6 | 7 | # The domain helper: one of [none, xcl, xl] 8 | DOMLIB ?= none 9 | 10 | DOM_NONE := n 11 | DOM_XCL := n 12 | DOM_XL := n 13 | ifeq ($(DOMLIB),none) 14 | DOM_NONE := y 15 | else ifeq ($(DOMLIB),xcl) 16 | DOM_XCL := y 17 | else ifeq ($(DOMLIB),xl) 18 | DOM_XL := y 19 | else 20 | $(error Invalid domain helper $(DOMLIB)) 21 | endif 22 | 23 | ifneq (,$(filter $(DOMLIB),xcl xl)) 24 | ifndef XEN_ROOT 25 | $(error "Define XEN_ROOT to build with DOMLIB=$(DOMLIB)") 26 | endif 27 | endif 28 | 29 | XEN_HOST_VERSION := $(shell xl info | grep -E "(xen_major|xen_minor|xen_extra)" | \ 30 | cut -d: -f2 | tr -d ' ' | tr -d '.' | tr '\n' '.' | \ 31 | awk -F '.' '{ split($$3, a, "-"); printf "%01x%02x%02x", $$1, $$2, a[1]; }') 32 | 33 | XEN_ROOT_VERSION := $(shell cd $(XEN_ROOT); make --no-print-directory -C xen xenversion | \ 34 | awk -F '.' '{ split($$3, a, "-"); printf "%01x%02x%02x", $$1, $$2, a[1]; }') 35 | 36 | define XEN_VERSION_ERR 37 | 38 | Version mismatch between your host and the sources you are using: 39 | 40 | host-xenversion=$(XEN_HOST_VERSION) 41 | build-xenversion=$(XEN_ROOT_VERSION) 42 | 43 | endef 44 | 45 | ifneq (,$(filter $(DOMLIB),xcl xl)) 46 | ifneq ($(XEN_HOST_VERSION), $(XEN_ROOT_VERSION)) 47 | $(error $(XEN_VERSION_ERR)) 48 | endif 49 | endif 50 | 51 | XEN_VERSION := $(XEN_HOST_VERSION) 52 | 53 | PYTHON_VERSION ?= 2.7 54 | 55 | V8_SWIG ?= swig 56 | V8_VERSION ?= 3.15.5.9 57 | V8_INCLUDE ?= /root/apps/node-v0.10.18/deps/v8/include 58 | 59 | 60 | .PHONY: 61 | default: all 62 | 63 | 64 | ################################################################################ 65 | # Base commands and functions 66 | ################################################################################ 67 | CP = cp -a 68 | MV = mv -f 69 | LN = ln -sf 70 | RM = rm -f 71 | MKDIR = mkdir -p 72 | RMDIR = rm -rf 73 | TOUCH = touch 74 | 75 | ASCOMPILE = $(CC) $(ASDEFINES) $(CDEFINES) $(CINCLUDES) $(ASFLAGS) 76 | COMPILE = $(CC) $(CDEFINES) $(CINCLUDES) $(CPPFLAGS) $(CFLAGS) 77 | CCLD = $(CC) 78 | CCLINK = $(CCLD) $(CFLAGS) $(1) $(LDFLAGS) -o $@ 79 | CXXCOMPILE = $(CXX) $(CDEFINES) $(CINCLUDES) $(CPPFLAGS) $(CXXFLAGS) 80 | CXXLD = $(CXX) 81 | CXXLINK = $(CXXLD) $(CXXFLAGS) $(1) $(LDFLAGS) -o $@ 82 | 83 | SWIG = swig 84 | SWIGCOMPILE = $(SWIG) $(SWIGFLAGS) $(SWIGINCLUDES) 85 | XXD ?= xxd 86 | 87 | ifneq ($(verbose),y) 88 | ascompile = @/bin/echo ' ' $(2) $< && $(ASCOMPILE) $(1) 89 | ccompile = @/bin/echo ' ' $(2) $< && $(COMPILE) $(1) 90 | cclink = @/bin/echo ' ' $(2) $@ && $(CCLINK) 91 | cxxcompile = @/bin/echo ' ' $(2) $< && $(CXXCOMPILE) $(1) 92 | cxxlink = @/bin/echo ' ' $(2) $< && $(CXXLINK) 93 | swig = @/bin/echo ' ' $(2) $< && $(SWIGCOMPILE) $(1) 94 | archive = @/bin/echo ' ' $(2) $@ && $(AR) cr $(1) 95 | x_verbose_cmd = $(if $(2),/bin/echo ' ' $(2) $(3) &&,) $(1) $(3) 96 | verbose_cmd = @$(x_verbose_cmd) 97 | else 98 | ascompile = $(ASCOMPILE) $(1) 99 | ccompile = $(COMPILE) $(1) 100 | cclink = $(CCLINK) 101 | cxxcompile = $(CXXCOMPILE) $(1) 102 | cxxlink = $(CXXLINK) 103 | swig = $(SWIGCOMPILE) $(1) 104 | archive = $(AR) crv $(1) 105 | x_verbose_cmd = $(1) $(3) 106 | verbose_cmd = $(1) $(3) 107 | endif 108 | 109 | 110 | ################################################################################ 111 | # Build directory structure 112 | ################################################################################ 113 | ROOT_DIR ?= $(realpath .) 114 | 115 | SOURCE_DIR ?= $(ROOT_DIR)/src 116 | INCLUDE_DIR ?= $(ROOT_DIR)/include 117 | BUILD_DIR ?= $(ROOT_DIR)/build 118 | 119 | DIST_DIR ?= $(ROOT_DIR)/dist 120 | BIN_DIR ?= $(DIST_DIR)/bin 121 | LIB_DIR ?= $(DIST_DIR)/lib 122 | 123 | BUILD_DIRS += $(BUILD_DIR) 124 | BUILD_DIRS += $(DIST_DIR) 125 | BUILD_DIRS += $(BIN_DIR) 126 | BUILD_DIRS += $(LIB_DIR) 127 | 128 | 129 | ################################################################################ 130 | # Configure building 131 | ################################################################################ 132 | CDEFINES += -DXEN_VERSION=$(XEN_VERSION) 133 | 134 | CINCLUDES += -I$(INCLUDE_DIR) 135 | 136 | CFLAGS += -std=gnu99 137 | CFLAGS += -fno-strict-aliasing 138 | CFLAGS += -fPIC 139 | CFLAGS += -Wall -Wstrict-prototypes 140 | CFLAGS += -Wno-format-zero-length 141 | 142 | LDFLAGS += -lxenctrl 143 | LDFLAGS += -lxenguest 144 | LDFLAGS += -lxenstore 145 | LDFLAGS += -luuid -ldl -lutil 146 | 147 | ifeq ($(debug),y) 148 | CFLAGS += -O0 -g 149 | endif 150 | 151 | 152 | ################################################################################ 153 | # libxcl 154 | ################################################################################ 155 | LIBXCL_VERSION := 0.1.0 156 | LIBXCL_VERSION_MAJOR := 0 157 | 158 | LIBXCL_BUILD_DIR = $(BUILD_DIR)/libxcl 159 | LIBXCL_SOURCE_DIR = $(SOURCE_DIR)/xcl 160 | LIBXCL_OBJS0 = \ 161 | xcl_dom.o \ 162 | xcl_net.o 163 | LIBXCL_OBJS = $(addprefix $(LIBXCL_BUILD_DIR)/,$(LIBXCL_OBJS0)) 164 | 165 | BUILD_DIRS += $(LIBXCL_BUILD_DIR) 166 | 167 | 168 | $(LIBXCL_BUILD_DIR)/%.o: CINCLUDES += -I$(INCLUDE_DIR)/xcl 169 | $(LIBXCL_BUILD_DIR)/%.o: CINCLUDES += -I$(XEN_ROOT)/tools/libxl 170 | $(LIBXCL_BUILD_DIR)/%.o: CINCLUDES += -I$(XEN_ROOT)/tools/libxc 171 | $(LIBXCL_BUILD_DIR)/%.o: CINCLUDES += -I$(XEN_ROOT)/tools/include 172 | $(LIBXCL_BUILD_DIR)/%.o: $(LIBXCL_SOURCE_DIR)/%.c | bootstrap 173 | $(call ccompile,-c $< -o $@,'CC ') 174 | 175 | $(LIB_DIR)/libxcl.so: LDFLAGS += -shared 176 | $(LIB_DIR)/libxcl.so: $(LIBXCL_OBJS) | bootstrap 177 | $(call verbose_cmd,$(LN) libxcl.so,'LN ',$@.$(LIBXCL_VERSION)) 178 | $(call verbose_cmd,$(LN) libxcl.so,'LN ',$@.$(LIBXCL_VERSION_MAJOR)) 179 | $(call cclink,$^,'LD ') 180 | 181 | 182 | .PHONY: libxcl 183 | libxcl: $(LIB_DIR)/libxcl.so 184 | 185 | .PHONY: clean-libxcl 186 | clean: clean-libxcl 187 | clean-libxcl: 188 | $(call verbose_cmd,$(RM) $(LIBXCL_BUILD_DIR)/*.o,'CLN $(LIBXCL_BUILD_DIR)/*.o') 189 | 190 | .PHONY: distclean-libxcl 191 | distclean: distclean-libxcl 192 | distclean-libxcl: clean-libxcl 193 | $(call verbose_cmd,$(RMDIR),'CLN',$(LIBXCL_BUILD_DIR)) 194 | $(call verbose_cmd,$(RM) $(LIB_DIR)/libxcl.so*,'CLN $(LIB_DIR)/libxcl.so') 195 | 196 | 197 | ################################################################################ 198 | # libxl 199 | ################################################################################ 200 | LIBXL_CINCLUDES = -I$(XEN_ROOT)/tools/libxl 201 | LIBXL_LDFLAGS = -lxenlight -lxlutil -lyajl 202 | 203 | 204 | ################################################################################ 205 | # libcosmos 206 | ################################################################################ 207 | LIBCOSMOS_VERSION := 0.1.0 208 | LIBCOSMOS_VERSION_MAJOR := 0 209 | 210 | LIBCOSMOS_BUILD_DIR = $(BUILD_DIR)/libcosmos 211 | LIBCOSMOS_SOURCE_DIR = $(SOURCE_DIR) 212 | LIBCOSMOS_OBJS0-y = \ 213 | clickos.o 214 | LIBCOSMOS_OBJS0-$(DOM_NONE) += domain_none.o 215 | LIBCOSMOS_OBJS0-$(DOM_XCL) += domain_xcl.o 216 | LIBCOSMOS_OBJS0-$(DOM_XL) += domain_xl.o 217 | LIBCOSMOS_OBJS = $(addprefix $(LIBCOSMOS_BUILD_DIR)/,$(LIBCOSMOS_OBJS0-y)) 218 | 219 | LIBCOSMOS_CFLAGS-y := 220 | LIBCOSMOS_CFLAGS-$(DOM_XCL) += -DHAVE_XCL 221 | LIBCOSMOS_CFLAGS-$(DOM_XL) += -DHAVE_XL 222 | LIBCOSMOS_CFLAGS = $(LIBCOSMOS_CFLAGS-y) 223 | 224 | LIBCOSMOS_CINCLUDES-y := 225 | LIBCOSMOS_CINCLUDES-$(DOM_XCL) += $(LIBXCL_CINCLUDES) 226 | LIBCOSMOS_CINCLUDES-$(DOM_XL) += $(LIBXL_CINCLUDES) 227 | LIBCOSMOS_CINCLUDES = $(LIBCOSMOS_CINCLUDES-y) 228 | 229 | LIBCOSMOS_LDFLAGS-y := 230 | LIBCOSMOS_LDFLAGS-$(DOM_XCL) += $(LIBXCL_LDFLAGS) 231 | LIBCOSMOS_LDFLAGS-$(DOM_XL) += $(LIBXL_LDFLAGS) 232 | LIBCOSMOS_LDFLAGS = $(LIBCOSMOS_LDFLAGS-y) 233 | 234 | BUILD_DIRS += $(LIBCOSMOS_BUILD_DIR) 235 | 236 | 237 | $(LIBCOSMOS_BUILD_DIR)/%.o: CFLAGS += $(LIBCOSMOS_CFLAGS) 238 | $(LIBCOSMOS_BUILD_DIR)/%.o: CINCLUDES += $(LIBCOSMOS_CINCLUDES) 239 | $(LIBCOSMOS_BUILD_DIR)/%.o: $(LIBCOSMOS_SOURCE_DIR)/%.c | bootstrap 240 | $(call ccompile,-c $< -o $@,'CC ') 241 | 242 | $(LIB_DIR)/libcosmos.so: LDFLAGS += -shared 243 | $(LIB_DIR)/libcosmos.so: $(LIBCOSMOS_OBJS) | bootstrap 244 | $(call verbose_cmd,$(LN) libcosmos.so,'LN ',$@.$(LIBCOSMOS_VERSION)) 245 | $(call verbose_cmd,$(LN) libcosmos.so,'LN ',$@.$(LIBCOSMOS_VERSION_MAJOR)) 246 | $(call cclink,$^,'LD ') 247 | 248 | 249 | .PHONY: libcosmos 250 | libcosmos: $(LIB_DIR)/libcosmos.so 251 | 252 | .PHONY: clean-libcosmos 253 | clean: clean-libcosmos 254 | clean-libcosmos: 255 | $(call verbose_cmd,$(RM) $(LIBCOSMOS_BUILD_DIR)/*.o,'CLN $(LIBCOSMOS_BUILD_DIR)/*.o') 256 | 257 | .PHONY: distclean-libcosmos 258 | distclean: distclean-libcosmos 259 | distclean-libcosmos: clean-libcosmos 260 | $(call verbose_cmd,$(RMDIR),'CLN',$(LIBCOSMOS_BUILD_DIR)) 261 | $(call verbose_cmd,$(RM) $(LIB_DIR)/libcosmos.so*,'CLN $(LIB_DIR)/libcosmos.so') 262 | 263 | 264 | ################################################################################ 265 | # cosmos 266 | ################################################################################ 267 | COSMOS_APP = $(BIN_DIR)/cosmos 268 | COSMOS_BUILD_DIR = $(BUILD_DIR)/cosmos 269 | COSMOS_OBJS0 = \ 270 | main.o 271 | COSMOS_OBJS-y = $(addprefix $(COSMOS_BUILD_DIR)/,$(COSMOS_OBJS0)) 272 | COSMOS_OBJS-y += $(LIBCOSMOS_OBJS) 273 | COSMOS_OBJS-$(DOM_XCL) += $(LIBXCL_OBJS) 274 | COSMOS_OBJS = $(COSMOS_OBJS-y) 275 | 276 | BUILD_DIRS += $(COSMOS_BUILD_DIR) 277 | 278 | 279 | $(COSMOS_BUILD_DIR)/%.o: CFLAGS += $(LIBCOSMOS_CFLAGS) 280 | $(COSMOS_BUILD_DIR)/%.o: CINCLUDES += $(LIBCOSMOS_CINCLUDES) 281 | $(COSMOS_BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c | bootstrap 282 | $(call ccompile,-c $< -o $@,'CC ') 283 | 284 | $(COSMOS_APP): LDFLAGS+=$(LIBCOSMOS_LDFLAGS) 285 | $(COSMOS_APP): $(COSMOS_OBJS) | bootstrap 286 | $(call cclink,$^,'LD ') 287 | 288 | 289 | .PHONY: cosmos 290 | all: cosmos 291 | cosmos: $(BIN_DIR)/cosmos 292 | 293 | .PHONY: clean-cosmos 294 | clean: clean-cosmos 295 | clean-cosmos: 296 | $(call verbose_cmd,$(RM) $(COSMOS_BUILD_DIR)/*.o,'CLN $(COSMOS_BUILD_DIR)/*.o') 297 | 298 | .PHONY: distclean-cosmos 299 | distclean: distclean-cosmos 300 | distclean-cosmos: clean-cosmos 301 | $(call verbose_cmd,$(RM),'CLN',$(COSMOS_APP)) 302 | 303 | 304 | ################################################################################ 305 | # bindings 306 | ################################################################################ 307 | BINDING_CFLAGS = -fPIC 308 | BINDING_LDFLAGS = -L$(LIB_DIR) -lcosmos 309 | 310 | SWIGFLAGS = -DBINDING_SWIG 311 | SWIGINCLUDES = -I$(INCLUDE_DIR) 312 | 313 | python-binding: BINDING_CINCLUDES += -I/usr/include/python$(PYTHON_VERSION) 314 | 315 | js-binding: SWIG = $(V8_SWIG) 316 | js-binding: SWIGFLAGS += -c++ -v8 317 | js-binding: BINDING_CFLAGS += $(V8_INCLUDE) 318 | 319 | # So that make doesn't delete intermediary files (in which the target is included) 320 | .SECONDARY: 321 | 322 | %-binding: LDFLAGS += -shared 323 | %-binding: $(LIB_DIR)/%-cosmos.so 324 | @# 325 | 326 | $(LIB_DIR)/%-cosmos.so: $(BUILD_DIR)/%/cosmos_wrap.o $(LIBCOSMOS_OBJS) 327 | $(call cclink, $^,'LD ') 328 | 329 | $(BUILD_DIR)/%/cosmos_wrap.o: CFLAGS = $(BINDING_CFLAGS) 330 | $(BUILD_DIR)/%/cosmos_wrap.o: CINCLUDES = $(BINDING_CINCLUDES) 331 | 332 | ifneq (,$(filter $(MAKECMDGOALS),js-binding)) 333 | $(BUILD_DIR)/%/cosmos_wrap.o: $(BUILD_DIR)/%/cosmos_wrap.cxx 334 | $(call cxxcompile, -c $< -o $@,'CXX') 335 | else 336 | $(BUILD_DIR)/%/cosmos_wrap.o: $(BUILD_DIR)/%/cosmos_wrap.c 337 | $(call ccompile, -c $< -o $@,'CC ') 338 | endif 339 | 340 | ifneq (,$(filter $(MAKECMDGOALS),js-binding)) 341 | $(BUILD_DIR)/%/cosmos_wrap.cxx: $(BUILD_DIR)/%/cosmos.i 342 | else 343 | $(BUILD_DIR)/%/cosmos_wrap.c: $(BUILD_DIR)/%/cosmos.i 344 | endif 345 | $(call swig, -includeall -$* $<,'SWG') 346 | 347 | $(BUILD_DIR)/%/cosmos.i: $(SOURCE_DIR)/cosmos.i | bootstrap 348 | $(call verbose_cmd, $(MKDIR), MKD, $(dir $@)) 349 | $(call verbose_cmd, $(CP), 'CP ',$< $@) 350 | 351 | 352 | ################################################################################ 353 | # Targets 354 | ################################################################################ 355 | 356 | .PHONY: all 357 | all: 358 | @# 359 | 360 | .PHONY: bootstrap 361 | bootstrap: $(BUILD_DIRS) 362 | 363 | $(BUILD_DIRS): 364 | $(call verbose_cmd,$(MKDIR),'MKD',$@) 365 | 366 | .PHONY:clean 367 | clean: 368 | @# 369 | 370 | .PHONY: distclean 371 | distclean: clean 372 | $(call verbose_cmd,$(RMDIR),'CLN',$(BUILD_DIR)) 373 | $(call verbose_cmd,$(RMDIR),'CLN',$(DIST_DIR)) 374 | 375 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Motivation 2 | ========== 3 | 4 | Initially ```cosmos``` was created to boot specifically ```ClickOS``` domains, in essence 5 | just to instantiate a middlebox. Given we were using MiniOS we also started exploring short 6 | boot up times. We started exploring these tools and gradually building our own while we 7 | studied the boot process. The end result is this toolstack, focused on MiniOS-based domains. 8 | 9 | Building 10 | ======== 11 | 12 | You will need Xen sources only when building cosmos with domain libraries. Mostly the headers 13 | are needed which means you don't need to compile xen or its tools. 14 | Make sure the xen version installed in your host and sources you got match, 15 | otherwise you won't be able to build cosmos with domain libraries. 16 | 17 | $ cd /path/to/xen-sources 18 | $ ./configure 19 | $ cd tools 20 | $ make -C include 21 | 22 | You will need to export your Xen sources location into ```XEN_ROOT```. 23 | 24 | $ export XEN_ROOT=/path/to/xen-sources 25 | 26 | To build cosmos just type ```make```. 27 | 28 | $ cd /path/to/cosmos 29 | $ make 30 | 31 | By default, it only builds a minimal core to start up middleboxes. If you 32 | want to enable domain management you will to explicitly enable a domain library: 33 | 34 | To use an ```libxl``` based domains creation: 35 | 36 | $ make DOMLIB=xl 37 | 38 | To use our ```libxcl``` (Xen control light) based domains creation: 39 | 40 | $ make DOMLIB=xcl 41 | 42 | The latter enables you faster boot times, although it is still experimental. 43 | 44 | Our build process can generate any binding. Examples are shown below (also the only ones tested): 45 | 46 | # For python (default) 47 | $ make python-binding 48 | 49 | # For ocaml 50 | $ make ocaml-binding 51 | 52 | # For nodejs (use this swig: github.com/olivier----/swig-v8 53 | $ make javascript-binding V8=y 54 | 55 | Note that not all bindings were tested. For example, ruby binding is currently not compiling. 56 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "cosmos", 5 | "sources": [ 6 | "build/javascript/cosmos_wrap.cxx", 7 | ], 8 | "include_dirs": [ 9 | "-I/root/cosmos/include" 10 | ], 11 | "libraries": [ 12 | "-lcosmos -L/root/cosmos/build/lib" 13 | ] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /doc/api.md: -------------------------------------------------------------------------------- 1 | ClickOS Manager API (COSMOS) 2 | ============================ 3 | 4 | The methods are the same whatever language you generate your binding with. 5 | 6 | C 7 | = 8 | 9 | Read the source. 10 | 11 | Python 12 | ====== 13 | 14 | To quickly test, please compile and go to `/build/python`, 15 | and run the following script: 16 | 17 | ```python 18 | import cosmos 19 | 20 | xen_config = "./etc/xen/test.cfg"; 21 | click_script = open("./etc/click/fromnetfront.click").read(); 22 | 23 | flags = 1; 24 | # Initializes a context for cosmos with verbose enabled. 25 | # consists of a bitmask which 26 | # 0x01 = enable verbose 27 | # 0x10 = enable autoattach in clickos_start 28 | cosmos.ctx(flags) 29 | 30 | # Create the domain 31 | domid = cosmos.create(xen_config); 32 | 33 | # Create the domain with and 34 | # plus default options 35 | domid = cosmos.create_default("clickos", 36 | "/clickos/build/bin/click-os-x86_64") 37 | 38 | # Network attach for vm with , , , 39 | cosmos.network_attach(domid, "00:11:22:33:44:55", 0, "") 40 | 41 | # Start the domain 42 | cosmos.start(domid, "script", click_script); 43 | 44 | # Destroy the domain 45 | if cosmos.destroy(domid) < 0: 46 | print "Domain invalid" 47 | 48 | # Frees the context 49 | cosmos.free() 50 | ``` 51 | 52 | Javascript 53 | ========== 54 | 55 | To quickly test, please compile everything and also do `$ make javascript-binding V8=1`, 56 | then just run the following script in the cosmos root folder: 57 | 58 | ```javascript 59 | var cosmos = require('../build/Release/cosmos') 60 | , fs = require('fs'); 61 | 62 | flags = 0; 63 | 64 | cosmos.ctx(flags); 65 | 66 | /* Create a VM */ 67 | domid = cosmos.create_default("test", 68 | "/clickos/build/click_os_x86_64"); 69 | 70 | /* Attaches a virtual interface */ 71 | cosmos.network_attach(domid, "11:22:33:44:55:66", 0, ""); 72 | 73 | fs.readFile("./etc/click/elements/idle.click", function(err, click_script){ 74 | 75 | /* Instantiates a middlebox */ 76 | cosmos.start(domid, "script", click_script+""); 77 | }); 78 | 79 | function destroy() { 80 | cosmos.destroy(domid); 81 | cosmos.free(); 82 | } 83 | 84 | setTimeout(destroy, 2000); 85 | ``` 86 | -------------------------------------------------------------------------------- /doc/cli.md: -------------------------------------------------------------------------------- 1 | ClickOS Manager tool (`cosmos`) 2 | ============================== 3 | 4 | It adds the ClickOS specific xenstore interactions plus the VALE port 5 | interface. Main differences are in user interface. While `xl` or `xm` 6 | only accept domains names, our cosmos tool can also use domain IDs. This 7 | is mostly usefull when crashes occur in the backend and a (null) appears 8 | in the domain listing (`xl list`. 9 | 10 | Find a trace of the terminal when using `cosmos`. 11 | 12 | # cosmos create etc/xen/test.cfg 13 | Parsing config file etc/xen/test.cfg 14 | Created domain with ID 148 in 0.021987 seconds 15 | VALE ports: 0 16 | 17 | # xl list 18 | Name ID Mem VCPUs State Time(s) 19 | Domain-0 0 10240 3 r----- 727.6 20 | test 148 5 1 -b---- 0.0 21 | 22 | # cosmos vale-attach test 00:11:22:33:44:55 Domain-0 23 | Network attach for id 148 mac 00:11:22:33:44:55 backend 0 24 | 25 | # cosmos vale-attach 148 00:11:22:33:44:55 0 26 | Network attach for id 148 mac 00:11:22:33:44:55 backend 0 27 | 28 | # cosmos start test etc/click/fromnetfront.click 29 | Dom ID 148 30 | Reading click script: etc/click/fromnetfront.click 31 | Read 94/94 bytes Click script: 32 | in :: FromNetFront(00:1a:31:a4:60:ff, BURST 256); 33 | sink :: Discard(BURST 256); 34 | in -> sink; 35 | 36 | Started domain with ID 148 in 0.001874 seconds 37 | 38 | # cosmos -a start test etc/click/fromnetfront.click 39 | Auto network-attach enabled 40 | Dom ID 154 41 | Reading click script: etc/click/fromnetfront.click 42 | Read 94/94 bytes Click script: 43 | in :: FromNetFront(00:1a:31:a4:60:ff, BURST 256); 44 | sink :: Discard(BURST 256); 45 | in -> sink; 46 | 47 | Started domain with ID 154 in 0.006211 seconds -------------------------------------------------------------------------------- /etc/bash_completion: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | commands="create load destroy suspend resume read write start stop network-attach" 4 | 5 | _complete_domains() { 6 | local cur prev domains 7 | cur=${COMP_WORDS[COMP_CWORD]} 8 | prev=${COMP_WORDS[COMP_CWORD-1]} 9 | 10 | COMPREPLY=() 11 | case "${prev}" in 12 | cosmos) 13 | COMPREPLY=( $(compgen -W "$commands" -- "$cur") ) 14 | ;; 15 | 16 | suspend|destroy|read|write|start|stop|network-attach) 17 | domains=$(xl list | awk -F ' ' '{print $1}' | tail -n +3 | xargs) 18 | COMPREPLY=( $(compgen -W "$domains" -- "$cur") ) 19 | ;; 20 | esac 21 | 22 | return 0 23 | } 24 | 25 | complete -o default -F _complete_domains cosmos 26 | -------------------------------------------------------------------------------- /etc/click/pingresponder.click: -------------------------------------------------------------------------------- 1 | c :: Classifier(12/0806 20/0001, 12/0806 20/0002, 12/0800,-); 2 | arpq :: ARPQuerier(10.0.20.2, 00:15:17:15:5d:74); 3 | arpr :: ARPResponder(10.0.20.2 00:15:17:15:5d:74); 4 | 5 | in :: FromDevice; 6 | out :: ToDevice; 7 | 8 | inc :: Counter(); 9 | outc :: Counter(); 10 | 11 | in -> inc -> c; 12 | 13 | c[0] -> arpr; 14 | arpr -> out; 15 | arpq -> out; 16 | 17 | c[1] -> [1]arpq; 18 | Idle -> [0]arpq; 19 | 20 | c[3] -> Print("What?") -> Discard; 21 | c[2] -> CheckIPHeader(14) -> Print("ICMP") -> ICMPPingResponder() -> EtherMirror() -> outc -> out; 22 | -------------------------------------------------------------------------------- /etc/click/rx.click: -------------------------------------------------------------------------------- 1 | in :: FromDevice(); 2 | //sink :: ToDevice(); 3 | sink :: Discard(BURST 1024); 4 | in -> sink; 5 | -------------------------------------------------------------------------------- /etc/click/wire.click: -------------------------------------------------------------------------------- 1 | in :: FromDevice(); 2 | sink :: ToDevice(); 3 | in -> sink; 4 | -------------------------------------------------------------------------------- /etc/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CLICKOS_TOOLS=`readlink -f .` 4 | CLICKOS_IMAGE=click-os-x86_64 5 | 6 | export PATH=$PATH:$CLICKOS_TOOLS/bin 7 | export PYTHONPATH=$PYTHONPATH:$CLICKOS_TOOLS/build/python 8 | 9 | cp /root/workspace/clickos-stable/trunk/click/clickos/build/bin/$CLICKOS_IMAGE /tmp/$CLICKOS_IMAGE-vif 10 | cp /root/workspace/clickos/trunk/click/clickos/build/bin/$CLICKOS_IMAGE /tmp/$CLICKOS_IMAGE-vale 11 | -------------------------------------------------------------------------------- /etc/xen/example.cfg: -------------------------------------------------------------------------------- 1 | 2 | kernel = 'clickos-x86_64' 3 | vcpus = '1' 4 | cpus = '2' 5 | memory = 12 6 | name = 'example' 7 | on_start = 'pause' 8 | on_crash = 'destroy' 9 | 10 | extra = '-d standard' 11 | 12 | # unmodified backend 13 | vif = ['mac=00:15:17:15:5d:74,bridge=xenbr0'] 14 | 15 | # patched backend 16 | #vif = ['mac=00:15:17:15:5d:74,bridge=vale0,script=/etc/xen/scripts/vif-vale'] 17 | 18 | click = 'pingresponder.click' 19 | -------------------------------------------------------------------------------- /etc/xen/scripts/vif-vale: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dir=$(dirname "$0") 4 | . "$dir/vif-common.sh" 5 | 6 | bridge=${bridge:-} 7 | bridge=$(xenstore_read_default "$XENBUS_PATH/bridge" "$bridge") 8 | 9 | if [ -z "$bridge" ] 10 | then 11 | if [ -z "$bridge" ] 12 | then 13 | fatal "Could not find bridge for $dev" 14 | fi 15 | fi 16 | 17 | case "$command" in 18 | online) 19 | ip link set $dev up 20 | ip link set $vif mtu 1500 21 | vale-ctl -a $bridge:$dev 22 | xenstore-write "$XENBUS_PATH/feature-netmap" 1 23 | xenstore-write "$XENBUS_PATH/hotplug-status" connected 24 | ;; 25 | 26 | offline) 27 | bridge=$(vale-ctl 2>&1 | grep $dev | cut -d' ' -f 5) 28 | vale-ctl -d $bridge 29 | ;; 30 | esac 31 | 32 | log debug "Successful vif-vale $command for $dev, bridge $bridge." 33 | -------------------------------------------------------------------------------- /include/clickos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cosmos 3 | * 4 | * file: clickos.h 5 | * 6 | * NEC Europe Ltd. PROPRIETARY INFORMATION 7 | * 8 | * This software is supplied under the terms of a license agreement 9 | * or nondisclosure agreement with NEC Europe Ltd. and may not be 10 | * copied or disclosed except in accordance with the terms of that 11 | * agreement. The software and its source code contain valuable trade 12 | * secrets and confidential information which have to be maintained in 13 | * confidence. 14 | * Any unauthorized publication, transfer to third parties or duplication 15 | * of the object or source code - either totally or in part – is 16 | * prohibited. 17 | * 18 | * Copyright (c) 2014 NEC Europe Ltd. All Rights Reserved. 19 | * 20 | * Authors: Joao Martins 21 | * Filipe Manco 22 | * 23 | * NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, 24 | * INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY 25 | * AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT 26 | * DEFECTS, WITH RESPECT TO THE PROGRAM AND THE ACCOMPANYING 27 | * DOCUMENTATION. 28 | * 29 | * No Liability For Consequential Damages IN NO EVENT SHALL NEC Europe 30 | * Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE LIABLE FOR ANY 31 | * DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS 32 | * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR 33 | * OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL, 34 | * ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY 35 | * TO USE THIS PROGRAM, EVEN IF NEC Europe Ltd. HAS BEEN ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGES. 37 | * 38 | * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 39 | */ 40 | #ifndef CLICKOS_H 41 | #define CLICKOS_H 42 | 43 | #define MAX_CLICK_SCRIPTS 32 44 | 45 | #ifndef BINDING_SWIG 46 | struct click_script { 47 | char *name; 48 | char *path; 49 | }; 50 | 51 | struct clickos_domain { 52 | int quiet; 53 | int paused; 54 | int vnc; 55 | const char *config_file; 56 | char *config_data; 57 | const char *click_file; 58 | char *extra_config; /* extra config string */ 59 | char *restore_file; 60 | int migrate_fd; /* -1 means none */ 61 | char **migration_domname_r; /* from malloc */ 62 | }; 63 | 64 | int clickos_create2(struct clickos_domain *dom_info); 65 | int clickos_create3(const char *config_file, const char *args); 66 | #endif /* BINDING_SWIG */ 67 | 68 | int clickos_global_init(int verbose); 69 | void clickos_global_free(void); 70 | 71 | int clickos_domid(char *domname); 72 | 73 | int clickos_create(const char *config_file); 74 | int clickos_create1(const char *name, const char* kernel_path); 75 | 76 | int clickos_destroy(int domid, int force); 77 | 78 | int clickos_suspend(int domid, char* filename); 79 | 80 | int clickos_start(int domid, const char *name, const char *script); 81 | int clickos_stop(int domid, int configid); 82 | 83 | char* clickos_read_script(const char *script_path); 84 | char* clickos_read_handler(int domid, char *element, char *attr); 85 | char* clickos_write_handler(int domid, char *element, char *attr, char *value); 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /include/xcl/xcl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Xen control light 3 | * 4 | * file: xcl.h 5 | * 6 | * NEC Europe Ltd. PROPRIETARY INFORMATION 7 | * 8 | * This software is supplied under the terms of a license agreement 9 | * or nondisclosure agreement with NEC Europe Ltd. and may not be 10 | * copied or disclosed except in accordance with the terms of that 11 | * agreement. The software and its source code contain valuable trade 12 | * secrets and confidential information which have to be maintained in 13 | * confidence. 14 | * Any unauthorized publication, transfer to third parties or duplication 15 | * of the object or source code - either totally or in part – is 16 | * prohibited. 17 | * 18 | * Copyright (c) 2014 NEC Europe Ltd. All Rights Reserved. 19 | * 20 | * Authors: Joao Martins 21 | * 22 | * NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, 23 | * INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY 24 | * AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT 25 | * DEFECTS, WITH RESPECT TO THE PROGRAM AND THE ACCOMPANYING 26 | * DOCUMENTATION. 27 | * 28 | * No Liability For Consequential Damages IN NO EVENT SHALL NEC Europe 29 | * Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE LIABLE FOR ANY 30 | * DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS 31 | * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR 32 | * OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL, 33 | * ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY 34 | * TO USE THIS PROGRAM, EVEN IF NEC Europe Ltd. HAS BEEN ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGES. 36 | * 37 | * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 38 | */ 39 | #ifndef LIBXCL_H 40 | #define LIBXCL_H 41 | 42 | #ifndef _GNU_SOURCE 43 | #define _GNU_SOURCE 44 | #endif 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #ifdef LIBXCL 56 | #include 57 | #endif 58 | 59 | #define NLOG(fmt, ...) 60 | #define LOG(fmt, ...) \ 61 | fprintf(stderr, "[%s:%d]: " fmt "\n", \ 62 | __FUNCTION__, __LINE__, ##__VA_ARGS__) 63 | #define LOGE(fmt, ...) \ 64 | fprintf(stderr, "[%s:%d] error: " fmt "\n", \ 65 | __FUNCTION__, __LINE__, ##__VA_ARGS__) 66 | 67 | struct xcl_domstate { 68 | uint32_t store_port; 69 | uint32_t store_domid; 70 | unsigned long store_mfn; 71 | uint32_t console_port; 72 | uint32_t console_domid; 73 | unsigned long console_mfn; 74 | char *kernel_path; 75 | const char *cmdline; 76 | #define MAX_DEVICE_NIC 16 77 | 78 | int nr_nics; 79 | struct xcl_device_nic { 80 | u_int backend_domid; 81 | char *mac; 82 | char *bridge; 83 | char *ifname; 84 | char *script; 85 | char *type; 86 | } *nics; 87 | }; 88 | 89 | struct xcl_dominfo { 90 | /* main info */ 91 | uint32_t domid; 92 | char *name; 93 | uint8_t uuid[16]; 94 | char *uuid_string; 95 | uint32_t ssidref; 96 | bool pvh; 97 | int max_vcpus; 98 | uint32_t pcpu; 99 | uint64_t max_memkb; 100 | uint64_t target_memkb; 101 | uint64_t video_memkb; 102 | uint64_t shadow_memkb; 103 | uint32_t rtc_timeoffset; 104 | 105 | /* guest */ 106 | char * kernel; 107 | uint64_t slack_memkb; 108 | char * cmdline; 109 | const char * features; 110 | 111 | /* dom state*/ 112 | struct xcl_domstate *state; 113 | }; 114 | 115 | struct xcl_ctx { 116 | struct xs_handle *xsh; 117 | xc_interface *xch; 118 | }; 119 | 120 | void xcl_ctx_init(void); 121 | void xcl_ctx_dispose(void); 122 | int xcl_dom_id(char *name); 123 | 124 | void xcl_dom_create(struct xcl_dominfo *info); 125 | void xcl_dom_shutdown(int domid); 126 | void xcl_dom_destroy(int domid); 127 | 128 | int xcl_net_nrdevs(int domid); 129 | void xcl_net_attach(int domid, int nr_nics, struct xcl_device_nic *nics); 130 | void xcl_net_detach(int domid, int devid); 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /include/xcl/xcl_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Xen control light 3 | * 4 | * file: xcl_util.h 5 | * 6 | * NEC Europe Ltd. PROPRIETARY INFORMATION 7 | * 8 | * This software is supplied under the terms of a license agreement 9 | * or nondisclosure agreement with NEC Europe Ltd. and may not be 10 | * copied or disclosed except in accordance with the terms of that 11 | * agreement. The software and its source code contain valuable trade 12 | * secrets and confidential information which have to be maintained in 13 | * confidence. 14 | * Any unauthorized publication, transfer to third parties or duplication 15 | * of the object or source code - either totally or in part – is 16 | * prohibited. 17 | * 18 | * Copyright (c) 2014 NEC Europe Ltd. All Rights Reserved. 19 | * 20 | * Authors: Joao Martins 21 | * 22 | * NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, 23 | * INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY 24 | * AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT 25 | * DEFECTS, WITH RESPECT TO THE PROGRAM AND THE ACCOMPANYING 26 | * DOCUMENTATION. 27 | * 28 | * No Liability For Consequential Damages IN NO EVENT SHALL NEC Europe 29 | * Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE LIABLE FOR ANY 30 | * DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS 31 | * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR 32 | * OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL, 33 | * ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY 34 | * TO USE THIS PROGRAM, EVEN IF NEC Europe Ltd. HAS BEEN ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGES. 36 | * 37 | * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 38 | */ 39 | #ifndef LIBXCL_UTIL_H 40 | #define LIBXCL_UTIL_H 41 | 42 | #ifndef _GNU_SOURCE 43 | #define _GNU_SOURCE 44 | #endif 45 | 46 | #include "xcl.h" 47 | 48 | extern struct xcl_ctx *ctx; 49 | extern xs_transaction_t t; 50 | 51 | #define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" 52 | #define UUID_FMTLEN ((2*16)+4) 53 | #define UUID_BYTES(uuid) uuid[0], uuid[1], uuid[2], uuid[3], \ 54 | uuid[4], uuid[5], uuid[6], uuid[7], \ 55 | uuid[8], uuid[9], uuid[10], uuid[11], \ 56 | uuid[12], uuid[13], uuid[14], uuid[15] 57 | 58 | #define TO_UUID_BYTES(arg) UUID_BYTES(((uint8_t *) arg)) 59 | 60 | static inline char* uuid_to_str(uint8_t uuid[]) 61 | { 62 | char *uuidstr = NULL; 63 | asprintf(&uuidstr, UUID_FMT, TO_UUID_BYTES(uuid)); 64 | return uuidstr; 65 | } 66 | 67 | #define __xsread(p) xs_read(ctx->xsh, XBT_NULL, p, NULL) 68 | #define __xswrite(p,v) xs_write(ctx->xsh, t, p, v, strlen(v)) 69 | #define __xschmod(p, f) xs_set_permissions(ctx->xsh, t, p, f, 1); 70 | 71 | static inline char* __xsreadk(char *path, char *key) 72 | { 73 | char *xspath = NULL; 74 | asprintf(&xspath, "%s/%s", path, key); 75 | return __xsread(xspath); 76 | } 77 | 78 | static inline void __xswritek(char *path, char *key, char *value) 79 | { 80 | char *xspath = NULL; 81 | asprintf(&xspath, "%s/%s", path, key); 82 | __xswrite(xspath, value); 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/clickos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cosmos 3 | * 4 | * file: clickos.c 5 | * 6 | * NEC Europe Ltd. PROPRIETARY INFORMATION 7 | * 8 | * This software is supplied under the terms of a license agreement 9 | * or nondisclosure agreement with NEC Europe Ltd. and may not be 10 | * copied or disclosed except in accordance with the terms of that 11 | * agreement. The software and its source code contain valuable trade 12 | * secrets and confidential information which have to be maintained in 13 | * confidence. 14 | * Any unauthorized publication, transfer to third parties or duplication 15 | * of the object or source code - either totally or in part – is 16 | * prohibited. 17 | * 18 | * Copyright (c) 2014 NEC Europe Ltd. All Rights Reserved. 19 | * 20 | * Authors: Joao Martins 21 | * Filipe Manco 22 | * 23 | * NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, 24 | * INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY 25 | * AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT 26 | * DEFECTS, WITH RESPECT TO THE PROGRAM AND THE ACCOMPANYING 27 | * DOCUMENTATION. 28 | * 29 | * No Liability For Consequential Damages IN NO EVENT SHALL NEC Europe 30 | * Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE LIABLE FOR ANY 31 | * DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS 32 | * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR 33 | * OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL, 34 | * ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY 35 | * TO USE THIS PROGRAM, EVEN IF NEC Europe Ltd. HAS BEEN ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGES. 37 | * 38 | * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 39 | */ 40 | #ifndef _GNU_SOURCE 41 | #define _GNU_SOURCE 42 | #endif 43 | 44 | #include 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #include "clickos.h" 54 | 55 | int domain_ctx_init(int flags); 56 | void domain_ctx_free(void); 57 | int domain_name_to_id(char *name); 58 | int domain_create(struct clickos_domain *dom_info); 59 | int domain_destroy(int domid, int force); 60 | int domain_suspend(const int domid, const char *filename); 61 | 62 | static struct xs_handle *xs; 63 | static xs_transaction_t th; 64 | static char *domain_root_path; 65 | static struct xs_permissions default_domain_perms; 66 | static const char clickos_config_fmt[] = "kernel = '%s'\n" 67 | "vcpus = '1'\n" 68 | "memory = 16\n" 69 | "name = '%s'\n" 70 | "on_start = 'pause'\n" 71 | "on_crash = 'destroy'\n" 72 | "extra = '-d standard'\n\n"; 73 | 74 | #define XENBUS_ID_NET "vif" 75 | #define MAX_ENTRY_LENGTH 4096 76 | #define MAX_PATH_LENGTH 256 77 | #define MAX_CHUNK_LENGTH 992 78 | #define MAX_ID_LENGTH 32 79 | 80 | int devid = -1; 81 | 82 | static void xenstore_init(int domid) 83 | { 84 | /* Get a connection to the daemon */ 85 | xs = xs_daemon_open(); 86 | 87 | if (!xs) { 88 | perror("error opening xenstore"); 89 | exit(1); 90 | } 91 | 92 | /* Get the local domain path */ 93 | domain_root_path = xs_get_domain_path(xs, domid); 94 | } 95 | 96 | #define xenstore_read(p) xs_read(xs, XBT_NULL, p, NULL) 97 | #define xenstore_write(p,v) xs_write(xs, th, p, v, strlen(v)) 98 | #define xenstore_chmod(p, f) xs_set_permissions(xs, th, p, f, 1); 99 | 100 | char* clickos_read_handler(int domid, char *elem, char *attr) 101 | { 102 | char *ctrlpath = NULL, *elempath = NULL; 103 | char *rpath = NULL, *wpath = NULL; 104 | char *value; 105 | int err; 106 | unsigned int len = 0; 107 | struct pollfd fds[1]; 108 | 109 | if (!xs) { 110 | xenstore_init(domid); 111 | } 112 | 113 | asprintf(&ctrlpath, "/local/domain/%d/data/clickos/0/control", domid); 114 | asprintf(&elempath, "/local/domain/%d/data/clickos/0/elements", domid); 115 | asprintf(&wpath, "%s/read/%s/%s", ctrlpath, elem, attr); 116 | asprintf(&rpath, "%s/%s/%s", elempath, elem, attr); 117 | 118 | th = xs_transaction_start(xs); 119 | xenstore_write(wpath, " "); 120 | xs_transaction_end(xs, th, 0); 121 | 122 | err = xs_watch(xs, rpath, "lock"); 123 | if (!err) { 124 | printf("Error setting a watch\n"); 125 | return NULL; 126 | } 127 | 128 | fds[0].fd = xs_fileno(xs); 129 | fds[0].events = (POLLIN); 130 | while (len <= 0) { 131 | if (poll(fds, 1, 1000) <= 0) { 132 | continue; 133 | } 134 | 135 | retry_wh: 136 | th = xs_transaction_start(xs); 137 | //value = xenstore_read(rpath); 138 | value = xs_read(xs, XBT_NULL, rpath, &len); 139 | //printf("read: len %d value %s\n", len, value); 140 | if (!xs_transaction_end(xs, th, 0)) { 141 | if (errno == EAGAIN) 142 | goto retry_wh; 143 | } 144 | usleep(5000); 145 | } 146 | 147 | err = xs_unwatch(xs, rpath, "lock"); 148 | th = xs_transaction_start(xs); 149 | xs_write(xs, th, rpath, "", 0); 150 | err = xs_transaction_end(xs, th, 0); 151 | return value; 152 | } 153 | 154 | char* clickos_write_handler(int domid, char *elem, char *attr, char *value) 155 | { 156 | char *elempath = NULL; 157 | char *wpath = NULL; 158 | 159 | if (!xs) { 160 | xenstore_init(domid); 161 | } 162 | 163 | asprintf(&elempath, "/local/domain/%d/data/clickos/0/elements", domid); 164 | asprintf(&wpath, "%s/%s/%s", elempath, elem, attr); 165 | 166 | xenstore_write(wpath, value); 167 | return 0; 168 | } 169 | 170 | static unsigned get_file_size(const char * file_name) 171 | { 172 | struct stat sb; 173 | if (stat(file_name, &sb) != 0) { 174 | fprintf (stderr, "'stat' failed for '%s': %s.\n", 175 | file_name, strerror(errno)); 176 | exit(EXIT_FAILURE); 177 | } 178 | return sb.st_size; 179 | } 180 | 181 | char* clickos_read_script(const char *script_path) 182 | { 183 | int len, bytes_read; 184 | char *script; 185 | FILE *f; 186 | 187 | len = get_file_size(script_path); 188 | script = malloc(len + 1); 189 | f = fopen(script_path, "r"); 190 | 191 | bytes_read = fread(script, sizeof(unsigned char), len, f); 192 | fclose(f); 193 | 194 | if (bytes_read != len) { 195 | fprintf(stderr, "(Only) Read %d of %d bytes from %s", 196 | bytes_read, len, script_path); 197 | free(script); 198 | errno = EINVAL; 199 | return NULL; 200 | } 201 | // make sure the string is null terminated 202 | script[len] = '\0'; 203 | return script; 204 | } 205 | 206 | int clickos_start(int domid, const char *name, const char *script) 207 | { 208 | const char *clickos_config_path_tail = "/config/"; 209 | char clickos_script_chunk[1501]; 210 | 211 | char *clickos_root_path = NULL; 212 | char *clickos_elem_path = NULL; 213 | char *clickos_ctl_path = NULL; 214 | char *clickos_config_name_path = NULL; 215 | char *clickos_config_path = NULL; 216 | char *clickos_status_path = NULL; 217 | char *clickos_router_path = NULL; 218 | int clickos_config_id = 0; 219 | default_domain_perms.id = domid; 220 | default_domain_perms.perms = XS_PERM_READ | XS_PERM_WRITE; 221 | 222 | if (!xs) { 223 | xenstore_init(domid); 224 | } 225 | 226 | retry_clickos: 227 | // Transaction for ClickOS 228 | th = xs_transaction_start(xs); 229 | 230 | asprintf(&domain_root_path, "/local/domain/%d", domid); 231 | 232 | do { 233 | asprintf(&clickos_root_path, "%s/data/clickos/%d", domain_root_path, clickos_config_id); 234 | clickos_router_path = xenstore_read(clickos_root_path); 235 | if (clickos_router_path) 236 | clickos_config_id++; 237 | } while (clickos_router_path != NULL); 238 | 239 | asprintf(&clickos_elem_path, "%s/elements", clickos_root_path); 240 | asprintf(&clickos_ctl_path, "%s/control", clickos_root_path); 241 | asprintf(&clickos_config_name_path, "%s/config_name", clickos_root_path); 242 | asprintf(&clickos_status_path, "%s/status", clickos_root_path); 243 | 244 | xenstore_write(clickos_elem_path, ""); 245 | xenstore_write(clickos_ctl_path, ""); 246 | 247 | xenstore_chmod(clickos_elem_path, &default_domain_perms); 248 | xenstore_chmod(clickos_ctl_path, &default_domain_perms); 249 | 250 | xenstore_write(clickos_config_name_path, name); 251 | 252 | // we need one character for each chunk 253 | int config_path_len = strlen(clickos_root_path) 254 | + strlen(clickos_config_path_tail) + MAX_ID_LENGTH + 1; 255 | clickos_config_path = malloc(config_path_len); 256 | int chunk = 0; 257 | int scriptSize = strlen(script); 258 | int remainingScriptSize = scriptSize; 259 | do { 260 | snprintf(clickos_config_path, config_path_len, "%s%s%d", 261 | clickos_root_path, clickos_config_path_tail, chunk); 262 | int chunkSize = MAX_CHUNK_LENGTH; 263 | if (remainingScriptSize < MAX_CHUNK_LENGTH) { 264 | chunkSize = remainingScriptSize; 265 | } 266 | memcpy(clickos_script_chunk, script + (chunk * MAX_CHUNK_LENGTH), chunkSize); 267 | clickos_script_chunk[chunkSize] = '\0'; 268 | xenstore_write(clickos_config_path, clickos_script_chunk); 269 | chunk++; 270 | remainingScriptSize -= chunkSize; 271 | } while (remainingScriptSize > 0); 272 | 273 | if (!xs_transaction_end(xs, th, 0)) { 274 | if (errno == EAGAIN) 275 | goto retry_clickos; 276 | } 277 | 278 | retry_status: 279 | // Transaction for ClickOS state 280 | th = xs_transaction_start(xs); 281 | 282 | xenstore_write(clickos_status_path, "Running"); 283 | 284 | if (!xs_transaction_end(xs, th, 0)) { 285 | if (errno == EAGAIN) 286 | goto retry_status; 287 | } 288 | 289 | return 0; 290 | } 291 | 292 | int clickos_stop(int domid, int configid) 293 | { 294 | char *statuspath = NULL; 295 | 296 | if (!xs) { 297 | xenstore_init(domid); 298 | } 299 | 300 | asprintf(&statuspath, "/local/domain/%d/data/clickos/%d/status", domid, configid); 301 | 302 | retry_stop: 303 | th = xs_transaction_start(xs); 304 | xenstore_write(statuspath, "Halted"); 305 | if (!xs_transaction_end(xs, th, 0)) { 306 | if (errno == EAGAIN) 307 | goto retry_stop; 308 | } 309 | return 0; 310 | } 311 | 312 | int clickos_global_init(int flags) 313 | { 314 | return domain_ctx_init(flags); 315 | } 316 | 317 | void clickos_global_free(void) 318 | { 319 | domain_ctx_free(); 320 | } 321 | 322 | int clickos_domid(char *domname) 323 | { 324 | uint32_t domid; 325 | domid = domain_name_to_id(domname); 326 | return domid <= 0 ? -ENOENT : domid; 327 | } 328 | 329 | int clickos_create(const char *config_file) 330 | { 331 | struct clickos_domain dom_info; 332 | memset(&dom_info, 0, sizeof(struct clickos_domain)); 333 | dom_info.quiet = 1; 334 | dom_info.config_file = config_file; 335 | dom_info.click_file = NULL; 336 | dom_info.extra_config = "\0"; 337 | dom_info.migrate_fd = -1; 338 | 339 | return domain_create(&dom_info); 340 | } 341 | 342 | int clickos_create1(const char *name, const char* kernel_path) 343 | { 344 | struct clickos_domain dom_info; 345 | 346 | memset(&dom_info, 0, sizeof(struct clickos_domain)); 347 | dom_info.quiet = 1; 348 | dom_info.config_file = NULL; 349 | dom_info.click_file = NULL; 350 | dom_info.extra_config = "\0"; 351 | dom_info.migrate_fd = -1; 352 | 353 | asprintf(&dom_info.config_data, clickos_config_fmt, kernel_path, name); 354 | 355 | return domain_create(&dom_info); 356 | } 357 | 358 | #ifndef BINDING_SWIG 359 | int clickos_create2(struct clickos_domain *dom_info) 360 | { 361 | return domain_create(dom_info); 362 | } 363 | #endif 364 | 365 | int clickos_create3(const char *config_file, const char *args) 366 | { 367 | struct clickos_domain dom_info; 368 | 369 | memset(&dom_info, 0, sizeof(struct clickos_domain)); 370 | dom_info.quiet = 1; 371 | dom_info.config_file = NULL; 372 | dom_info.click_file = NULL; 373 | dom_info.extra_config = "\0"; 374 | dom_info.migrate_fd = -1; 375 | 376 | asprintf(&dom_info.config_data, "%s\nextra = '%s'\n", config_file, args); 377 | 378 | return domain_create(&dom_info); 379 | } 380 | 381 | int clickos_destroy(int domid, int force) 382 | { 383 | return domain_destroy(domid, force); 384 | } 385 | 386 | int clickos_suspend(int domid, char* filename) 387 | { 388 | return domain_suspend(domid, filename); 389 | } 390 | 391 | -------------------------------------------------------------------------------- /src/cosmos.i: -------------------------------------------------------------------------------- 1 | %module cosmos 2 | 3 | %rename(ctx) clickos_global_init; 4 | %rename(free) clickos_global_free; 5 | %rename(domid) clickos_domid; 6 | %rename(create) clickos_create; 7 | %rename(create_default) clickos_create1; 8 | %rename(destroy) clickos_destroy; 9 | %rename(network_attach) clickos_network_attach; 10 | %rename(script) clickos_read_script; 11 | %rename(start) clickos_start; 12 | %rename(stop) clickos_stop; 13 | %rename(readh) clickos_read_handler; 14 | %rename(writeh) clickos_write_handler; 15 | 16 | %ignore clickos_network_attach1; 17 | 18 | %inline %{ 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | extern int clickos_global_init(int verbose); 24 | extern void clickos_global_free(void); 25 | extern int clickos_domid(char *domname); 26 | extern int clickos_create(const char *config_file); 27 | extern int clickos_create1(const char *name, const char* kernel_path); 28 | extern int clickos_stop(int domid, int configid); 29 | extern int clickos_destroy(int domid, int force); 30 | extern int clickos_suspend(int domid, char* filename); 31 | extern int clickos_network_attach(int domid, char *macaddr, int backend_id, char *bridge); 32 | extern int clickos_start(int domid, const char *name, const char *script); 33 | extern char* clickos_read_script(const char *script_path); 34 | extern char* clickos_read_handler(int domid, char *element, char *attr); 35 | extern char* clickos_write_handler(int domid, char *element, char *attr, char *value); 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #ifdef BUILDING_NODE_EXTENSION 42 | #include 43 | #endif 44 | %} 45 | 46 | #include "clickos.h" 47 | -------------------------------------------------------------------------------- /src/domain_none.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cosmos 3 | * 4 | * file: domain_none.c 5 | * 6 | * NEC Europe Ltd. PROPRIETARY INFORMATION 7 | * 8 | * This software is supplied under the terms of a license agreement 9 | * or nondisclosure agreement with NEC Europe Ltd. and may not be 10 | * copied or disclosed except in accordance with the terms of that 11 | * agreement. The software and its source code contain valuable trade 12 | * secrets and confidential information which have to be maintained in 13 | * confidence. 14 | * Any unauthorized publication, transfer to third parties or duplication 15 | * of the object or source code - either totally or in part – is 16 | * prohibited. 17 | * 18 | * Copyright (c) 2014 NEC Europe Ltd. All Rights Reserved. 19 | * 20 | * Authors: Joao Martins 21 | * 22 | * NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, 23 | * INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY 24 | * AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT 25 | * DEFECTS, WITH RESPECT TO THE PROGRAM AND THE ACCOMPANYING 26 | * DOCUMENTATION. 27 | * 28 | * No Liability For Consequential Damages IN NO EVENT SHALL NEC Europe 29 | * Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE LIABLE FOR ANY 30 | * DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS 31 | * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR 32 | * OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL, 33 | * ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY 34 | * TO USE THIS PROGRAM, EVEN IF NEC Europe Ltd. HAS BEEN ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGES. 36 | * 37 | * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 38 | */ 39 | #include 40 | #include 41 | #include 42 | 43 | #include "clickos.h" 44 | 45 | int domain_name_to_id(char *name) 46 | { 47 | return atoi(name); 48 | } 49 | 50 | int domain_ctx_init(int flags) 51 | { 52 | return -ENOTSUP; 53 | } 54 | 55 | void domain_ctx_free(void) 56 | { 57 | } 58 | 59 | int domain_create(struct clickos_domain *dom_info) 60 | { 61 | fprintf(stderr, "Compile with DOMLIB=xl or DOMLIB=xcl to enable this\n"); 62 | return -ENOTSUP; 63 | } 64 | 65 | int domain_suspend(const int domid, const char *filename) 66 | { 67 | fprintf(stderr, "Compile with DOMLIB=xl or DOMLIB=xcl to enable this\n"); 68 | return -ENOTSUP; 69 | } 70 | 71 | int domain_destroy(int domid, int force) 72 | { 73 | fprintf(stderr, "Compile with DOMLIB=xl or DOMLIB=xcl to enable this\n"); 74 | return -ENOTSUP; 75 | } 76 | -------------------------------------------------------------------------------- /src/domain_xcl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cosmos 3 | * 4 | * file: domain_xcl.c 5 | * 6 | * NEC Europe Ltd. PROPRIETARY INFORMATION 7 | * 8 | * This software is supplied under the terms of a license agreement 9 | * or nondisclosure agreement with NEC Europe Ltd. and may not be 10 | * copied or disclosed except in accordance with the terms of that 11 | * agreement. The software and its source code contain valuable trade 12 | * secrets and confidential information which have to be maintained in 13 | * confidence. 14 | * Any unauthorized publication, transfer to third parties or duplication 15 | * of the object or source code - either totally or in part – is 16 | * prohibited. 17 | * 18 | * Copyright (c) 2014 NEC Europe Ltd. All Rights Reserved. 19 | * 20 | * Authors: Joao Martins 21 | * 22 | * NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, 23 | * INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY 24 | * AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT 25 | * DEFECTS, WITH RESPECT TO THE PROGRAM AND THE ACCOMPANYING 26 | * DOCUMENTATION. 27 | * 28 | * No Liability For Consequential Damages IN NO EVENT SHALL NEC Europe 29 | * Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE LIABLE FOR ANY 30 | * DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS 31 | * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR 32 | * OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL, 33 | * ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY 34 | * TO USE THIS PROGRAM, EVEN IF NEC Europe Ltd. HAS BEEN ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGES. 36 | * 37 | * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 38 | */ 39 | #include 40 | #include 41 | #include 42 | 43 | #include "clickos.h" 44 | 45 | static char* lstrip(const char* s) 46 | { 47 | while (*s && isspace((unsigned char)(*s))) 48 | s++; 49 | return (char*)s; 50 | } 51 | 52 | static char* rstrip(char *s) 53 | { 54 | char *end = s + strlen(s); 55 | while (end > s && isspace((unsigned char)(*--end))) 56 | *end = '\0'; 57 | 58 | return (char *) s; 59 | } 60 | 61 | #define strip(s) lstrip(rstrip(s)) 62 | 63 | static char* find_attr(const char *s) 64 | { 65 | char *attr = strchr(s, '='); 66 | return attr ? attr : (char *) s; 67 | } 68 | 69 | static int parse_config_item(struct xcl_dominfo **_info, const char *name, 70 | char *value, int devid) 71 | { 72 | struct xcl_dominfo *info = *_info; 73 | struct xcl_device_nic *nic = &info->state->nics[devid]; 74 | char *p, *p2; 75 | 76 | memset(nic, 0, sizeof(struct xcl_device_nic)); 77 | 78 | if (!strcmp(name, "vif")) { 79 | p = strtok(value, ","); 80 | if (!p) { 81 | return -EINVAL; 82 | } 83 | do { 84 | while (*p == ' ') 85 | p++; 86 | if ((p2 = strchr(p, '=')) == NULL) 87 | break; 88 | 89 | *p2 = '\0'; 90 | if (!strcmp(p, "mac")) { 91 | nic->mac = strndup(p2 + 1, 17); 92 | } else if (!strcmp(p, "bridge")) { 93 | nic->bridge = strdup(p2 + 1); 94 | } else if (!strcmp(p, "script")) { 95 | nic->script = strdup(p2 + 1); 96 | } else if (!strcmp(p, "backend")) { 97 | nic->backend_domid = 0; 98 | } 99 | 100 | } while ((p = strtok(NULL, ",")) != NULL); 101 | 102 | if (!nic->script) 103 | nic->script = "/etc/xen/scripts/vif-bridge"; 104 | 105 | if (!nic->type) 106 | nic->type = "vif"; 107 | } 108 | return 0; 109 | } 110 | 111 | #define is_sep(str, i) \ 112 | (str[i] == ',') && \ 113 | (str[i-1] == '\'') && \ 114 | (str[i+1] == '\'') 115 | 116 | #define XCL_MAX_DEVICES 4 117 | 118 | static void parse_config_list(struct xcl_dominfo **_info, const char *name, 119 | char *val) 120 | { 121 | struct xcl_dominfo *info = *_info; 122 | int i; 123 | int is_item = 0, item_parsed = 0; 124 | int nr_items = 0; 125 | char *token, *token_end, *buf; 126 | char *end = strchr(++val, ']'); 127 | *end = '\0'; 128 | 129 | if (!strcmp(name, "vif")) 130 | info->state->nics = malloc(XCL_MAX_DEVICES * 131 | sizeof(struct xcl_device_nic*)); 132 | 133 | for (i=0 ; val[i] != 0 ;++i) { 134 | if (is_sep(val, i)) { 135 | continue; 136 | } 137 | 138 | if (val[i] == '\'') { 139 | if (is_item) { 140 | nr_items++; 141 | } 142 | is_item = !is_item; 143 | item_parsed = 0; 144 | continue; 145 | } 146 | 147 | if (is_item && !item_parsed) { 148 | item_parsed = 1; 149 | token = strdup(&val[i]); 150 | token_end = strchr(token, '\''); 151 | *token_end = '\0'; 152 | buf = malloc(strlen(token)); 153 | strncpy(buf, token, token_end - token); 154 | i += strlen(buf) - 2; 155 | parse_config_item(_info, name, buf, nr_items); 156 | } 157 | } 158 | 159 | info->state->nr_nics = nr_items; 160 | } 161 | 162 | static void parse_config_value(struct xcl_dominfo **dinfo, const char **click_file, 163 | const char *name, char *value) 164 | { 165 | struct xcl_dominfo *info = *dinfo; 166 | int len = strlen(value); 167 | char *val = value; 168 | 169 | if (val[0] == '\'') { 170 | val++; 171 | val[len-2] = '\0'; 172 | len--; 173 | } 174 | 175 | if (!strcmp(name, "pvh")) 176 | info->pvh = atoi(val) != 0 ? true : false; 177 | 178 | if (!strcmp(name, "cpus")) 179 | info->pcpu = atoi(val); 180 | 181 | if (!strcmp(name, "vcpus")) 182 | info->max_vcpus = atoi(val); 183 | 184 | if (!strcmp(name, "name")) { 185 | info->name = malloc(sizeof(char) * len); 186 | info->name[len] = '\0'; 187 | strncpy(info->name, val, len); 188 | } 189 | 190 | if (!strcmp(name, "memory")) { 191 | info->target_memkb = atoi(val) * 1024; 192 | info->max_memkb = info->target_memkb * 2; 193 | } 194 | 195 | if (!strcmp(name, "kernel")) { 196 | info->state->kernel_path = malloc(sizeof(char) * len); 197 | info->state->kernel_path[len] = '\0'; 198 | strncpy(info->state->kernel_path, val, len); 199 | } 200 | 201 | if (!strcmp(name, "click")) { 202 | char *click_cfg; 203 | click_cfg = malloc(sizeof(char) * len); 204 | click_cfg[len] = '\0'; 205 | strncpy(click_cfg, val, len); 206 | *click_file = click_cfg; 207 | } 208 | } 209 | 210 | #define MAX_LINE_LEN 256 211 | static void parse_config(const char *config, struct xcl_dominfo *info, 212 | const char **click_file) 213 | { 214 | FILE *file; 215 | char *line = (char*) malloc(MAX_LINE_LEN); 216 | char *buf, *cont; 217 | 218 | file = fopen(config, "r"); 219 | if (!file) { 220 | errno = ENOENT; 221 | return; 222 | } 223 | 224 | while (fgets(line, MAX_LINE_LEN, file) != NULL) { 225 | buf = lstrip(rstrip(line)); 226 | if (*buf == '#') { 227 | continue; 228 | } 229 | 230 | cont = find_attr(buf); 231 | if (*cont == '=') { 232 | char *name, *value; 233 | *cont = '\0'; 234 | name = rstrip(buf); 235 | value = lstrip(cont + 1); 236 | if (value[0] == '[') 237 | parse_config_list(&info, name, value); 238 | else 239 | parse_config_value(&info, click_file, name, value); 240 | } 241 | 242 | } 243 | fclose(file); 244 | } 245 | 246 | int domain_name_to_id(char *name) 247 | { 248 | return xcl_dom_id(name); 249 | } 250 | 251 | int domain_ctx_init(int flags) 252 | { 253 | xcl_ctx_init(); 254 | return 0; 255 | } 256 | 257 | void domain_ctx_free(void) 258 | { 259 | xcl_ctx_dispose(); 260 | } 261 | 262 | int domain_create(struct clickos_domain *dom_info) 263 | { 264 | struct xcl_dominfo info; 265 | struct xcl_domstate state; 266 | 267 | memset(&info, 0, sizeof(struct xcl_dominfo)); 268 | memset(&state, 0, sizeof(struct xcl_domstate)); 269 | 270 | info.state = &state; 271 | parse_config(dom_info->config_file, &info, &dom_info->click_file); 272 | 273 | xcl_dom_create(&info); 274 | 275 | if (dom_info->click_file) { 276 | clickos_start(info.domid, dom_info->click_file, 277 | clickos_read_script(dom_info->click_file)); 278 | } 279 | 280 | return 0; 281 | } 282 | 283 | int domain_suspend(const int domid, const char *filename) 284 | { 285 | return -ENOTSUP; 286 | } 287 | 288 | int domain_destroy(int domid, int force) 289 | { 290 | if (domid <= 0) { 291 | fprintf(stderr, "domain_xcl: please supply a domain id\n"); 292 | return -EINVAL; 293 | } 294 | 295 | if (force) 296 | xcl_dom_destroy(domid); 297 | else 298 | xcl_dom_shutdown(domid); 299 | return 0; 300 | } 301 | -------------------------------------------------------------------------------- /src/domain_xl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Domain creation based on xl toolstack 3 | * Copyright (c) 2014 NEC Europe Ltd., NEC Corporation 4 | * Author Joao Martins 5 | * Author Filipe Manco 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as published 9 | * by the Free Software Foundation; version 2.1 only. with the special 10 | * exception on linking described in file LICENSE. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU Lesser General Public License for more details. 16 | */ 17 | #ifndef CLICKOS_DOMAIN_H 18 | #define CLICKOS_DOMAIN_H 19 | 20 | #define _GNU_SOURCE 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include /* for utsname in xl info */ 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | #include "clickos.h" 46 | 47 | #define CHK_ERRNO( call ) ({ \ 48 | int chk_errno = (call); \ 49 | if (chk_errno < 0) { \ 50 | fprintf(stderr,"xl: fatal error: %s:%d: %s: %s\n", \ 51 | __FILE__,__LINE__, strerror(chk_errno), #call); \ 52 | exit(-ERROR_FAIL); \ 53 | } \ 54 | }) 55 | 56 | #define MUST( call ) ({ \ 57 | int must_rc = (call); \ 58 | if (must_rc < 0) { \ 59 | fprintf(stderr,"xl: fatal error: %s:%d, rc=%d: %s\n", \ 60 | __FILE__,__LINE__, must_rc, #call); \ 61 | exit(-must_rc); \ 62 | } \ 63 | }) 64 | 65 | xentoollog_logger_stdiostream *logger; 66 | xentoollog_level minmsglevel = XTL_PROGRESS; 67 | /* every libxl action in xl uses this same libxl context */ 68 | libxl_ctx *ctx; 69 | char *lockfile; 70 | 71 | int autoballoon = 0; 72 | int run_hotplug_scripts = 1; 73 | int logfile = 2; 74 | char *lockfile; 75 | char *default_vifscript = NULL; 76 | char *default_bridge = "xenbr0"; 77 | char *blkdev_start; 78 | 79 | /* when we operate on a domain, it is this one: */ 80 | /* when we operate on a domain, it is this one: */ 81 | #define INVALID_DOMID ~0 82 | static uint32_t domid = INVALID_DOMID; 83 | static const char *common_domname; 84 | static int fd_lock = -1; 85 | 86 | /* Stash for specific vcpu to pcpu mappping */ 87 | static int *vcpu_to_pcpu; 88 | 89 | static const char savefileheader_magic[32]= 90 | "Xen saved domain, xl format\n \0 \r"; 91 | 92 | static const char migrate_receiver_banner[]= 93 | "xl migration receiver ready, send binary domain data.\n"; 94 | static const char migrate_receiver_ready[]= 95 | "domain received, ready to unpause"; 96 | static const char migrate_permission_to_go[]= 97 | "domain is yours, you are cleared to unpause"; 98 | static const char migrate_report[]= 99 | "my copy unpause results are as follows"; 100 | /* followed by one byte: 101 | * 0: everything went well, domain is running 102 | * next thing is we all exit 103 | * non-0: things went badly 104 | * next thing should be a migrate_permission_to_go 105 | * from target to source 106 | */ 107 | 108 | struct save_file_header { 109 | char magic[32]; /* savefileheader_magic */ 110 | /* All uint32_ts are in domain's byte order. */ 111 | uint32_t byteorder; /* SAVEFILE_BYTEORDER_VALUE */ 112 | uint32_t mandatory_flags; /* unknown flags => reject restore */ 113 | uint32_t optional_flags; /* unknown flags => reject restore */ 114 | uint32_t optional_data_len; /* skip, or skip tail, if not understood */ 115 | }; 116 | 117 | typedef struct { 118 | char *click_file; 119 | } clickos_extra_config; 120 | 121 | static const char *action_on_shutdown_names[] = { 122 | [LIBXL_ACTION_ON_SHUTDOWN_DESTROY] = "destroy", 123 | 124 | [LIBXL_ACTION_ON_SHUTDOWN_RESTART] = "restart", 125 | [LIBXL_ACTION_ON_SHUTDOWN_RESTART_RENAME] = "rename-restart", 126 | 127 | [LIBXL_ACTION_ON_SHUTDOWN_PRESERVE] = "preserve", 128 | 129 | [LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY] = "coredump-destroy", 130 | [LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_RESTART] = "coredump-restart", 131 | }; 132 | 133 | /* Optional data, in order: 134 | * 4 bytes uint32_t config file size 135 | * n bytes config file in Unix text file format 136 | */ 137 | 138 | #define SAVEFILE_BYTEORDER_VALUE ((uint32_t)0x01020304UL) 139 | 140 | static int qualifier_to_id(const char *p, uint32_t *id_r) 141 | { 142 | int i, alldigit; 143 | 144 | alldigit = 1; 145 | for (i = 0; p[i]; i++) { 146 | if (!isdigit((uint8_t)p[i])) { 147 | alldigit = 0; 148 | break; 149 | } 150 | } 151 | 152 | if (i > 0 && alldigit) { 153 | *id_r = strtoul(p, NULL, 10); 154 | return 0; 155 | } else { 156 | /* check here if it's a uuid and do proper conversion */ 157 | } 158 | return 1; 159 | } 160 | 161 | static int cpupool_qualifier_to_cpupoolid(const char *p, uint32_t *poolid_r, 162 | int *was_name_r) 163 | { 164 | int was_name; 165 | 166 | was_name = qualifier_to_id(p, poolid_r); 167 | if (was_name_r) *was_name_r = was_name; 168 | return was_name ? libxl_name_to_cpupoolid(ctx, p, poolid_r) : 0; 169 | } 170 | 171 | static int acquire_lock(void) 172 | { 173 | int rc; 174 | struct flock fl; 175 | 176 | /* lock already acquired */ 177 | if (fd_lock >= 0) 178 | return ERROR_INVAL; 179 | 180 | fl.l_type = F_WRLCK; 181 | fl.l_whence = SEEK_SET; 182 | fl.l_start = 0; 183 | fl.l_len = 0; 184 | fd_lock = open(lockfile, O_WRONLY|O_CREAT, S_IWUSR); 185 | if (fd_lock < 0) { 186 | fprintf(stderr, "cannot open the lockfile %s errno=%d\n", lockfile, errno); 187 | return ERROR_FAIL; 188 | } 189 | if (fcntl(fd_lock, F_SETFD, FD_CLOEXEC) < 0) { 190 | close(fd_lock); 191 | fprintf(stderr, "cannot set cloexec to lockfile %s errno=%d\n", lockfile, errno); 192 | return ERROR_FAIL; 193 | } 194 | get_lock: 195 | rc = fcntl(fd_lock, F_SETLKW, &fl); 196 | if (rc < 0 && errno == EINTR) 197 | goto get_lock; 198 | if (rc < 0) { 199 | fprintf(stderr, "cannot acquire lock %s errno=%d\n", lockfile, errno); 200 | rc = ERROR_FAIL; 201 | } else 202 | rc = 0; 203 | return rc; 204 | } 205 | 206 | static int release_lock(void) 207 | { 208 | int rc; 209 | struct flock fl; 210 | 211 | /* lock not acquired */ 212 | if (fd_lock < 0) 213 | return ERROR_INVAL; 214 | 215 | release_lock: 216 | fl.l_type = F_UNLCK; 217 | fl.l_whence = SEEK_SET; 218 | fl.l_start = 0; 219 | fl.l_len = 0; 220 | 221 | rc = fcntl(fd_lock, F_SETLKW, &fl); 222 | if (rc < 0 && errno == EINTR) 223 | goto release_lock; 224 | if (rc < 0) { 225 | fprintf(stderr, "cannot release lock %s, errno=%d\n", lockfile, errno); 226 | rc = ERROR_FAIL; 227 | } else 228 | rc = 0; 229 | close(fd_lock); 230 | fd_lock = -1; 231 | 232 | return rc; 233 | } 234 | 235 | static void *xmalloc(size_t sz) { 236 | void *r; 237 | r = malloc(sz); 238 | if (!r) { fprintf(stderr,"xl: Unable to malloc %lu bytes.\n", 239 | (unsigned long)sz); exit(-ERROR_FAIL); } 240 | return r; 241 | } 242 | 243 | static int parse_action_on_shutdown(const char *buf, libxl_action_on_shutdown *a) 244 | { 245 | int i; 246 | const char *n; 247 | 248 | for (i = 0; i < sizeof(action_on_shutdown_names) / sizeof(action_on_shutdown_names[0]); i++) { 249 | n = action_on_shutdown_names[i]; 250 | 251 | if (!n) continue; 252 | 253 | if (strcmp(buf, n) == 0) { 254 | *a = i; 255 | return 1; 256 | } 257 | } 258 | return 0; 259 | } 260 | 261 | static void parse_disk_config_multistring(XLU_Config **config, 262 | int nspecs, const char *const *specs, 263 | libxl_device_disk *disk) 264 | { 265 | int e; 266 | 267 | libxl_device_disk_init(disk); 268 | 269 | if (!*config) { 270 | *config = xlu_cfg_init(stderr, "command line"); 271 | if (!*config) { perror("xlu_cfg_init"); exit(-1); } 272 | } 273 | 274 | e = xlu_disk_parse(*config, nspecs, specs, disk); 275 | if (e == EINVAL) exit(-1); 276 | if (e) { 277 | fprintf(stderr,"xlu_disk_parse failed: %s\n",strerror(errno)); 278 | exit(-1); 279 | } 280 | } 281 | 282 | static void parse_disk_config(XLU_Config **config, const char *spec, 283 | libxl_device_disk *disk) 284 | { 285 | parse_disk_config_multistring(config, 1, &spec, disk); 286 | } 287 | 288 | static void parse_vif_rate(XLU_Config **config, const char *rate, 289 | libxl_device_nic *nic) 290 | { 291 | int e; 292 | 293 | e = xlu_vif_parse_rate(*config, rate, nic); 294 | if (e == EINVAL || e == EOVERFLOW) exit(-1); 295 | if (e) { 296 | fprintf(stderr,"xlu_vif_parse_rate failed: %s\n",strerror(errno)); 297 | exit(-1); 298 | } 299 | } 300 | 301 | static void split_string_into_string_list(const char *str, 302 | const char *delim, 303 | libxl_string_list *psl) 304 | { 305 | char *s, *saveptr; 306 | const char *p; 307 | libxl_string_list sl; 308 | 309 | int i = 0, nr = 0; 310 | 311 | s = strdup(str); 312 | if (s == NULL) { 313 | fprintf(stderr, "unable to allocate memory to parse bootloader args\n"); 314 | exit(-1); 315 | } 316 | 317 | /* Count number of entries */ 318 | p = strtok_r(s, delim, &saveptr); 319 | do { 320 | nr++; 321 | } while ((p = strtok_r(NULL, delim, &saveptr))); 322 | 323 | free(s); 324 | 325 | s = strdup(str); 326 | 327 | sl = malloc((nr+1) * sizeof (char *)); 328 | if (sl == NULL) { 329 | fprintf(stderr, "unable to allocate memory for bootloader args\n"); 330 | exit(-1); 331 | } 332 | 333 | p = strtok_r(s, delim, &saveptr); 334 | do { 335 | assert(i < nr); 336 | sl[i] = strdup(p); 337 | i++; 338 | } while ((p = strtok_r(NULL, delim, &saveptr))); 339 | sl[i] = NULL; 340 | 341 | *psl = sl; 342 | 343 | free(s); 344 | } 345 | 346 | static int vcpupin_parse(char *cpu, libxl_bitmap *cpumap) 347 | { 348 | libxl_bitmap exclude_cpumap; 349 | uint32_t cpuida, cpuidb; 350 | char *endptr, *toka, *tokb, *saveptr = NULL; 351 | int i, rc = 0, rmcpu; 352 | 353 | if (!strcmp(cpu, "all")) { 354 | libxl_bitmap_set_any(cpumap); 355 | return 0; 356 | } 357 | 358 | if (libxl_cpu_bitmap_alloc(ctx, &exclude_cpumap, 0)) { 359 | fprintf(stderr, "Error: Failed to allocate cpumap.\n"); 360 | return ENOMEM; 361 | } 362 | 363 | for (toka = strtok_r(cpu, ",", &saveptr); toka; 364 | toka = strtok_r(NULL, ",", &saveptr)) { 365 | rmcpu = 0; 366 | if (*toka == '^') { 367 | /* This (These) Cpu(s) will be removed from the map */ 368 | toka++; 369 | rmcpu = 1; 370 | } 371 | /* Extract a valid (range of) cpu(s) */ 372 | cpuida = cpuidb = strtoul(toka, &endptr, 10); 373 | if (endptr == toka) { 374 | fprintf(stderr, "Error: Invalid argument.\n"); 375 | rc = EINVAL; 376 | goto vcpp_out; 377 | } 378 | if (*endptr == '-') { 379 | tokb = endptr + 1; 380 | cpuidb = strtoul(tokb, &endptr, 10); 381 | if (endptr == tokb || cpuida > cpuidb) { 382 | fprintf(stderr, "Error: Invalid argument.\n"); 383 | rc = EINVAL; 384 | goto vcpp_out; 385 | } 386 | } 387 | while (cpuida <= cpuidb) { 388 | rmcpu == 0 ? libxl_bitmap_set(cpumap, cpuida) : 389 | libxl_bitmap_set(&exclude_cpumap, cpuida); 390 | cpuida++; 391 | } 392 | } 393 | 394 | /* Clear all the cpus from the removal list */ 395 | libxl_for_each_set_bit(i, exclude_cpumap) { 396 | libxl_bitmap_reset(cpumap, i); 397 | } 398 | 399 | vcpp_out: 400 | libxl_bitmap_dispose(&exclude_cpumap); 401 | 402 | return rc; 403 | } 404 | static void parse_config_data(const char *config_source, 405 | const char *config_data, 406 | int config_len, 407 | libxl_domain_config *d_config, 408 | struct clickos_domain *dom_info, 409 | clickos_extra_config *e_config) 410 | 411 | { 412 | const char *buf; 413 | long l; 414 | XLU_Config *config; 415 | XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids; 416 | XLU_ConfigList *ioports, *irqs; 417 | int num_ioports, num_irqs; 418 | int pci_power_mgmt = 0; 419 | int pci_msitranslate = 0; 420 | int pci_permissive = 0; 421 | int i, e; 422 | 423 | libxl_domain_create_info *c_info = &d_config->c_info; 424 | libxl_domain_build_info *b_info = &d_config->b_info; 425 | 426 | config= xlu_cfg_init(stderr, config_source); 427 | if (!config) { 428 | fprintf(stderr, "Failed to allocate for configuration\n"); 429 | exit(1); 430 | } 431 | 432 | e= xlu_cfg_readdata(config, config_data, config_len); 433 | if (e) { 434 | fprintf(stderr, "Failed to parse config: %s\n", strerror(e)); 435 | exit(1); 436 | } 437 | if (!xlu_cfg_get_string (config, "seclabel", &buf, 0)) { 438 | e = libxl_flask_context_to_sid(ctx, (char *)buf, strlen(buf), 439 | &c_info->ssidref); 440 | if (e) { 441 | if (errno == ENOSYS) { 442 | fprintf(stderr, "XSM Disabled: seclabel not supported\n"); 443 | } else { 444 | fprintf(stderr, "Invalid seclabel: %s\n", buf); 445 | exit(1); 446 | } 447 | } 448 | } 449 | 450 | libxl_defbool_set(&c_info->run_hotplug_scripts, run_hotplug_scripts); 451 | c_info->type = LIBXL_DOMAIN_TYPE_PV; 452 | if (!xlu_cfg_get_string (config, "builder", &buf, 0) && 453 | !strncmp(buf, "hvm", strlen(buf))) 454 | c_info->type = LIBXL_DOMAIN_TYPE_HVM; 455 | 456 | xlu_cfg_get_defbool(config, "hap", &c_info->hap, 0); 457 | 458 | if (xlu_cfg_replace_string (config, "name", &c_info->name, 0)) { 459 | fprintf(stderr, "Domain name must be specified.\n"); 460 | exit(1); 461 | } 462 | 463 | if (!xlu_cfg_get_string (config, "uuid", &buf, 0) ) { 464 | if ( libxl_uuid_from_string(&c_info->uuid, buf) ) { 465 | fprintf(stderr, "Failed to parse UUID: %s\n", buf); 466 | exit(1); 467 | } 468 | }else{ 469 | libxl_uuid_generate(&c_info->uuid); 470 | } 471 | 472 | xlu_cfg_get_defbool(config, "oos", &c_info->oos, 0); 473 | 474 | if (!xlu_cfg_get_string (config, "pool", &buf, 0)) { 475 | c_info->poolid = -1; 476 | cpupool_qualifier_to_cpupoolid(buf, &c_info->poolid, NULL); 477 | } 478 | if (!libxl_cpupoolid_to_name(ctx, c_info->poolid)) { 479 | fprintf(stderr, "Illegal pool specified\n"); 480 | exit(1); 481 | } 482 | 483 | libxl_domain_build_info_init_type(b_info, c_info->type); 484 | if (blkdev_start) 485 | b_info->blkdev_start = strdup(blkdev_start); 486 | 487 | /* the following is the actual config parsing with overriding 488 | * values in the structures */ 489 | if (!xlu_cfg_get_long (config, "cpu_weight", &l, 0)) 490 | b_info->sched_params.weight = l; 491 | if (!xlu_cfg_get_long (config, "cap", &l, 0)) 492 | b_info->sched_params.cap = l; 493 | if (!xlu_cfg_get_long (config, "period", &l, 0)) 494 | b_info->sched_params.period = l; 495 | if (!xlu_cfg_get_long (config, "slice", &l, 0)) 496 | b_info->sched_params.slice = l; 497 | if (!xlu_cfg_get_long (config, "latency", &l, 0)) 498 | b_info->sched_params.latency = l; 499 | if (!xlu_cfg_get_long (config, "extratime", &l, 0)) 500 | b_info->sched_params.extratime = l; 501 | 502 | if (!xlu_cfg_get_long (config, "vcpus", &l, 0)) { 503 | b_info->max_vcpus = l; 504 | 505 | if (libxl_cpu_bitmap_alloc(ctx, &b_info->avail_vcpus, l)) { 506 | fprintf(stderr, "Unable to allocate cpumap\n"); 507 | exit(1); 508 | } 509 | libxl_bitmap_set_none(&b_info->avail_vcpus); 510 | while (l-- > 0) 511 | libxl_bitmap_set((&b_info->avail_vcpus), l); 512 | } 513 | 514 | if (!xlu_cfg_get_long (config, "maxvcpus", &l, 0)) 515 | b_info->max_vcpus = l; 516 | 517 | if (!xlu_cfg_get_list (config, "cpus", &cpus, 0, 1)) { 518 | int i, n_cpus = 0; 519 | 520 | if (libxl_cpu_bitmap_alloc(ctx, &b_info->cpumap, 0)) { 521 | fprintf(stderr, "Unable to allocate cpumap\n"); 522 | exit(1); 523 | } 524 | 525 | /* Prepare the array for single vcpu to pcpu mappings */ 526 | vcpu_to_pcpu = xmalloc(sizeof(int) * b_info->max_vcpus); 527 | memset(vcpu_to_pcpu, -1, sizeof(int) * b_info->max_vcpus); 528 | 529 | /* 530 | * Idea here is to let libxl think all the domain's vcpus 531 | * have cpu affinity with all the pcpus on the list. 532 | * It is then us, here in xl, that matches each single vcpu 533 | * to its pcpu (and that's why we need to stash such info in 534 | * the vcpu_to_pcpu array now) after the domain has been created. 535 | * Doing it like this saves the burden of passing to libxl 536 | * some big array hosting the single mappings. Also, using 537 | * the cpumap derived from the list ensures memory is being 538 | * allocated on the proper nodes anyway. 539 | */ 540 | libxl_bitmap_set_none(&b_info->cpumap); 541 | while ((buf = xlu_cfg_get_listitem(cpus, n_cpus)) != NULL) { 542 | i = atoi(buf); 543 | if (!libxl_bitmap_cpu_valid(&b_info->cpumap, i)) { 544 | fprintf(stderr, "cpu %d illegal\n", i); 545 | exit(1); 546 | } 547 | libxl_bitmap_set(&b_info->cpumap, i); 548 | if (n_cpus < b_info->max_vcpus) 549 | vcpu_to_pcpu[n_cpus] = i; 550 | n_cpus++; 551 | } 552 | 553 | /* We have a cpumap, disable automatic placement */ 554 | libxl_defbool_set(&b_info->numa_placement, false); 555 | } 556 | else if (!xlu_cfg_get_string (config, "cpus", &buf, 0)) { 557 | char *buf2 = strdup(buf); 558 | 559 | if (libxl_cpu_bitmap_alloc(ctx, &b_info->cpumap, 0)) { 560 | fprintf(stderr, "Unable to allocate cpumap\n"); 561 | exit(1); 562 | } 563 | 564 | libxl_bitmap_set_none(&b_info->cpumap); 565 | if (vcpupin_parse(buf2, &b_info->cpumap)) 566 | exit(1); 567 | free(buf2); 568 | 569 | libxl_defbool_set(&b_info->numa_placement, false); 570 | } 571 | 572 | if (!xlu_cfg_get_long (config, "memory", &l, 0)) { 573 | b_info->max_memkb = l * 1024; 574 | b_info->target_memkb = b_info->max_memkb; 575 | } 576 | 577 | if (!xlu_cfg_get_long (config, "maxmem", &l, 0)) 578 | b_info->max_memkb = l * 1024; 579 | 580 | if (xlu_cfg_get_string (config, "on_poweroff", &buf, 0)) 581 | buf = "destroy"; 582 | 583 | if (!parse_action_on_shutdown(buf, &d_config->on_poweroff)) { 584 | fprintf(stderr, "Unknown on_poweroff action \"%s\" specified\n", buf); 585 | exit(1); 586 | } 587 | 588 | if (xlu_cfg_get_string (config, "on_reboot", &buf, 0)) 589 | buf = "restart"; 590 | if (!parse_action_on_shutdown(buf, &d_config->on_reboot)) { 591 | fprintf(stderr, "Unknown on_reboot action \"%s\" specified\n", buf); 592 | exit(1); 593 | } 594 | 595 | if (xlu_cfg_get_string (config, "on_watchdog", &buf, 0)) 596 | buf = "destroy"; 597 | if (!parse_action_on_shutdown(buf, &d_config->on_watchdog)) { 598 | fprintf(stderr, "Unknown on_watchdog action \"%s\" specified\n", buf); 599 | exit(1); 600 | } 601 | 602 | if (xlu_cfg_get_string (config, "on_crash", &buf, 0)) 603 | buf = "destroy"; 604 | if (!parse_action_on_shutdown(buf, &d_config->on_crash)) { 605 | fprintf(stderr, "Unknown on_crash action \"%s\" specified\n", buf); 606 | exit(1); 607 | } 608 | 609 | /* libxl_get_required_shadow_memory() must be called after final values 610 | * (default or specified) for vcpus and memory are set, because the 611 | * calculation depends on those values. */ 612 | b_info->shadow_memkb = !xlu_cfg_get_long(config, "shadow_memory", &l, 0) 613 | ? l * 1024 614 | : libxl_get_required_shadow_memory(b_info->max_memkb, 615 | b_info->max_vcpus); 616 | 617 | xlu_cfg_get_defbool(config, "nomigrate", &b_info->disable_migrate, 0); 618 | 619 | if (!xlu_cfg_get_long(config, "tsc_mode", &l, 1)) { 620 | const char *s = libxl_tsc_mode_to_string(l); 621 | fprintf(stderr, "WARNING: specifying \"tsc_mode\" as an integer is deprecated. " 622 | "Please use the named parameter variant. %s%s%s\n", 623 | s ? "e.g. tsc_mode=\"" : "", 624 | s ? s : "", 625 | s ? "\"" : ""); 626 | 627 | if (l < LIBXL_TSC_MODE_DEFAULT || 628 | l > LIBXL_TSC_MODE_NATIVE_PARAVIRT) { 629 | fprintf(stderr, "ERROR: invalid value %ld for \"tsc_mode\"\n", l); 630 | exit (1); 631 | } 632 | b_info->tsc_mode = l; 633 | } else if (!xlu_cfg_get_string(config, "tsc_mode", &buf, 0)) { 634 | fprintf(stderr, "got a tsc mode string: \"%s\"\n", buf); 635 | if (libxl_tsc_mode_from_string(buf, &b_info->tsc_mode)) { 636 | fprintf(stderr, "ERROR: invalid value \"%s\" for \"tsc_mode\"\n", 637 | buf); 638 | exit (1); 639 | } 640 | } 641 | 642 | if (!xlu_cfg_get_long(config, "rtc_timeoffset", &l, 0)) 643 | b_info->rtc_timeoffset = l; 644 | 645 | if (dom_info && !xlu_cfg_get_long(config, "vncviewer", &l, 0)) { 646 | /* Command line arguments must take precedence over what's 647 | * specified in the configuration file. */ 648 | if (!dom_info->vnc) 649 | dom_info->vnc = l; 650 | } 651 | 652 | xlu_cfg_get_defbool(config, "localtime", &b_info->localtime, 0); 653 | 654 | if (!xlu_cfg_get_long (config, "videoram", &l, 0)) 655 | b_info->video_memkb = l * 1024; 656 | 657 | switch(b_info->type) { 658 | case LIBXL_DOMAIN_TYPE_HVM: 659 | if (!xlu_cfg_get_string (config, "kernel", &buf, 0)) 660 | fprintf(stderr, "WARNING: ignoring \"kernel\" directive for HVM guest. " 661 | "Use \"firmware_override\" instead if you really want a non-default firmware\n"); 662 | 663 | xlu_cfg_replace_string (config, "firmware_override", 664 | &b_info->u.hvm.firmware, 0); 665 | if (!xlu_cfg_get_string(config, "bios", &buf, 0) && 666 | libxl_bios_type_from_string(buf, &b_info->u.hvm.bios)) { 667 | fprintf(stderr, "ERROR: invalid value \"%s\" for \"bios\"\n", 668 | buf); 669 | exit (1); 670 | } 671 | 672 | xlu_cfg_get_defbool(config, "pae", &b_info->u.hvm.pae, 0); 673 | xlu_cfg_get_defbool(config, "apic", &b_info->u.hvm.apic, 0); 674 | xlu_cfg_get_defbool(config, "acpi", &b_info->u.hvm.acpi, 0); 675 | xlu_cfg_get_defbool(config, "acpi_s3", &b_info->u.hvm.acpi_s3, 0); 676 | xlu_cfg_get_defbool(config, "acpi_s4", &b_info->u.hvm.acpi_s4, 0); 677 | xlu_cfg_get_defbool(config, "nx", &b_info->u.hvm.nx, 0); 678 | xlu_cfg_get_defbool(config, "viridian", &b_info->u.hvm.viridian, 0); 679 | xlu_cfg_get_defbool(config, "hpet", &b_info->u.hvm.hpet, 0); 680 | xlu_cfg_get_defbool(config, "vpt_align", &b_info->u.hvm.vpt_align, 0); 681 | 682 | if (!xlu_cfg_get_long(config, "timer_mode", &l, 1)) { 683 | const char *s = libxl_timer_mode_to_string(l); 684 | fprintf(stderr, "WARNING: specifying \"timer_mode\" as an integer is deprecated. " 685 | "Please use the named parameter variant. %s%s%s\n", 686 | s ? "e.g. timer_mode=\"" : "", 687 | s ? s : "", 688 | s ? "\"" : ""); 689 | 690 | if (l < LIBXL_TIMER_MODE_DELAY_FOR_MISSED_TICKS || 691 | l > LIBXL_TIMER_MODE_ONE_MISSED_TICK_PENDING) { 692 | fprintf(stderr, "ERROR: invalid value %ld for \"timer_mode\"\n", l); 693 | exit (1); 694 | } 695 | b_info->u.hvm.timer_mode = l; 696 | } else if (!xlu_cfg_get_string(config, "timer_mode", &buf, 0)) { 697 | if (libxl_timer_mode_from_string(buf, &b_info->u.hvm.timer_mode)) { 698 | fprintf(stderr, "ERROR: invalid value \"%s\" for \"timer_mode\"\n", 699 | buf); 700 | exit (1); 701 | } 702 | } 703 | 704 | xlu_cfg_get_defbool(config, "nestedhvm", &b_info->u.hvm.nested_hvm, 0); 705 | break; 706 | case LIBXL_DOMAIN_TYPE_PV: 707 | { 708 | char *cmdline = NULL; 709 | const char *root = NULL, *extra = ""; 710 | 711 | xlu_cfg_replace_string (config, "kernel", &b_info->u.pv.kernel, 0); 712 | 713 | xlu_cfg_get_string (config, "root", &root, 0); 714 | xlu_cfg_get_string (config, "extra", &extra, 0); 715 | 716 | if (root) { 717 | if (asprintf(&cmdline, "root=%s %s", root, extra) == -1) 718 | cmdline = NULL; 719 | } else { 720 | cmdline = strdup(extra); 721 | } 722 | 723 | if ((root || extra) && !cmdline) { 724 | fprintf(stderr, "Failed to allocate memory for cmdline\n"); 725 | exit(1); 726 | } 727 | 728 | xlu_cfg_replace_string (config, "bootloader", &b_info->u.pv.bootloader, 0); 729 | switch (xlu_cfg_get_list_as_string_list(config, "bootloader_args", 730 | &b_info->u.pv.bootloader_args, 1)) 731 | { 732 | 733 | case 0: break; /* Success */ 734 | case ESRCH: break; /* Option not present */ 735 | case EINVAL: 736 | if (!xlu_cfg_get_string(config, "bootloader_args", &buf, 0)) { 737 | 738 | fprintf(stderr, "WARNING: Specifying \"bootloader_args\"" 739 | " as a string is deprecated. " 740 | "Please use a list of arguments.\n"); 741 | split_string_into_string_list(buf, " \t\n", 742 | &b_info->u.pv.bootloader_args); 743 | } 744 | break; 745 | default: 746 | fprintf(stderr,"xl: Unable to parse bootloader_args.\n"); 747 | exit(-ERROR_FAIL); 748 | } 749 | 750 | if (!b_info->u.pv.bootloader && !b_info->u.pv.kernel) { 751 | fprintf(stderr, "Neither kernel nor bootloader specified\n"); 752 | exit(1); 753 | } 754 | 755 | b_info->u.pv.cmdline = cmdline; 756 | xlu_cfg_replace_string (config, "ramdisk", &b_info->u.pv.ramdisk, 0); 757 | break; 758 | } 759 | default: 760 | abort(); 761 | } 762 | 763 | if (!xlu_cfg_get_list(config, "ioports", &ioports, &num_ioports, 0)) { 764 | b_info->num_ioports = num_ioports; 765 | b_info->ioports = calloc(num_ioports, sizeof(*b_info->ioports)); 766 | if (b_info->ioports == NULL) { 767 | fprintf(stderr, "unable to allocate memory for ioports\n"); 768 | exit(-1); 769 | } 770 | 771 | for (i = 0; i < num_ioports; i++) { 772 | const char *buf2; 773 | char *ep; 774 | uint32_t start, end; 775 | unsigned long ul; 776 | 777 | buf = xlu_cfg_get_listitem (ioports, i); 778 | if (!buf) { 779 | fprintf(stderr, 780 | "xl: Unable to get element #%d in ioport list\n", i); 781 | exit(1); 782 | } 783 | ul = strtoul(buf, &ep, 16); 784 | if (ep == buf) { 785 | fprintf(stderr, "xl: Invalid argument parsing ioport: %s\n", 786 | buf); 787 | exit(1); 788 | } 789 | if (ul >= UINT32_MAX) { 790 | fprintf(stderr, "xl: ioport %lx too big\n", ul); 791 | exit(1); 792 | } 793 | start = end = ul; 794 | 795 | if (*ep == '-') { 796 | buf2 = ep + 1; 797 | ul = strtoul(buf2, &ep, 16); 798 | if (ep == buf2 || *ep != '\0' || start > end) { 799 | fprintf(stderr, 800 | "xl: Invalid argument parsing ioport: %s\n", buf); 801 | exit(1); 802 | } 803 | if (ul >= UINT32_MAX) { 804 | fprintf(stderr, "xl: ioport %lx too big\n", ul); 805 | exit(1); 806 | } 807 | end = ul; 808 | } else if ( *ep != '\0' ) 809 | fprintf(stderr, 810 | "xl: Invalid argument parsing ioport: %s\n", buf); 811 | b_info->ioports[i].first = start; 812 | b_info->ioports[i].number = end - start + 1; 813 | } 814 | } 815 | 816 | if (!xlu_cfg_get_list(config, "irqs", &irqs, &num_irqs, 0)) { 817 | b_info->num_irqs = num_irqs; 818 | b_info->irqs = calloc(num_irqs, sizeof(*b_info->irqs)); 819 | if (b_info->irqs == NULL) { 820 | fprintf(stderr, "unable to allocate memory for ioports\n"); 821 | exit(-1); 822 | } 823 | for (i = 0; i < num_irqs; i++) { 824 | char *ep; 825 | unsigned long ul; 826 | buf = xlu_cfg_get_listitem (irqs, i); 827 | if (!buf) { 828 | fprintf(stderr, 829 | "xl: Unable to get element %d in irq list\n", i); 830 | exit(1); 831 | } 832 | ul = strtoul(buf, &ep, 10); 833 | if (ep == buf) { 834 | fprintf(stderr, 835 | "xl: Invalid argument parsing irq: %s\n", buf); 836 | exit(1); 837 | } 838 | if (ul >= UINT32_MAX) { 839 | fprintf(stderr, "xl: irq %lx too big\n", ul); 840 | exit(1); 841 | } 842 | b_info->irqs[i] = ul; 843 | } 844 | } 845 | 846 | if (!xlu_cfg_get_list (config, "disk", &vbds, 0, 0)) { 847 | d_config->num_disks = 0; 848 | d_config->disks = NULL; 849 | while ((buf = xlu_cfg_get_listitem (vbds, d_config->num_disks)) != NULL) { 850 | libxl_device_disk *disk; 851 | char *buf2 = strdup(buf); 852 | 853 | d_config->disks = (libxl_device_disk *) realloc(d_config->disks, sizeof (libxl_device_disk) * (d_config->num_disks + 1)); 854 | disk = d_config->disks + d_config->num_disks; 855 | parse_disk_config(&config, buf2, disk); 856 | 857 | free(buf2); 858 | d_config->num_disks++; 859 | } 860 | } 861 | 862 | if (!xlu_cfg_get_list (config, "vif", &nics, 0, 0)) { 863 | d_config->num_nics = 0; 864 | d_config->nics = NULL; 865 | while ((buf = xlu_cfg_get_listitem (nics, d_config->num_nics)) != NULL) { 866 | libxl_device_nic *nic; 867 | char *buf2 = strdup(buf); 868 | char *p, *p2; 869 | 870 | d_config->nics = (libxl_device_nic *) realloc(d_config->nics, sizeof (libxl_device_nic) * (d_config->num_nics+1)); 871 | nic = d_config->nics + d_config->num_nics; 872 | libxl_device_nic_init(nic); 873 | nic->devid = d_config->num_nics; 874 | 875 | if (default_vifscript) { 876 | free(nic->script); 877 | nic->script = strdup(default_vifscript); 878 | } 879 | 880 | if (default_bridge) { 881 | free(nic->bridge); 882 | nic->bridge = strdup(default_bridge); 883 | } 884 | 885 | p = strtok(buf2, ","); 886 | if (!p) 887 | goto skip; 888 | do { 889 | while (*p == ' ') 890 | p++; 891 | if ((p2 = strchr(p, '=')) == NULL) 892 | break; 893 | *p2 = '\0'; 894 | if (!strcmp(p, "model")) { 895 | free(nic->model); 896 | nic->model = strdup(p2 + 1); 897 | } else if (!strcmp(p, "mac")) { 898 | char *p3 = p2 + 1; 899 | *(p3 + 2) = '\0'; 900 | nic->mac[0] = strtol(p3, NULL, 16); 901 | p3 = p3 + 3; 902 | *(p3 + 2) = '\0'; 903 | nic->mac[1] = strtol(p3, NULL, 16); 904 | p3 = p3 + 3; 905 | *(p3 + 2) = '\0'; 906 | nic->mac[2] = strtol(p3, NULL, 16); 907 | p3 = p3 + 3; 908 | *(p3 + 2) = '\0'; 909 | nic->mac[3] = strtol(p3, NULL, 16); 910 | p3 = p3 + 3; 911 | *(p3 + 2) = '\0'; 912 | nic->mac[4] = strtol(p3, NULL, 16); 913 | p3 = p3 + 3; 914 | *(p3 + 2) = '\0'; 915 | nic->mac[5] = strtol(p3, NULL, 16); 916 | } else if (!strcmp(p, "bridge")) { 917 | free(nic->bridge); 918 | nic->bridge = strdup(p2 + 1); 919 | } else if (!strcmp(p, "type")) { 920 | if (!strcmp(p2 + 1, "ioemu")) 921 | nic->nictype = LIBXL_NIC_TYPE_VIF_IOEMU; 922 | else 923 | nic->nictype = LIBXL_NIC_TYPE_VIF; 924 | } else if (!strcmp(p, "ip")) { 925 | free(nic->ip); 926 | nic->ip = strdup(p2 + 1); 927 | } else if (!strcmp(p, "script")) { 928 | free(nic->script); 929 | nic->script = strdup(p2 + 1); 930 | } else if (!strcmp(p, "vifname")) { 931 | free(nic->ifname); 932 | nic->ifname = strdup(p2 + 1); 933 | } else if (!strcmp(p, "backend")) { 934 | if(libxl_name_to_domid(ctx, (p2 + 1), &(nic->backend_domid))) { 935 | fprintf(stderr, "Specified backend domain does not exist, defaulting to Dom0\n"); 936 | nic->backend_domid = 0; 937 | } 938 | } else if (!strcmp(p, "rate")) { 939 | parse_vif_rate(&config, (p2 + 1), nic); 940 | } else if (!strcmp(p, "accel")) { 941 | fprintf(stderr, "the accel parameter for vifs is currently not supported\n"); 942 | } 943 | } while ((p = strtok(NULL, ",")) != NULL); 944 | skip: 945 | free(buf2); 946 | d_config->num_nics++; 947 | } 948 | } 949 | 950 | 951 | if (xlu_cfg_replace_string (config, "click", &e_config->click_file, 0)) { 952 | e_config->click_file = NULL; 953 | } 954 | 955 | if (!xlu_cfg_get_list(config, "vif2", NULL, 0, 0)) { 956 | fprintf(stderr, "WARNING: vif2: netchannel2 is deprecated and not supported by xl\n"); 957 | } 958 | 959 | if (!xlu_cfg_get_list (config, "vfb", &cvfbs, 0, 0)) { 960 | d_config->num_vfbs = 0; 961 | d_config->num_vkbs = 0; 962 | d_config->vfbs = NULL; 963 | d_config->vkbs = NULL; 964 | while ((buf = xlu_cfg_get_listitem (cvfbs, d_config->num_vfbs)) != NULL) { 965 | libxl_device_vfb *vfb; 966 | libxl_device_vkb *vkb; 967 | 968 | char *buf2 = strdup(buf); 969 | char *p, *p2; 970 | 971 | d_config->vfbs = (libxl_device_vfb *) realloc(d_config->vfbs, sizeof(libxl_device_vfb) * (d_config->num_vfbs + 1)); 972 | vfb = d_config->vfbs + d_config->num_vfbs; 973 | libxl_device_vfb_init(vfb); 974 | vfb->devid = d_config->num_vfbs; 975 | 976 | d_config->vkbs = (libxl_device_vkb *) realloc(d_config->vkbs, sizeof(libxl_device_vkb) * (d_config->num_vkbs + 1)); 977 | vkb = d_config->vkbs + d_config->num_vkbs; 978 | libxl_device_vkb_init(vkb); 979 | vkb->devid = d_config->num_vkbs; 980 | 981 | p = strtok(buf2, ","); 982 | if (!p) 983 | goto skip_vfb; 984 | do { 985 | while (*p == ' ') 986 | p++; 987 | if ((p2 = strchr(p, '=')) == NULL) 988 | break; 989 | *p2 = '\0'; 990 | if (!strcmp(p, "vnc")) { 991 | libxl_defbool_set(&vfb->vnc.enable, atoi(p2 + 1)); 992 | } else if (!strcmp(p, "vnclisten")) { 993 | free(vfb->vnc.listen); 994 | vfb->vnc.listen = strdup(p2 + 1); 995 | } else if (!strcmp(p, "vncpasswd")) { 996 | free(vfb->vnc.passwd); 997 | vfb->vnc.passwd = strdup(p2 + 1); 998 | } else if (!strcmp(p, "vncdisplay")) { 999 | vfb->vnc.display = atoi(p2 + 1); 1000 | } else if (!strcmp(p, "vncunused")) { 1001 | libxl_defbool_set(&vfb->vnc.findunused, atoi(p2 + 1)); 1002 | } else if (!strcmp(p, "keymap")) { 1003 | free(vfb->keymap); 1004 | vfb->keymap = strdup(p2 + 1); 1005 | } else if (!strcmp(p, "sdl")) { 1006 | libxl_defbool_set(&vfb->sdl.enable, atoi(p2 + 1)); 1007 | } else if (!strcmp(p, "opengl")) { 1008 | libxl_defbool_set(&vfb->sdl.opengl, atoi(p2 + 1)); 1009 | } else if (!strcmp(p, "display")) { 1010 | free(vfb->sdl.display); 1011 | vfb->sdl.display = strdup(p2 + 1); 1012 | } else if (!strcmp(p, "xauthority")) { 1013 | free(vfb->sdl.xauthority); 1014 | vfb->sdl.xauthority = strdup(p2 + 1); 1015 | } 1016 | } while ((p = strtok(NULL, ",")) != NULL); 1017 | skip_vfb: 1018 | free(buf2); 1019 | d_config->num_vfbs++; 1020 | d_config->num_vkbs++; 1021 | } 1022 | } 1023 | 1024 | if (!xlu_cfg_get_long (config, "pci_msitranslate", &l, 0)) 1025 | pci_msitranslate = l; 1026 | 1027 | if (!xlu_cfg_get_long (config, "pci_power_mgmt", &l, 0)) 1028 | pci_power_mgmt = l; 1029 | 1030 | if (!xlu_cfg_get_long (config, "pci_permissive", &l, 0)) 1031 | pci_permissive = l; 1032 | 1033 | /* To be reworked (automatically enabled) once the auto ballooning 1034 | * after guest starts is done (with PCI devices passed in). */ 1035 | if (c_info->type == LIBXL_DOMAIN_TYPE_PV) { 1036 | xlu_cfg_get_defbool(config, "e820_host", &b_info->u.pv.e820_host, 0); 1037 | } 1038 | 1039 | if (!xlu_cfg_get_list (config, "pci", &pcis, 0, 0)) { 1040 | int i; 1041 | d_config->num_pcidevs = 0; 1042 | d_config->pcidevs = NULL; 1043 | for(i = 0; (buf = xlu_cfg_get_listitem (pcis, i)) != NULL; i++) { 1044 | libxl_device_pci *pcidev; 1045 | 1046 | d_config->pcidevs = (libxl_device_pci *) realloc(d_config->pcidevs, sizeof (libxl_device_pci) * (d_config->num_pcidevs + 1)); 1047 | pcidev = d_config->pcidevs + d_config->num_pcidevs; 1048 | libxl_device_pci_init(pcidev); 1049 | 1050 | pcidev->msitranslate = pci_msitranslate; 1051 | pcidev->power_mgmt = pci_power_mgmt; 1052 | pcidev->permissive = pci_permissive; 1053 | if (!xlu_pci_parse_bdf(config, pcidev, buf)) 1054 | d_config->num_pcidevs++; 1055 | } 1056 | if (d_config->num_pcidevs && c_info->type == LIBXL_DOMAIN_TYPE_PV) 1057 | libxl_defbool_set(&b_info->u.pv.e820_host, true); 1058 | } 1059 | 1060 | switch (xlu_cfg_get_list(config, "cpuid", &cpuids, 0, 1)) { 1061 | case 0: 1062 | { 1063 | int i; 1064 | const char *errstr; 1065 | 1066 | for (i = 0; (buf = xlu_cfg_get_listitem(cpuids, i)) != NULL; i++) { 1067 | e = libxl_cpuid_parse_config_xend(&b_info->cpuid, buf); 1068 | switch (e) { 1069 | case 0: continue; 1070 | case 1: 1071 | errstr = "illegal leaf number"; 1072 | break; 1073 | case 2: 1074 | errstr = "illegal subleaf number"; 1075 | break; 1076 | case 3: 1077 | errstr = "missing colon"; 1078 | break; 1079 | case 4: 1080 | errstr = "invalid register name (must be e[abcd]x)"; 1081 | break; 1082 | case 5: 1083 | errstr = "policy string must be exactly 32 characters long"; 1084 | break; 1085 | default: 1086 | errstr = "unknown error"; 1087 | break; 1088 | } 1089 | fprintf(stderr, "while parsing CPUID line: \"%s\":\n", buf); 1090 | fprintf(stderr, " error #%i: %s\n", e, errstr); 1091 | } 1092 | } 1093 | break; 1094 | case EINVAL: /* config option is not a list, parse as a string */ 1095 | if (!xlu_cfg_get_string(config, "cpuid", &buf, 0)) { 1096 | char *buf2, *p, *strtok_ptr = NULL; 1097 | const char *errstr; 1098 | 1099 | buf2 = strdup(buf); 1100 | p = strtok_r(buf2, ",", &strtok_ptr); 1101 | if (p == NULL) { 1102 | free(buf2); 1103 | break; 1104 | } 1105 | if (strcmp(p, "host")) { 1106 | fprintf(stderr, "while parsing CPUID string: \"%s\":\n", buf); 1107 | fprintf(stderr, " error: first word must be \"host\"\n"); 1108 | free(buf2); 1109 | break; 1110 | } 1111 | for (p = strtok_r(NULL, ",", &strtok_ptr); p != NULL; 1112 | p = strtok_r(NULL, ",", &strtok_ptr)) { 1113 | e = libxl_cpuid_parse_config(&b_info->cpuid, p); 1114 | switch (e) { 1115 | case 0: continue; 1116 | case 1: 1117 | errstr = "missing \"=\" in key=value"; 1118 | break; 1119 | case 2: 1120 | errstr = "unknown CPUID flag name"; 1121 | break; 1122 | case 3: 1123 | errstr = "illegal CPUID value (must be: [0|1|x|k|s])"; 1124 | break; 1125 | default: 1126 | errstr = "unknown error"; 1127 | break; 1128 | } 1129 | fprintf(stderr, "while parsing CPUID flag: \"%s\":\n", p); 1130 | fprintf(stderr, " error #%i: %s\n", e, errstr); 1131 | } 1132 | free(buf2); 1133 | } 1134 | break; 1135 | default: 1136 | break; 1137 | } 1138 | 1139 | /* parse device model arguments, this works for pv, hvm and stubdom */ 1140 | if (!xlu_cfg_get_string (config, "device_model", &buf, 0)) { 1141 | fprintf(stderr, 1142 | "WARNING: ignoring device_model directive.\n" 1143 | "WARNING: Use \"device_model_override\" instead if you" 1144 | " really want a non-default device_model\n"); 1145 | if (strstr(buf, "stubdom-dm")) { 1146 | if (c_info->type == LIBXL_DOMAIN_TYPE_HVM) 1147 | fprintf(stderr, "WARNING: Or use" 1148 | " \"device_model_stubdomain_override\" if you " 1149 | " want to enable stubdomains\n"); 1150 | else 1151 | fprintf(stderr, "WARNING: ignoring" 1152 | " \"device_model_stubdomain_override\" directive" 1153 | " for pv guest\n"); 1154 | } 1155 | } 1156 | 1157 | 1158 | xlu_cfg_replace_string (config, "device_model_override", 1159 | &b_info->device_model, 0); 1160 | if (!xlu_cfg_get_string (config, "device_model_version", &buf, 0)) { 1161 | if (!strcmp(buf, "qemu-xen-traditional")) { 1162 | b_info->device_model_version 1163 | = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL; 1164 | } else if (!strcmp(buf, "qemu-xen")) { 1165 | b_info->device_model_version 1166 | = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN; 1167 | } else { 1168 | fprintf(stderr, 1169 | "Unknown device_model_version \"%s\" specified\n", buf); 1170 | exit(1); 1171 | } 1172 | } else if (b_info->device_model) 1173 | fprintf(stderr, "WARNING: device model override given without specific DM version\n"); 1174 | xlu_cfg_get_defbool (config, "device_model_stubdomain_override", 1175 | &b_info->device_model_stubdomain, 0); 1176 | 1177 | if (!xlu_cfg_get_string (config, "device_model_stubdomain_seclabel", 1178 | &buf, 0)) { 1179 | e = libxl_flask_context_to_sid(ctx, (char *)buf, strlen(buf), 1180 | &b_info->device_model_ssidref); 1181 | if (e) { 1182 | if (errno == ENOSYS) { 1183 | fprintf(stderr, "XSM Disabled:" 1184 | " device_model_stubdomain_seclabel not supported\n"); 1185 | } else { 1186 | fprintf(stderr, "Invalid device_model_stubdomain_seclabel:" 1187 | " %s\n", buf); 1188 | exit(1); 1189 | } 1190 | } 1191 | } 1192 | #define parse_extra_args(type) \ 1193 | e = xlu_cfg_get_list_as_string_list(config, "device_model_args"#type, \ 1194 | &b_info->extra##type, 0); \ 1195 | if (e && e != ESRCH) { \ 1196 | fprintf(stderr,"xl: Unable to parse device_model_args"#type".\n");\ 1197 | exit(-ERROR_FAIL); \ 1198 | } 1199 | 1200 | /* parse extra args for qemu, common to both pv, hvm */ 1201 | parse_extra_args(); 1202 | 1203 | /* parse extra args dedicated to pv */ 1204 | parse_extra_args(_pv); 1205 | 1206 | /* parse extra args dedicated to hvm */ 1207 | parse_extra_args(_hvm); 1208 | 1209 | #undef parse_extra_args 1210 | 1211 | if (c_info->type == LIBXL_DOMAIN_TYPE_HVM) { 1212 | if (!xlu_cfg_get_long(config, "stdvga", &l, 0)) 1213 | b_info->u.hvm.vga.kind = l ? LIBXL_VGA_INTERFACE_TYPE_STD : 1214 | LIBXL_VGA_INTERFACE_TYPE_CIRRUS; 1215 | 1216 | xlu_cfg_get_defbool(config, "vnc", &b_info->u.hvm.vnc.enable, 0); 1217 | xlu_cfg_replace_string (config, "vnclisten", 1218 | &b_info->u.hvm.vnc.listen, 0); 1219 | xlu_cfg_replace_string (config, "vncpasswd", 1220 | &b_info->u.hvm.vnc.passwd, 0); 1221 | if (!xlu_cfg_get_long (config, "vncdisplay", &l, 0)) 1222 | b_info->u.hvm.vnc.display = l; 1223 | xlu_cfg_get_defbool(config, "vncunused", 1224 | &b_info->u.hvm.vnc.findunused, 0); 1225 | xlu_cfg_replace_string (config, "keymap", &b_info->u.hvm.keymap, 0); 1226 | xlu_cfg_get_defbool(config, "sdl", &b_info->u.hvm.sdl.enable, 0); 1227 | xlu_cfg_get_defbool(config, "opengl", &b_info->u.hvm.sdl.opengl, 0); 1228 | xlu_cfg_get_defbool (config, "spice", &b_info->u.hvm.spice.enable, 0); 1229 | if (!xlu_cfg_get_long (config, "spiceport", &l, 0)) 1230 | b_info->u.hvm.spice.port = l; 1231 | if (!xlu_cfg_get_long (config, "spicetls_port", &l, 0)) 1232 | b_info->u.hvm.spice.tls_port = l; 1233 | xlu_cfg_replace_string (config, "spicehost", 1234 | &b_info->u.hvm.spice.host, 0); 1235 | xlu_cfg_get_defbool(config, "spicedisable_ticketing", 1236 | &b_info->u.hvm.spice.disable_ticketing, 0); 1237 | xlu_cfg_replace_string (config, "spicepasswd", 1238 | &b_info->u.hvm.spice.passwd, 0); 1239 | xlu_cfg_get_defbool(config, "spiceagent_mouse", 1240 | &b_info->u.hvm.spice.agent_mouse, 0); 1241 | xlu_cfg_get_defbool(config, "nographic", &b_info->u.hvm.nographic, 0); 1242 | xlu_cfg_get_defbool(config, "gfx_passthru", 1243 | &b_info->u.hvm.gfx_passthru, 0); 1244 | xlu_cfg_replace_string (config, "serial", &b_info->u.hvm.serial, 0); 1245 | xlu_cfg_replace_string (config, "boot", &b_info->u.hvm.boot, 0); 1246 | xlu_cfg_get_defbool(config, "usb", &b_info->u.hvm.usb, 0); 1247 | xlu_cfg_replace_string (config, "usbdevice", 1248 | &b_info->u.hvm.usbdevice, 0); 1249 | xlu_cfg_replace_string (config, "soundhw", &b_info->u.hvm.soundhw, 0); 1250 | xlu_cfg_get_defbool(config, "xen_platform_pci", 1251 | &b_info->u.hvm.xen_platform_pci, 0); 1252 | } 1253 | 1254 | xlu_cfg_destroy(config); 1255 | } 1256 | 1257 | static int freemem(libxl_domain_build_info *b_info) 1258 | { 1259 | int rc, retries = 3; 1260 | uint32_t need_memkb, free_memkb; 1261 | 1262 | if (!autoballoon) 1263 | return 0; 1264 | 1265 | rc = libxl_domain_need_memory(ctx, b_info, &need_memkb); 1266 | if (rc < 0) 1267 | return rc; 1268 | 1269 | do { 1270 | rc = libxl_get_free_memory(ctx, &free_memkb); 1271 | if (rc < 0) 1272 | return rc; 1273 | 1274 | if (free_memkb >= need_memkb) 1275 | return 0; 1276 | 1277 | rc = libxl_set_memory_target(ctx, 0, free_memkb - need_memkb, 1, 0); 1278 | if (rc < 0) 1279 | return rc; 1280 | 1281 | rc = libxl_wait_for_free_memory(ctx, domid, need_memkb, 10); 1282 | if (!rc) 1283 | return 0; 1284 | else if (rc != ERROR_NOMEM) 1285 | return rc; 1286 | 1287 | /* the memory target has been reached but the free memory is still 1288 | * not enough: loop over again */ 1289 | rc = libxl_wait_for_memory_target(ctx, 0, 1); 1290 | if (rc < 0) 1291 | return rc; 1292 | 1293 | retries--; 1294 | } while (retries > 0); 1295 | 1296 | return ERROR_NOMEM; 1297 | } 1298 | 1299 | static int domain_wait_event(libxl_event **event_r) 1300 | { 1301 | int ret; 1302 | for (;;) { 1303 | ret = libxl_event_wait(ctx, event_r, LIBXL_EVENTMASK_ALL, 0,0); 1304 | if (ret) { 1305 | fprintf(stderr, "Domain %d, failed to get event, quitting (rc=%d)", domid, ret); 1306 | return ret; 1307 | } 1308 | if ((*event_r)->domid != domid) { 1309 | char *evstr = libxl_event_to_json(ctx, *event_r); 1310 | fprintf(stderr, "Ignoring unexpected event for domain %d (expected %d): event=%s", 1311 | (*event_r)->domid, domid, evstr); 1312 | free(evstr); 1313 | libxl_event_free(ctx, *event_r); 1314 | continue; 1315 | } 1316 | return ret; 1317 | } 1318 | } 1319 | #endif 1320 | 1321 | static void write_domain_config(int fd, 1322 | const char *source, 1323 | const uint8_t *config_data, 1324 | int config_len) 1325 | { 1326 | struct save_file_header hdr; 1327 | uint8_t *optdata_begin; 1328 | union { uint32_t u32; char b[4]; } u32buf; 1329 | 1330 | memset(&hdr, 0, sizeof(hdr)); 1331 | memcpy(hdr.magic, savefileheader_magic, sizeof(hdr.magic)); 1332 | hdr.byteorder = SAVEFILE_BYTEORDER_VALUE; 1333 | 1334 | optdata_begin = 0; 1335 | 1336 | #define ADD_OPTDATA(ptr, len) ({ \ 1337 | if ((len)) { \ 1338 | hdr.optional_data_len += (len); \ 1339 | optdata_begin = realloc(optdata_begin, hdr.optional_data_len); \ 1340 | memcpy(optdata_begin + hdr.optional_data_len - (len), \ 1341 | (ptr), (len)); \ 1342 | } \ 1343 | }) 1344 | 1345 | u32buf.u32 = config_len; 1346 | ADD_OPTDATA(u32buf.b, 4); 1347 | ADD_OPTDATA(config_data, config_len); 1348 | 1349 | /* that's the optional data */ 1350 | 1351 | CHK_ERRNO( libxl_write_exactly(ctx, fd, 1352 | &hdr, sizeof(hdr), source, "header") ); 1353 | CHK_ERRNO( libxl_write_exactly(ctx, fd, 1354 | optdata_begin, hdr.optional_data_len, source, "header") ); 1355 | 1356 | fprintf(stderr, "Saving to %s new xl format (info" 1357 | " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n", 1358 | source, hdr.mandatory_flags, hdr.optional_flags, 1359 | hdr.optional_data_len); 1360 | } 1361 | 1362 | int domain_name_to_id(char *domname) 1363 | { 1364 | uint32_t domid; 1365 | 1366 | if(libxl_name_to_domid(ctx, domname, &domid)) { 1367 | return -EINVAL; 1368 | } 1369 | 1370 | return domid; 1371 | } 1372 | 1373 | int domain_ctx_init(int flags) 1374 | { 1375 | int ret; 1376 | int verbose = flags & 0x01; 1377 | if (verbose) { 1378 | minmsglevel--; 1379 | printf("Setting loglevel to %d\n", minmsglevel); 1380 | } 1381 | 1382 | logger = xtl_createlogger_stdiostream(stderr, minmsglevel, 0); 1383 | if (!logger) 1384 | exit(1); 1385 | 1386 | if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, (xentoollog_logger*)logger)) { 1387 | fprintf(stderr, "cannot init xl context\n"); 1388 | exit(1); 1389 | } 1390 | 1391 | ret = asprintf(&lockfile, "/var/lock/xl"); 1392 | if (ret < 0) { 1393 | fprintf(stderr, "asprintf memory allocation failed\n"); 1394 | exit(1); 1395 | } 1396 | 1397 | return ret; 1398 | } 1399 | 1400 | void domain_ctx_free(void) 1401 | { 1402 | libxl_ctx_free(ctx); 1403 | xtl_logger_destroy((xentoollog_logger*) logger); 1404 | } 1405 | 1406 | int domain_create(struct clickos_domain *dom_info) 1407 | { 1408 | libxl_domain_config d_config; 1409 | clickos_extra_config e_config; 1410 | 1411 | const char *config_file = dom_info->config_file; 1412 | const char *extra_config = dom_info->extra_config; 1413 | const char *restore_file = dom_info->restore_file; 1414 | int migrate_fd = dom_info->migrate_fd; 1415 | 1416 | int i, ret, rc; 1417 | void *config_data = (char*) dom_info->config_data; 1418 | int config_len = 0; 1419 | int restore_fd = -1; 1420 | int status = 0; 1421 | const libxl_asyncprogress_how *autoconnect_console_how; 1422 | pid_t child_console_pid = -1; 1423 | struct save_file_header hdr; 1424 | char *click_script; 1425 | 1426 | libxl_domain_config_init(&d_config); 1427 | 1428 | if (restore_file) { 1429 | uint8_t *optdata_begin = 0; 1430 | const uint8_t *optdata_here = 0; 1431 | union { uint32_t u32; char b[4]; } u32buf; 1432 | uint32_t badflags; 1433 | 1434 | restore_fd = migrate_fd >= 0 ? migrate_fd : 1435 | open(restore_file, O_RDONLY); 1436 | 1437 | CHK_ERRNO( libxl_read_exactly(ctx, restore_fd, &hdr, 1438 | sizeof(hdr), restore_file, "header") ); 1439 | if (memcmp(hdr.magic, savefileheader_magic, sizeof(hdr.magic))) { 1440 | fprintf(stderr, "File has wrong magic number -" 1441 | " corrupt or for a different tool?\n"); 1442 | return ERROR_INVAL; 1443 | } 1444 | if (hdr.byteorder != SAVEFILE_BYTEORDER_VALUE) { 1445 | fprintf(stderr, "File has wrong byte order\n"); 1446 | return ERROR_INVAL; 1447 | } 1448 | fprintf(stderr, "Loading new save file %s" 1449 | " (new xl fmt info" 1450 | " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n", 1451 | restore_file, hdr.mandatory_flags, hdr.optional_flags, 1452 | hdr.optional_data_len); 1453 | 1454 | badflags = hdr.mandatory_flags & ~( 0 /* none understood yet */ ); 1455 | if (badflags) { 1456 | fprintf(stderr, "Savefile has mandatory flag(s) 0x%"PRIx32" " 1457 | "which are not supported; need newer xl\n", 1458 | badflags); 1459 | return ERROR_INVAL; 1460 | } 1461 | if (hdr.optional_data_len) { 1462 | optdata_begin = xmalloc(hdr.optional_data_len); 1463 | CHK_ERRNO( libxl_read_exactly(ctx, restore_fd, optdata_begin, 1464 | hdr.optional_data_len, restore_file, "optdata") ); 1465 | } 1466 | 1467 | #define OPTDATA_LEFT (hdr.optional_data_len - (optdata_here - optdata_begin)) 1468 | #define WITH_OPTDATA(amt, body) \ 1469 | if (OPTDATA_LEFT < (amt)) { \ 1470 | fprintf(stderr, "Savefile truncated.\n"); \ 1471 | return ERROR_INVAL; \ 1472 | } else { \ 1473 | body; \ 1474 | optdata_here += (amt); \ 1475 | } 1476 | 1477 | optdata_here = optdata_begin; 1478 | 1479 | if (OPTDATA_LEFT) { 1480 | fprintf(stderr, " Savefile contains xl domain config\n"); 1481 | WITH_OPTDATA(4, { 1482 | memcpy(u32buf.b, optdata_here, 4); 1483 | config_len = u32buf.u32; 1484 | }); 1485 | WITH_OPTDATA(config_len, { 1486 | config_data = xmalloc(config_len); 1487 | memcpy(config_data, optdata_here, config_len); 1488 | }); 1489 | } 1490 | 1491 | } 1492 | 1493 | if (config_file) { 1494 | free(config_data); config_data = 0; 1495 | ret = libxl_read_file_contents(ctx, config_file, 1496 | &config_data, &config_len); 1497 | if (ret) { fprintf(stderr, "Failed to read config file: %s: %s\n", 1498 | config_file, strerror(errno)); return ERROR_FAIL; } 1499 | if (!restore_file && extra_config && strlen(extra_config)) { 1500 | if (config_len > INT_MAX - (strlen(extra_config) + 2 + 1)) { 1501 | fprintf(stderr, "Failed to attach extra configration\n"); 1502 | return ERROR_FAIL; 1503 | } 1504 | /* allocate space for the extra config plus two EOLs plus \0 */ 1505 | config_data = realloc(config_data, config_len 1506 | + strlen(extra_config) + 2 + 1); 1507 | if (!config_data) { 1508 | fprintf(stderr, "Failed to realloc config_data\n"); 1509 | return ERROR_FAIL; 1510 | } 1511 | config_len += sprintf(config_data + config_len, "\n%s\n", 1512 | extra_config); 1513 | } 1514 | } else { 1515 | if (!config_data) { 1516 | fprintf(stderr, "Config file not specified and" 1517 | " none in save file\n"); 1518 | return ERROR_INVAL; 1519 | } 1520 | config_file = ""; 1521 | config_len = strlen(config_data); 1522 | } 1523 | 1524 | //fprintf(stderr, "%s\n", config_data); 1525 | 1526 | if (!dom_info->quiet) 1527 | printf("Parsing config file %s\n", config_file); 1528 | 1529 | e_config.click_file = NULL; 1530 | click_script = NULL; 1531 | 1532 | parse_config_data(config_file, config_data, config_len, &d_config, dom_info, &e_config); 1533 | 1534 | if (migrate_fd >= 0) { 1535 | if (d_config.c_info.name) { 1536 | /* when we receive a domain we get its name from the config 1537 | * file; and we receive it to a temporary name */ 1538 | assert(!common_domname); 1539 | 1540 | common_domname = d_config.c_info.name; 1541 | d_config.c_info.name = 0; /* steals allocation from config */ 1542 | 1543 | if (asprintf(&d_config.c_info.name, 1544 | "%s--incoming", common_domname) < 0) { 1545 | fprintf(stderr, "Failed to allocate memory in asprintf\n"); 1546 | exit(1); 1547 | } 1548 | *dom_info->migration_domname_r = strdup(d_config.c_info.name); 1549 | } 1550 | } 1551 | 1552 | ret = 0; 1553 | 1554 | domid = -1; 1555 | 1556 | rc = acquire_lock(); 1557 | if (rc < 0) 1558 | goto error_out; 1559 | 1560 | ret = freemem(&d_config.b_info); 1561 | if (ret < 0) { 1562 | fprintf(stderr, "failed to free memory for the domain\n"); 1563 | ret = ERROR_FAIL; 1564 | goto error_out; 1565 | } 1566 | 1567 | autoconnect_console_how = 0; 1568 | 1569 | if ( restore_file ) { 1570 | #if XEN_VERSION >= 40400 1571 | libxl_domain_restore_params params; 1572 | params.checkpointed_stream = 0; 1573 | #endif 1574 | ret = libxl_domain_create_restore(ctx, &d_config, 1575 | &domid, restore_fd, 1576 | #if XEN_VERSION >= 40400 1577 | ¶ms, 1578 | #endif 1579 | 0, autoconnect_console_how); 1580 | }else{ 1581 | ret = libxl_domain_create_new(ctx, &d_config, &domid, 1582 | 0, autoconnect_console_how); 1583 | } 1584 | 1585 | if ( ret ) { 1586 | perror("error creating domain"); 1587 | goto error_out; 1588 | } 1589 | 1590 | /* If single vcpu to pcpu mapping was requested, honour it */ 1591 | if (vcpu_to_pcpu) { 1592 | libxl_bitmap vcpu_cpumap; 1593 | 1594 | ret = libxl_cpu_bitmap_alloc(ctx, &vcpu_cpumap, 0); 1595 | if (ret) 1596 | goto error_out; 1597 | for (i = 0; i < d_config.b_info.max_vcpus; i++) { 1598 | 1599 | if (vcpu_to_pcpu[i] != -1) { 1600 | libxl_bitmap_set_none(&vcpu_cpumap); 1601 | libxl_bitmap_set(&vcpu_cpumap, vcpu_to_pcpu[i]); 1602 | } else { 1603 | libxl_bitmap_set_any(&vcpu_cpumap); 1604 | } 1605 | if (libxl_set_vcpuaffinity(ctx, domid, i, &vcpu_cpumap)) { 1606 | fprintf(stderr, "setting affinity failed on vcpu `%d'.\n", i); 1607 | libxl_bitmap_dispose(&vcpu_cpumap); 1608 | free(vcpu_to_pcpu); 1609 | ret = ERROR_FAIL; 1610 | goto error_out; 1611 | } 1612 | } 1613 | libxl_bitmap_dispose(&vcpu_cpumap); 1614 | free(vcpu_to_pcpu); vcpu_to_pcpu = NULL; 1615 | } 1616 | 1617 | 1618 | ret = libxl_userdata_store(ctx, domid, "xl", 1619 | config_data, config_len); 1620 | if (ret) { 1621 | perror("cannot save config file"); 1622 | ret = ERROR_FAIL; 1623 | goto error_out; 1624 | } 1625 | 1626 | release_lock(); 1627 | 1628 | if (!dom_info->paused) 1629 | libxl_domain_unpause(ctx, domid); 1630 | 1631 | if (e_config.click_file != NULL) { 1632 | click_script = clickos_read_script(e_config.click_file); 1633 | } 1634 | 1635 | if (click_script) { 1636 | clickos_start(domid, d_config.c_info.name, click_script); 1637 | } 1638 | 1639 | ret = domid; /* caller gets success in parent */ 1640 | 1641 | goto out; 1642 | 1643 | error_out: 1644 | release_lock(); 1645 | if (libxl_domid_valid_guest(domid)) 1646 | libxl_domain_destroy(ctx, domid, 0); 1647 | 1648 | if (logfile != 2) 1649 | close(logfile); 1650 | out: 1651 | libxl_domain_config_dispose(&d_config); 1652 | 1653 | free(config_data); 1654 | 1655 | waitpid_out: 1656 | if (child_console_pid > 0 && 1657 | waitpid(child_console_pid, &status, 0) < 0 && errno == EINTR) 1658 | goto waitpid_out; 1659 | 1660 | return ret; 1661 | 1662 | } 1663 | 1664 | int domain_destroy(int _domid, int force) 1665 | { 1666 | int rc; 1667 | libxl_event *event; 1668 | libxl_evgen_domain_death *deathw; 1669 | 1670 | domid = _domid; 1671 | 1672 | if (!libxl_domid_valid_guest(domid)) 1673 | return -EINVAL; 1674 | 1675 | if (force) { 1676 | rc = libxl_domain_destroy(ctx, domid, 0); 1677 | return rc; 1678 | } 1679 | 1680 | rc = libxl_domain_shutdown(ctx, domid); 1681 | if (rc) 1682 | fprintf(stderr, "shutdown failed (rc=%d)\n", rc); 1683 | 1684 | rc = libxl_evenable_domain_death(ctx, domid, 0, &deathw); 1685 | if (rc) { 1686 | fprintf(stderr,"wait for death failed (evgen, rc=%d)\n",rc); 1687 | exit(-1); 1688 | } 1689 | 1690 | for (;;) { 1691 | rc = domain_wait_event(&event); 1692 | if (rc) exit(-1); 1693 | 1694 | switch (event->type) { 1695 | 1696 | case LIBXL_EVENT_TYPE_DOMAIN_DEATH: 1697 | goto done; 1698 | 1699 | case LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN: 1700 | rc = libxl_domain_destroy(ctx, domid, 0); 1701 | break; 1702 | 1703 | default: 1704 | fprintf(stderr, "Unexpected event type %d", event->type); 1705 | break; 1706 | } 1707 | libxl_event_free(ctx, event); 1708 | } 1709 | done: 1710 | libxl_event_free(ctx, event); 1711 | libxl_evdisable_domain_death(ctx, deathw); 1712 | 1713 | return rc; 1714 | } 1715 | 1716 | int domain_suspend(const int domid, const char *filename) 1717 | { 1718 | int rc; 1719 | int fd; 1720 | uint8_t *config_data; 1721 | int config_len; 1722 | 1723 | rc = libxl_userdata_retrieve(ctx, domid, "xl", &config_data, &config_len); 1724 | 1725 | if (rc) { 1726 | fputs("Unable to get config file\n",stderr); 1727 | exit(2); 1728 | } 1729 | 1730 | if (!config_len) { 1731 | fputs(" Savefile will not contain xl domain config\n", stderr); 1732 | } 1733 | 1734 | fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644); 1735 | if (fd < 0) { 1736 | fprintf(stderr, "Failed to open temp file %s for writing\n", filename); 1737 | exit(2); 1738 | } 1739 | 1740 | write_domain_config(fd, filename, config_data, config_len); 1741 | 1742 | MUST(libxl_domain_suspend(ctx, domid, fd, 0, NULL)); 1743 | close(fd); 1744 | 1745 | libxl_domain_destroy(ctx, domid, 0); 1746 | 1747 | return 0; 1748 | } 1749 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cosmos 3 | * 4 | * file: main.c 5 | * 6 | * NEC Europe Ltd. PROPRIETARY INFORMATION 7 | * 8 | * This software is supplied under the terms of a license agreement 9 | * or nondisclosure agreement with NEC Europe Ltd. and may not be 10 | * copied or disclosed except in accordance with the terms of that 11 | * agreement. The software and its source code contain valuable trade 12 | * secrets and confidential information which have to be maintained in 13 | * confidence. 14 | * Any unauthorized publication, transfer to third parties or duplication 15 | * of the object or source code - either totally or in part – is 16 | * prohibited. 17 | * 18 | * Copyright (c) 2014 NEC Europe Ltd. All Rights Reserved. 19 | * 20 | * Authors: Joao Martins 21 | * Filipe Manco 22 | * 23 | * NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, 24 | * INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY 25 | * AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT 26 | * DEFECTS, WITH RESPECT TO THE PROGRAM AND THE ACCOMPANYING 27 | * DOCUMENTATION. 28 | * 29 | * No Liability For Consequential Damages IN NO EVENT SHALL NEC Europe 30 | * Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE LIABLE FOR ANY 31 | * DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS 32 | * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR 33 | * OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL, 34 | * ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY 35 | * TO USE THIS PROGRAM, EVEN IF NEC Europe Ltd. HAS BEEN ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGES. 37 | * 38 | * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 39 | */ 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | #ifdef HAVE_XL 55 | # include 56 | # include 57 | # include 58 | #endif 59 | 60 | #include "clickos.h" 61 | 62 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 63 | 64 | #ifdef HAVE_XL 65 | extern libxl_ctx *ctx; 66 | #endif 67 | 68 | struct cmd_struct { 69 | const char *cmd; 70 | int (*fn)(int, char **); 71 | }; 72 | 73 | const char cosmos_usage_string[] = 74 | #ifdef HAVE_XL 75 | "cosmos [-v] [create|load|destroy|start|stop|suspend|resume|write|read] []"; 76 | #else 77 | "cosmos [-v] [create|destroy|start|stop|suspend|resume|write|read] []"; 78 | #endif 79 | 80 | const char cosmos_more_info_string[] = 81 | "See 'cosmos help ' for more information on a specific command."; 82 | 83 | int cmd_help(int argc, char **argv); 84 | int cmd_create(int argc, char **argv); 85 | #ifdef HAVE_XL 86 | int cmd_load(int argc, char **argv); 87 | #endif 88 | int cmd_start(int argc, char **argv); 89 | int cmd_stop(int argc, char **argv); 90 | int cmd_destroy(int argc, char **argv); 91 | int cmd_suspend(int argc, char **argv); 92 | int cmd_resume(int argc, char **argv); 93 | int cmd_read_h(int argc, char **argv); 94 | int cmd_write_h(int argc, char **argv); 95 | 96 | static struct cmd_struct commands[] = { 97 | { "create", cmd_create }, 98 | #ifdef HAVE_XL 99 | { "load", cmd_load }, 100 | #endif 101 | { "destroy", cmd_destroy }, 102 | { "suspend", cmd_suspend }, 103 | { "resume", cmd_resume }, 104 | { "start", cmd_start }, 105 | { "stop", cmd_stop }, 106 | { "read", cmd_read_h }, 107 | { "write", cmd_write_h }, 108 | { "help", cmd_help }, 109 | }; 110 | 111 | static int report_timing; 112 | static struct timeval tic, toc; 113 | 114 | static inline void timing_record(struct timeval *t) 115 | { 116 | if (report_timing) { 117 | gettimeofday(t, NULL); 118 | } 119 | } 120 | 121 | static inline void timing_report(struct timeval *tic, struct timeval *toc, char *msg_fmt) 122 | { 123 | if (report_timing) { 124 | timersub(toc, tic, toc); 125 | double diff = toc->tv_sec + 1e-6 * toc->tv_usec; 126 | 127 | timerclear(tic); 128 | timerclear(toc); 129 | printf(msg_fmt, diff); 130 | } 131 | } 132 | 133 | #define TRACE(msg, fn) \ 134 | do { \ 135 | timing_record(&tic); \ 136 | fn \ 137 | timing_record(&toc); \ 138 | timing_report(&tic, &toc, msg); \ 139 | } while(0) 140 | 141 | 142 | int cmd_help(int argc, char **argv) 143 | { 144 | return 0; 145 | } 146 | 147 | int cmd_create(int argc, char **argv) 148 | { 149 | const char *filename = NULL; 150 | char extra_config[1024]; 151 | struct clickos_domain dom_info; 152 | int paused = 0, quiet = 0; 153 | int opt, domid; 154 | int option_index = 0; 155 | static struct option long_options[] = { 156 | {"quiet", 0, 0, 'q'}, 157 | {"defconfig", 1, 0, 'f'}, 158 | {0, 0, 0, 0} 159 | }; 160 | 161 | if (argv[1] && argv[1][0] != '-' && !strchr(argv[1], '=')) { 162 | filename = argv[1]; 163 | argc--; 164 | argv++; 165 | } 166 | 167 | while (1) { 168 | opt = getopt_long(argc, argv, "qf:p", long_options, &option_index); 169 | if (opt == -1) 170 | break; 171 | 172 | switch (opt) { 173 | case 'f': 174 | filename = optarg; 175 | break; 176 | case 'p': 177 | paused = 1; 178 | break; 179 | case 'q': 180 | quiet = 1; 181 | break; 182 | default: 183 | fprintf(stderr, "option `%c' not supported.\n", optopt); 184 | break; 185 | } 186 | } 187 | 188 | extra_config[0] = '\0'; 189 | filename = argv[optind - 1]; 190 | 191 | memset(&dom_info, 0, sizeof(struct clickos_domain)); 192 | dom_info.quiet = quiet; 193 | dom_info.paused = paused; 194 | dom_info.config_file = filename; 195 | dom_info.config_data = 0; 196 | dom_info.click_file = NULL; 197 | dom_info.extra_config = extra_config; 198 | dom_info.migrate_fd = -1; 199 | 200 | TRACE("Created domain in %f s\n", domid = clickos_create2(&dom_info);); 201 | 202 | if (domid < 0) 203 | return 1; 204 | 205 | return 0; 206 | } 207 | 208 | int cmd_destroy(int argc, char **argv) 209 | { 210 | int domid, force = 0; 211 | int opt, option_index = 0; 212 | static struct option long_options[] = { 213 | {"force", 0, 0, 'f'}, 214 | {0, 0, 0, 0} 215 | }; 216 | 217 | while (1) { 218 | opt = getopt_long(argc, argv, "f", long_options, &option_index); 219 | if (opt == -1) 220 | break; 221 | 222 | switch (opt) { 223 | case 'f': 224 | fprintf(stderr, "option -f enabled.\n"); 225 | force = 1; 226 | break; 227 | default: 228 | fprintf(stderr, "option `%c' not supported.\n", optopt); 229 | break; 230 | } 231 | } 232 | 233 | if (!(domid = strtol(argv[optind], NULL, 10))) 234 | domid = clickos_domid(argv[optind]); 235 | 236 | TRACE("Destroyed domain in %f s\n", clickos_destroy(domid, force);); 237 | 238 | return 0; 239 | } 240 | 241 | #ifdef HAVE_XL 242 | static unsigned get_file_size(const char * file_name) 243 | { 244 | struct stat sb; 245 | if (stat(file_name, &sb) != 0) { 246 | fprintf (stderr, "'stat' failed for '%s': %s.\n", 247 | file_name, strerror(errno)); 248 | exit(EXIT_FAILURE); 249 | } 250 | return sb.st_size; 251 | } 252 | 253 | int cmd_load(int argc, char **argv) 254 | { 255 | int domid, pid; 256 | int len, i; 257 | char *buf, args[1024]; 258 | const char *wspace=" "; 259 | FILE *fp; 260 | 261 | if (argc < 2) { 262 | fprintf(stderr, "Must specify a valid XEN configuration.\n"); 263 | return -EINVAL; 264 | } 265 | 266 | argc = argc - 1; 267 | args[0] = '\0'; 268 | 269 | for (i = 2; i <= argc; ++i) { 270 | strcat(args, argv[i]); 271 | strcat(args, wspace); 272 | } 273 | 274 | len = get_file_size(argv[1]); 275 | buf = malloc(len + 1); 276 | 277 | fp = fopen(argv[1], "r"); 278 | fread(buf, sizeof(unsigned char), len, fp); 279 | fclose(fp); 280 | 281 | domid = clickos_create3(buf, args); 282 | fprintf(stderr, "Created Domain with ID %d\n", domid); 283 | 284 | pid = fork(); 285 | if (pid) { 286 | while ((pid = waitpid(-1, NULL, 0)) > 0) { 287 | if (errno == ECHILD) { 288 | break; 289 | } 290 | } 291 | libxl_domain_destroy(ctx, domid, 0); 292 | } 293 | else 294 | { 295 | clickos_global_init(4); 296 | libxl_primary_console_exec(ctx, domid); 297 | } 298 | return 0; 299 | } 300 | #endif 301 | 302 | int cmd_suspend(int argc, char **argv) 303 | { 304 | int domid; 305 | 306 | if (argc != 3) { 307 | fprintf(stderr, "Usage: cosmos suspend \n"); 308 | return -EINVAL; 309 | } 310 | 311 | if (!(domid = strtol(argv[1], NULL, 10))) 312 | domid = clickos_domid(argv[1]); 313 | 314 | if (domid == -EINVAL) { 315 | fprintf(stderr, "Invalid domain identifier: %s\n", argv[2]); 316 | return -EINVAL; 317 | } 318 | 319 | TRACE("Suspended domain in %f s\n", clickos_suspend(domid, argv[2]);); 320 | 321 | return 0; 322 | } 323 | 324 | int cmd_resume(int argc, char **argv) 325 | { 326 | char *filename = NULL; 327 | char extra_config[1024]; 328 | struct clickos_domain dom_info; 329 | int paused = 0, quiet = 0; 330 | int opt, domid; 331 | int option_index = 0; 332 | static struct option long_options[] = { 333 | {"quiet", 0, 0, 'q'}, 334 | {0, 0, 0, 0} 335 | }; 336 | 337 | if (argv[1] && argv[1][0] != '-' && !strchr(argv[1], '=')) { 338 | filename = argv[1]; 339 | argc--; 340 | argv++; 341 | } 342 | 343 | while (1) { 344 | opt = getopt_long(argc, argv, "qf:p", long_options, &option_index); 345 | if (opt == -1) 346 | break; 347 | 348 | switch (opt) { 349 | case 'f': 350 | filename = optarg; 351 | break; 352 | case 'p': 353 | paused = 1; 354 | break; 355 | case 'q': 356 | quiet = 1; 357 | break; 358 | default: 359 | fprintf(stderr, "option `%c' not supported.\n", optopt); 360 | break; 361 | } 362 | } 363 | 364 | extra_config[0] = '\0'; 365 | filename = argv[optind - 1]; 366 | 367 | memset(&dom_info, 0, sizeof(struct clickos_domain)); 368 | dom_info.quiet = quiet; 369 | dom_info.paused = paused; 370 | dom_info.config_file = NULL; 371 | dom_info.config_data = 0; 372 | dom_info.click_file = NULL; 373 | dom_info.extra_config = extra_config; 374 | dom_info.migrate_fd = -1; 375 | dom_info.restore_file = filename; 376 | 377 | TRACE("Resumed domain in %f seconds\n", domid = clickos_create2(&dom_info);); 378 | 379 | if (domid < 0) 380 | return 1; 381 | 382 | return 0; 383 | } 384 | 385 | #define parse_h_args(id,elem,attr) \ 386 | if (!(id = strtol(argv[1], NULL, 10))) \ 387 | id = clickos_domid(argv[1]); \ 388 | elem = argv[2]; \ 389 | attr = argv[3]; \ 390 | 391 | 392 | int cmd_read_h(int argc, char **argv) 393 | { 394 | int domid; 395 | char *elem, *attr, *value; 396 | 397 | parse_h_args(domid, elem, attr); 398 | 399 | value = clickos_read_handler(domid, elem, attr); 400 | printf("read(%s/%s) => %s\n", elem, attr, value); 401 | 402 | return 0; 403 | } 404 | 405 | int cmd_write_h(int argc, char **argv) 406 | { 407 | int domid; 408 | char *elem, *attr, *value; 409 | 410 | parse_h_args(domid, elem, attr); 411 | value = argv[4]; 412 | 413 | clickos_write_handler(domid, elem, attr, value); 414 | printf("write(%s/%s, %s)\n", elem, attr, value); 415 | 416 | return 0; 417 | } 418 | 419 | int cmd_start(int argc, char **argv) 420 | { 421 | char *script, *script_path; 422 | int opt, domid; 423 | int option_index = 0; 424 | static struct option long_options[] = { 425 | {"autoattach", 0, 0, 'a'}, 426 | {0, 0, 0, 0} 427 | }; 428 | 429 | if (argv[1] && argv[1][0] != '-') { 430 | argc--; 431 | argv++; 432 | } 433 | 434 | while (1) { 435 | opt = getopt_long(argc, argv, "ax", long_options, &option_index); 436 | if (opt == -1) 437 | break; 438 | 439 | switch (opt) { 440 | default: 441 | fprintf(stderr, "option `%c' not supported.\n", optopt); 442 | break; 443 | } 444 | } 445 | 446 | if ((argc - optind + 1) != 2) { 447 | fprintf(stderr, "wrong number of arguments (expected 2, got %d).\n", 448 | ((argc - optind) <= 0 ? 0 : (argc - optind))); 449 | return -EINVAL; 450 | } 451 | 452 | domid = clickos_domid(argv[optind - 1]); 453 | script_path = argv[optind]; 454 | 455 | fprintf(stderr, "Domain ID for %s: %d\n", argv[optind - 1], domid); 456 | fprintf(stderr, "Location of click script: %s\n", script_path); 457 | 458 | script = clickos_read_script(script_path); 459 | clickos_start(domid, "script", script); 460 | return 0; 461 | } 462 | 463 | int cmd_stop(int argc, char **argv) 464 | { 465 | int domid, configid; 466 | 467 | if (!(domid = strtol(argv[1], NULL, 10))) 468 | domid = clickos_domid(argv[1]); 469 | 470 | configid = atoi(argv[2]); 471 | 472 | clickos_stop(domid, configid); 473 | 474 | return 0; 475 | } 476 | 477 | int main(int argc, char **argv) 478 | { 479 | int i; 480 | int opt = 0, verbose=0; 481 | int ret; 482 | 483 | report_timing = 0; 484 | 485 | while ((opt = getopt(argc, argv, "+v+xt")) >= 0) { 486 | switch (opt) { 487 | case 'v': 488 | verbose = 1; 489 | break; 490 | case 't': 491 | report_timing = 1; 492 | break; 493 | default: 494 | fprintf(stderr, "unknown global option\n"); 495 | exit(2); 496 | } 497 | } 498 | 499 | opterr = 0; 500 | 501 | /* Reset options for per-command use of getopt. */ 502 | argv += optind; 503 | argc -= optind; 504 | optind = 1; 505 | 506 | if (argc == 0) { 507 | printf("usage: %s\n\n", cosmos_usage_string); 508 | printf("\n%s\n", cosmos_more_info_string); 509 | exit(1); 510 | } 511 | 512 | clickos_global_init(verbose); 513 | 514 | for (i = 0; i < ARRAY_SIZE(commands); i++) { 515 | struct cmd_struct *p = commands + i; 516 | if (strcmp(p->cmd, *argv)) 517 | continue; 518 | 519 | ret = p->fn(argc, argv); 520 | } 521 | 522 | clickos_global_free(); 523 | 524 | return ret; 525 | } 526 | -------------------------------------------------------------------------------- /src/xcl/xcl_dom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Xen control light 3 | * 4 | * file: xcl_dom.c 5 | * 6 | * NEC Europe Ltd. PROPRIETARY INFORMATION 7 | * 8 | * This software is supplied under the terms of a license agreement 9 | * or nondisclosure agreement with NEC Europe Ltd. and may not be 10 | * copied or disclosed except in accordance with the terms of that 11 | * agreement. The software and its source code contain valuable trade 12 | * secrets and confidential information which have to be maintained in 13 | * confidence. 14 | * Any unauthorized publication, transfer to third parties or duplication 15 | * of the object or source code - either totally or in part – is 16 | * prohibited. 17 | * 18 | * Copyright (c) 2014 NEC Europe Ltd. All Rights Reserved. 19 | * 20 | * Authors: Joao Martins 21 | * 22 | * NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, 23 | * INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY 24 | * AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT 25 | * DEFECTS, WITH RESPECT TO THE PROGRAM AND THE ACCOMPANYING 26 | * DOCUMENTATION. 27 | * 28 | * No Liability For Consequential Damages IN NO EVENT SHALL NEC Europe 29 | * Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE LIABLE FOR ANY 30 | * DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS 31 | * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR 32 | * OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL, 33 | * ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY 34 | * TO USE THIS PROGRAM, EVEN IF NEC Europe Ltd. HAS BEEN ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGES. 36 | * 37 | * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 38 | */ 39 | #include 40 | #include 41 | 42 | #include 43 | 44 | #define XCL_MAXMEM 1024 45 | static xentoollog_level minmsglevel = XTL_PROGRESS; 46 | static xentoollog_logger_stdiostream *lg; 47 | struct xcl_ctx *ctx; 48 | xs_transaction_t t; 49 | 50 | static void __xcl_dom_pin(struct xcl_dominfo *info) 51 | { 52 | int max_cpus, l; 53 | xc_cpumap_t map; 54 | 55 | max_cpus = xc_get_max_cpus(ctx->xch); 56 | 57 | /* Set 'any cpu' on invalid option */ 58 | if (info->pcpu > max_cpus) 59 | info->pcpu = 0; 60 | 61 | l = (max_cpus + 7)/8; 62 | 63 | map = malloc(l * sizeof(*map)); 64 | memset(map, 0, l*sizeof(*map)); 65 | 66 | map[info->pcpu / 8] |= 1 << (info->pcpu % 8); 67 | 68 | xc_vcpu_setaffinity(ctx->xch, info->domid, 0, map); 69 | 70 | free(map); 71 | } 72 | 73 | void xcl_ctx_init() 74 | { 75 | xentoollog_logger *l; 76 | if (!lg) 77 | lg = xtl_createlogger_stdiostream(stderr, minmsglevel, 0); 78 | 79 | l = (xentoollog_logger*) lg; 80 | ctx = malloc(sizeof(struct xcl_ctx)); 81 | memset(ctx, 0, sizeof(struct xcl_ctx)); 82 | 83 | ctx->xch = xc_interface_open(l,l,0); 84 | if (!ctx->xch) 85 | LOGE("cannot open libxc handle"); 86 | 87 | ctx->xsh = xs_daemon_open(); 88 | if (!ctx->xsh) 89 | ctx->xsh = xs_domain_open(); 90 | if (!ctx->xsh) { 91 | LOGE("cannot connect to xenstore"); 92 | exit(1); 93 | } 94 | } 95 | 96 | void xcl_ctx_dispose() 97 | { 98 | if (ctx->xch) 99 | xc_interface_close(ctx->xch); 100 | 101 | if (ctx->xsh) 102 | xs_daemon_close(ctx->xsh); 103 | 104 | if (lg) { 105 | xtl_logger_destroy((xentoollog_logger*)lg); 106 | lg = NULL; 107 | } 108 | 109 | } 110 | 111 | void xcl_pre(struct xcl_dominfo *info, struct xcl_domstate *state) 112 | { 113 | char *dom_path, *vm_path; 114 | char *domid_val; 115 | struct xs_permissions roperm[2]; 116 | struct xs_permissions rwperm[1]; 117 | 118 | roperm[0].id = 0; 119 | roperm[0].perms = XS_PERM_NONE; 120 | roperm[1].id = info->domid; 121 | roperm[1].perms = XS_PERM_READ; 122 | 123 | rwperm[0].id = info->domid; 124 | rwperm[0].perms = XS_PERM_NONE; 125 | 126 | retry_transaction: 127 | t = xs_transaction_start(ctx->xsh); 128 | 129 | dom_path = xs_get_domain_path(ctx->xsh, info->domid); 130 | 131 | { 132 | char *control_path, *shutdown_path, *clickos_path, *clickos_shutdown_path; 133 | asprintf(&clickos_path, "%s/data/clickos", dom_path); 134 | asprintf(&control_path, "%s/control", dom_path); 135 | asprintf(&shutdown_path, "%s/control/shutdown", dom_path); 136 | 137 | xs_mkdir(ctx->xsh, t, shutdown_path); 138 | xs_set_permissions(ctx->xsh, t, shutdown_path, rwperm, 1); 139 | xs_set_permissions(ctx->xsh, t, control_path, roperm, 2); 140 | 141 | asprintf(&clickos_shutdown_path, "%s/data/clickos/shutdown", dom_path); 142 | xs_mkdir(ctx->xsh, t, clickos_shutdown_path); 143 | xs_set_permissions(ctx->xsh, t, clickos_shutdown_path, rwperm, 1); 144 | xs_set_permissions(ctx->xsh, t, clickos_path, rwperm, 1); 145 | } 146 | 147 | 148 | asprintf(&vm_path, "/vm/%s", (char *) info->uuid_string); 149 | __xswritek(dom_path, "vm", vm_path); 150 | 151 | __xswritek(vm_path, "uuid", info->uuid_string); 152 | __xswritek(vm_path, "name", info->name); 153 | xs_set_permissions(ctx->xsh, t, vm_path, roperm, 2); 154 | 155 | __xswritek(dom_path, "name", info->name); 156 | xs_set_permissions(ctx->xsh, t, dom_path, roperm, 2); 157 | 158 | asprintf(&domid_val, "%u", info->domid); 159 | __xswritek(dom_path, "domid", domid_val); 160 | 161 | if (!xs_transaction_end(ctx->xsh, t, 0)) { 162 | if (errno == EAGAIN) { 163 | goto retry_transaction; 164 | } 165 | } 166 | } 167 | 168 | void xcl_post(struct xcl_dominfo *info, struct xcl_domstate *state) 169 | { 170 | struct xs_permissions rwperm[1]; 171 | char *dom_path, *console_path; 172 | char *port_val, *mfn_val; 173 | 174 | rwperm[0].id = info->domid; 175 | rwperm[0].perms = XS_PERM_NONE; 176 | 177 | dom_path = xs_get_domain_path(ctx->xsh, info->domid); 178 | 179 | retry_console: 180 | t = xs_transaction_start(ctx->xsh); 181 | 182 | asprintf(&console_path, "%s/console", dom_path); 183 | xs_mkdir(ctx->xsh, t, console_path); 184 | xs_set_permissions(ctx->xsh, t, console_path, rwperm, 1); 185 | 186 | asprintf(&port_val, "%u", state->console_port); 187 | __xswritek(console_path, "port", port_val); 188 | asprintf(&mfn_val, "%lu", state->console_mfn); 189 | __xswritek(console_path, "ring-ref", mfn_val); 190 | 191 | if (!xs_transaction_end(ctx->xsh, t, 0)) { 192 | if (errno == EAGAIN) { 193 | goto retry_console; 194 | } 195 | } 196 | 197 | if (state->nr_nics) { 198 | xcl_net_attach(info->domid, state->nr_nics, state->nics); 199 | } 200 | } 201 | 202 | #define TSC_MODE_NATIVE 2 203 | #define TSC_MODE_NATIVE_PARAVIRT 3 204 | 205 | void xcl_dom_create(struct xcl_dominfo *info) 206 | { 207 | struct xcl_domstate *state = info->state; 208 | struct xc_dom_image *dom; 209 | int ret; 210 | int flags = 0, tsc_mode = TSC_MODE_NATIVE_PARAVIRT; 211 | uint32_t domid = -1; 212 | 213 | xen_domain_handle_t handle; 214 | 215 | uuid_generate(info->uuid); 216 | info->uuid_string = uuid_to_str(info->uuid); 217 | 218 | if (info->pvh) { 219 | #if XEN_VERSION >= 40400 220 | flags |= XEN_DOMCTL_CDF_pvh_guest; 221 | flags |= XEN_DOMCTL_CDF_hap; 222 | tsc_mode = TSC_MODE_NATIVE; 223 | info->slack_memkb = 0; 224 | #else 225 | LOG("PVH mode supported only for Xen >= 4.4.0"); 226 | info->pvh = 0; 227 | #endif 228 | } 229 | 230 | 231 | ret = xc_domain_create(ctx->xch, 0, handle, flags, &domid); 232 | info->domid = domid; 233 | 234 | ret = xc_cpupool_movedomain(ctx->xch, 0, domid); 235 | xc_domain_max_vcpus(ctx->xch, domid, info->max_vcpus); 236 | __xcl_dom_pin(info); 237 | 238 | /* pre */ 239 | xcl_pre(info, state); 240 | 241 | xc_domain_setmaxmem(ctx->xch, domid, info->target_memkb + XCL_MAXMEM); 242 | state->store_port = xc_evtchn_alloc_unbound(ctx->xch, domid, state->store_domid); 243 | state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, state->console_domid); 244 | xc_domain_set_memmap_limit(ctx->xch, domid, (info->max_memkb + info->slack_memkb)); 245 | xc_domain_set_tsc_info(ctx->xch, domid, tsc_mode, 0, 0, 0); 246 | if (info->pvh) { 247 | info->features = "writable_descriptor_tables|" 248 | "auto_translated_physmap|" 249 | "supervisor_mode_kernel|" 250 | "hvm_callback_vector"; 251 | } 252 | 253 | /* build */ 254 | xc_dom_loginit(ctx->xch); 255 | 256 | dom = (struct xc_dom_image*) xc_dom_allocate(ctx->xch, state->cmdline, info->features); 257 | dom->flags = flags; 258 | dom->console_evtchn = state->console_port; 259 | dom->console_domid = state->console_domid; 260 | dom->xenstore_evtchn = state->store_port; 261 | dom->xenstore_domid = state->store_domid; 262 | #if XEN_VERSION >= 40400 263 | dom->pvh_enabled = info->pvh; 264 | #endif 265 | 266 | /* We can also map the image size - could be useful to 267 | * avoid always reading from a filei (e.g using xxd) 268 | */ 269 | //ret = xc_dom_kernel_mem(dom, state->pv_kernel.data, state->pv_kernel.size); 270 | ret = xc_dom_kernel_file(dom, state->kernel_path); 271 | ret = xc_dom_boot_xen_init(dom, ctx->xch, domid); 272 | ret = xc_dom_parse_image(dom); 273 | ret = xc_dom_mem_init(dom, info->target_memkb / 1024); 274 | ret = xc_dom_boot_mem_init(dom); 275 | ret = xc_dom_build_image(dom); 276 | ret = xc_dom_boot_image(dom); 277 | ret = xc_dom_gnttab_init(dom); 278 | 279 | if (info->pvh) { 280 | state->console_mfn = dom->console_pfn; 281 | state->store_mfn = dom->xenstore_pfn; 282 | } else { 283 | state->console_mfn = xc_dom_p2m_host(dom, dom->console_pfn); 284 | state->store_mfn = xc_dom_p2m_host(dom, dom->xenstore_pfn); 285 | } 286 | 287 | xc_dom_release(dom); 288 | 289 | /* post */ 290 | xcl_post(info, state); 291 | xs_introduce_domain(ctx->xsh, domid, state->store_mfn, state->store_port); 292 | 293 | ret = xc_domain_unpause(ctx->xch, domid); 294 | (void) (ret); 295 | } 296 | 297 | #define INFOLIST_MAX_DOMAINS 1024 298 | int xcl_dom_id(char *name) 299 | { 300 | int sz = INFOLIST_MAX_DOMAINS; 301 | xc_domaininfo_t info[sz]; 302 | char path[strlen("/local/domain") + 20]; 303 | void *s; 304 | int i, rc; 305 | rc = xc_domain_getinfolist(ctx->xch, 1, sz, info); 306 | 307 | rc = -ENOENT; 308 | for(i=0; ixsh); 335 | dom_path = xs_get_domain_path(ctx->xsh, domid); 336 | asprintf(&shutdown_path, "%s/control", dom_path); 337 | __xswritek(shutdown_path, "shutdown", "poweroff"); 338 | if (!xs_transaction_end(ctx->xsh, t, 0)) { 339 | if (errno == EAGAIN) 340 | goto retry_shutdown; 341 | } 342 | 343 | do { 344 | xc_domain_getinfolist(ctx->xch, domid, 1, &info); 345 | shutdown = !!(info.flags & XEN_DOMINF_dying) || 346 | !!(info.flags & XEN_DOMINF_shutdown); 347 | usleep(5E3); 348 | --retries; 349 | } while (!shutdown && retries); 350 | 351 | if (shutdown) 352 | xcl_dom_destroy(domid); 353 | } 354 | 355 | void xcl_dom_destroy(int domid) 356 | { 357 | int rc, nr_devs; 358 | char *dom_path, *dom_vm_path, *vm_path; 359 | 360 | if (xc_domain_pause(ctx->xch, domid) < 0) 361 | LOG("error unpausing domain %d", domid); 362 | 363 | nr_devs = xcl_net_nrdevs(domid); 364 | for(int i = 0; i < nr_devs; ++i) { 365 | xcl_net_detach(domid, i); 366 | } 367 | 368 | if (xc_domain_destroy(ctx->xch, domid) < 0) 369 | LOG("error destroying domain %d", domid); 370 | 371 | dom_path = xs_get_domain_path(ctx->xsh, domid); 372 | asprintf(&dom_vm_path, "%s/vm", dom_path); 373 | vm_path = __xsread(dom_vm_path); 374 | 375 | do { 376 | t = xs_transaction_start(ctx->xsh); 377 | xs_rm(ctx->xsh, t, dom_path); 378 | xs_rm(ctx->xsh, t, vm_path); 379 | rc = xs_transaction_end(ctx->xsh, t, 0); 380 | } while (!rc && errno == EAGAIN); 381 | 382 | xs_release_domain(ctx->xsh, domid); 383 | } 384 | -------------------------------------------------------------------------------- /src/xcl/xcl_net.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Xen control light 3 | * 4 | * file: xcl_net.c 5 | * 6 | * NEC Europe Ltd. PROPRIETARY INFORMATION 7 | * 8 | * This software is supplied under the terms of a license agreement 9 | * or nondisclosure agreement with NEC Europe Ltd. and may not be 10 | * copied or disclosed except in accordance with the terms of that 11 | * agreement. The software and its source code contain valuable trade 12 | * secrets and confidential information which have to be maintained in 13 | * confidence. 14 | * Any unauthorized publication, transfer to third parties or duplication 15 | * of the object or source code - either totally or in part – is 16 | * prohibited. 17 | * 18 | * Copyright (c) 2014 NEC Europe Ltd. All Rights Reserved. 19 | * 20 | * Authors: Joao Martins 21 | * 22 | * NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, 23 | * INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY 24 | * AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT 25 | * DEFECTS, WITH RESPECT TO THE PROGRAM AND THE ACCOMPANYING 26 | * DOCUMENTATION. 27 | * 28 | * No Liability For Consequential Damages IN NO EVENT SHALL NEC Europe 29 | * Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE LIABLE FOR ANY 30 | * DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS 31 | * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR 32 | * OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL, 33 | * ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY 34 | * TO USE THIS PROGRAM, EVEN IF NEC Europe Ltd. HAS BEEN ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGES. 36 | * 37 | * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 38 | */ 39 | #include "xcl.h" 40 | #include "xcl_util.h" 41 | 42 | static void xennet_create_fe(int domid, int handle, char *macaddr, int backend_id, 43 | char *type) 44 | { 45 | char *basename_path = NULL; 46 | char *fe_path = NULL; 47 | char *be_path = NULL; 48 | char *backend_id_str = NULL; 49 | int devid = handle; 50 | char *devid_str = NULL; 51 | char *addr = (!macaddr ? "00:00:00:00:00:00" : macaddr); 52 | struct xs_permissions frontend_perms[2]; 53 | 54 | frontend_perms[0].id = domid; 55 | frontend_perms[0].perms = XS_PERM_NONE; 56 | frontend_perms[1].id = backend_id; 57 | frontend_perms[1].perms = XS_PERM_READ; 58 | 59 | asprintf(&basename_path, "/local/domain/%d/device/%s", domid, type); 60 | asprintf(&fe_path, "%s/%d", basename_path, devid); 61 | asprintf(&be_path, "/local/domain/%d/backend/%s/%d/%d", 62 | backend_id, type, domid, devid); 63 | asprintf(&devid_str, "%d", devid); 64 | retry_frontend: 65 | // Transaction for the vale ring attach 66 | t = xs_transaction_start(ctx->xsh); 67 | 68 | xs_mkdir(ctx->xsh, t, fe_path); 69 | xs_set_permissions(ctx->xsh, t, fe_path, frontend_perms, 2); 70 | 71 | __xswritek(fe_path, "backend", be_path); 72 | 73 | asprintf(&backend_id_str, "%d", backend_id); 74 | __xswritek(fe_path, "backend-id", backend_id_str); 75 | __xswritek(fe_path, "state", "1"); 76 | __xswritek(fe_path, "handle", devid_str); 77 | __xswritek(fe_path, "mac", addr); 78 | 79 | if (!xs_transaction_end(ctx->xsh, t, 0)) { 80 | if (errno == EAGAIN) 81 | goto retry_frontend; 82 | } 83 | } 84 | 85 | static void xennet_create_bk(int domid, int handle, char *macaddr, int backend_id, 86 | struct xcl_device_nic *vif) 87 | { 88 | char *bridge = vif->bridge; 89 | char *basename_path = NULL, 90 | *be_path = NULL, *be_state_path = NULL, 91 | *fe_path = NULL, *fe_id_str = NULL, 92 | *devid_str = NULL; 93 | int devid = handle; 94 | char *addr = (macaddr == NULL ? "00:00:00:00:00:00" : macaddr); 95 | struct xs_permissions backend_perms[2]; 96 | 97 | backend_perms[0].id = backend_id; 98 | backend_perms[0].perms = XS_PERM_NONE; 99 | backend_perms[1].id = domid; 100 | backend_perms[1].perms = XS_PERM_READ; 101 | 102 | asprintf(&basename_path, "/local/domain/%d/backend/%s/%d", 103 | backend_id, vif->type, domid); 104 | asprintf(&be_path, "%s/%d", basename_path, devid); 105 | asprintf(&be_state_path, "%s/state", be_path); 106 | asprintf(&fe_path, "/local/domain/%d/device/%s/%d", domid, 107 | vif->type, devid); 108 | asprintf(&fe_id_str, "%d", domid); 109 | asprintf(&devid_str, "%d", devid); 110 | 111 | retry_backend: 112 | // Transaction for the vale ring attach 113 | t = xs_transaction_start(ctx->xsh); 114 | __xswrite(basename_path, ""); 115 | xs_set_permissions(ctx->xsh, t, basename_path, backend_perms, 2); 116 | 117 | __xswritek(be_path, "frontend", fe_path); 118 | __xswritek(be_path, "frontend-id", fe_id_str); 119 | __xswritek(be_path, "online", "1"); 120 | 121 | if (bridge) { 122 | __xswritek(be_path, "bridge", bridge); 123 | } 124 | 125 | if (!strcmp(vif->type,"vif")) { 126 | __xswritek(be_path, "script", vif->script); 127 | __xswritek(be_path, "type", vif->type); 128 | __xswritek(be_path, "hotplug-status", ""); 129 | } 130 | 131 | __xswritek(be_path, "handle", devid_str); 132 | __xswritek(be_path, "mac", addr); 133 | 134 | // Backend reacts here 135 | __xswrite(be_state_path, "1"); 136 | 137 | if (!xs_transaction_end(ctx->xsh, t, 0)) { 138 | if (errno == EAGAIN) 139 | goto retry_backend; 140 | } 141 | } 142 | 143 | static void do_hotplug(const char *arg0, char *const args[], char *const env[]) 144 | { 145 | int i; 146 | for (i = 0; env[i] != NULL && env[i+1] != NULL; i += 2) { 147 | if (setenv(env[i], env[i+1], 1) < 0) { 148 | LOGE("setting env vars (%s = %s)", 149 | env[i], env[i+1]); 150 | goto out; 151 | } 152 | } 153 | 154 | xcl_ctx_dispose(); 155 | execvp(arg0, args); 156 | out: 157 | LOGE("cannot call hotplug script %s: %s\n", arg0, strerror(errno)); 158 | exit(-1); 159 | } 160 | 161 | #define WATCHDOG_WAIT_TIME 5000 162 | static void xennet_watchdog(char *path, const char *expected) 163 | { 164 | int watchdog = 0; 165 | while (watchdog < 100) { 166 | char *buf = __xsread(path); 167 | if (buf == NULL) { 168 | if (errno == ENOENT) 169 | break; 170 | } 171 | 172 | if (!strcmp(buf, expected)) { 173 | NLOG("hotplug connected"); 174 | break; 175 | } else { 176 | usleep(WATCHDOG_WAIT_TIME); 177 | watchdog++; 178 | } 179 | } 180 | } 181 | 182 | static void xennet_hotplug(int domid, int handle, char *script, char *type, int online) 183 | { 184 | char *dev_path, *state_path, *vif_name; 185 | const char *expected = online ? "connected" : "disconnected"; 186 | char **args = malloc(4*sizeof(char *)); 187 | char **env = malloc(15*sizeof(char *)); 188 | pid_t pid; 189 | int nr = 0, argnr = 0; 190 | 191 | asprintf(&dev_path, "backend/%s/%u/%d", type, domid, handle); 192 | asprintf(&state_path, "%s/hotplug-status", dev_path); 193 | asprintf(&vif_name, "vif%u.%u", domid, handle); 194 | 195 | args[argnr++] = script; 196 | args[argnr++] = online ? "online" : "offline"; 197 | args[argnr++] = "type_if=vif"; 198 | args[argnr++] = NULL; 199 | 200 | env[nr++] = "script"; 201 | env[nr++] = script; 202 | env[nr++] = "XENBUS_TYPE"; 203 | env[nr++] = type; 204 | env[nr++] = "XENBUS_PATH"; 205 | env[nr++] = dev_path; 206 | env[nr++] = "XENBUS_BASE_PATH"; 207 | env[nr++] = "backend"; 208 | env[nr++] = "netdev"; 209 | env[nr++] = ""; 210 | env[nr++] = "vif"; 211 | env[nr++] = vif_name; 212 | env[nr++] = NULL; 213 | 214 | pid = fork(); 215 | 216 | if (pid == -1) { 217 | LOGE("cannot fork: %s", strerror(errno)); 218 | exit(0); 219 | } 220 | 221 | if (!pid) { /* child */ 222 | do_hotplug(args[0], args, env); 223 | } 224 | 225 | if (online) 226 | xennet_watchdog(state_path, expected); 227 | } 228 | 229 | void xcl_net_attach(int domid, int nr_nics, struct xcl_device_nic *nics) 230 | { 231 | int i; 232 | 233 | for (i = 0; i < nr_nics; ++i) { 234 | struct xcl_device_nic *nic = &nics[i]; 235 | 236 | xennet_create_fe(domid, i, nic->mac, nic->backend_domid, 237 | nic->type); 238 | xennet_create_bk(domid, i, nic->mac, nic->backend_domid, 239 | nic); 240 | xennet_hotplug(domid, i, nic->script, nic->type, 1); 241 | } 242 | } 243 | 244 | int xcl_net_nrdevs(int domid) 245 | { 246 | int backend_domid = 0, nr_devs = 0, i; 247 | char *vif_path, *buf; 248 | 249 | for (i=0; i<64; i++) { 250 | asprintf(&vif_path, "/local/domain/%d/backend/vif/%d/%d", 251 | backend_domid, domid, i); 252 | buf = __xsreadk(vif_path, "state"); 253 | if (!buf) 254 | break; 255 | ++nr_devs; 256 | } 257 | 258 | return nr_devs; 259 | } 260 | 261 | void xcl_net_detach(int domid, int devid) 262 | { 263 | char *buf; 264 | char *vif_path, *vif_err_path, *vif_fe_path; 265 | int backend_domid = 0, rc; 266 | 267 | asprintf(&vif_path, "/local/domain/%d/backend/vif/%d/%d", 268 | backend_domid, domid, devid); 269 | buf = __xsreadk(vif_path, "state"); 270 | if (!buf) 271 | return; 272 | 273 | buf = __xsreadk(vif_path, "bridge"); 274 | 275 | if (!strncmp("vale", buf, 4)) { 276 | xennet_hotplug(domid, devid, 277 | __xsreadk(vif_path, "script"), 278 | __xsreadk(vif_path, "type"), 279 | 0); 280 | } 281 | 282 | asprintf(&vif_path, "/local/domain/%d/backend/vif/%d/%d", 283 | backend_domid, domid, devid); 284 | asprintf(&vif_err_path, "/local/domain/%d/error/backend/vif/%d", 285 | backend_domid, domid); 286 | asprintf(&vif_fe_path, "/local/domain/%d/device/vif/%d", 287 | domid, devid); 288 | 289 | do { 290 | t = xs_transaction_start(ctx->xsh); 291 | xs_rm(ctx->xsh, t, vif_fe_path); 292 | rc = xs_transaction_end(ctx->xsh, t, 0); 293 | } while (!rc && errno == EAGAIN); 294 | 295 | do { 296 | t = xs_transaction_start(ctx->xsh); 297 | xs_rm(ctx->xsh, t, vif_path); 298 | xs_rm(ctx->xsh, t, vif_err_path); 299 | rc = xs_transaction_end(ctx->xsh, t, 0); 300 | } while (!rc && errno == EAGAIN); 301 | } 302 | -------------------------------------------------------------------------------- /tests/api.js: -------------------------------------------------------------------------------- 1 | var cosmos = require('../build/Release/cosmos') 2 | , fs = require('fs'); 3 | 4 | flags = 0; 5 | 6 | cosmos.ctx(flags); 7 | 8 | // Create a VM 9 | console.time('create'); 10 | domid = cosmos.create_default("test", 11 | "/root/click/clickos/build/click_os_x86_64"); 12 | console.timeEnd('create'); 13 | 14 | // Attaches a virtual interface 15 | console.time('network-attach'); 16 | cosmos.network_attach(domid, "11:22:33:44:55:66", 0, ""); 17 | console.timeEnd('network-attach'); 18 | 19 | fs.readFile("./etc/click/elements/idle.click", function(err, click_script){ 20 | 21 | // Instantiates a middlebox 22 | console.time('start') 23 | cosmos.start(domid, "script", click_script+""); 24 | console.timeEnd('start') 25 | }); 26 | 27 | function destroy() { 28 | cosmos.destroy(domid); 29 | cosmos.free(); 30 | } 31 | 32 | setTimeout(destroy, 2000); 33 | -------------------------------------------------------------------------------- /tests/api.py: -------------------------------------------------------------------------------- 1 | import cosmos 2 | import time 3 | import os 4 | import subprocess, commands 5 | 6 | def isvmalive(name): 7 | cmd = "xl list | grep \"%s\" | grep \"sc\"" % name 8 | domid = cosmos.domid(name) 9 | ret, output = commands.getstatusoutput(cmd) 10 | print output 11 | if len(output) > 0: 12 | return domid 13 | return 0 14 | 15 | xen_config = "./etc/xen/test.cfg"; 16 | #click_script = open("./etc/click/pingresponder.click").read(); 17 | click_script = open("./etc/click/elements/idle.click").read(); 18 | #click_script = open("./etc/click/elements/fromnetfront.click").read(); 19 | 20 | flags = 0; 21 | 22 | # Initializes a context for cosmos with verbose enabled. 23 | # consists of a bitmask which 24 | # 0x01 = enable verbose 25 | # 0x10 = enable autoattach in clickos_start 26 | cosmos.ctx(flags) 27 | 28 | start = time.time() 29 | 30 | # Create the domain 31 | #domid = cosmos.create(xen_config); 32 | 33 | # Create the domain with and 34 | # plus default options 35 | domid = cosmos.create_default("test", "/root/click/clickos/build/click_os_x86_64") 36 | 37 | stop = time.time() 38 | creation_time = stop - start; 39 | 40 | # Network attach for vm with 41 | #cosmos.network_attach(domid, "00:11:22:33:44:66", 0, "ixgbe.52.1") 42 | start = time.time() 43 | cosmos.network_attach(domid, "11:22:33:44:55:66", 0, "") 44 | stop = time.time() 45 | attach_time = stop - start; 46 | 47 | #print "VALE Port: %s" % cosmos.vport(domid, 0) 48 | 49 | start = time.time() 50 | # Start the domain 51 | cosmos.start(domid, "script", click_script); 52 | stop = time.time() 53 | start_time = stop - start; 54 | 55 | time.sleep(0.5); 56 | #time.sleep(7); 57 | print "Alive? " 58 | print "\033[32mYes\033[0m" if not isvmalive("test") else "\033[31mNo\033[0m"; 59 | 60 | # Destroy the domain 61 | if cosmos.destroy(domid) < 0: 62 | print "Domain invalid" 63 | 64 | print "Creation time: %f" % creation_time 65 | print "Attach time: %f" % attach_time 66 | print "Start time: %f" % start_time 67 | 68 | # Frees the context 69 | cosmos.free() 70 | -------------------------------------------------------------------------------- /tests/bootperf.py: -------------------------------------------------------------------------------- 1 | import cosmos 2 | import time 3 | import os, subprocess, commands 4 | import sys 5 | 6 | def isvmalive(name): 7 | cmd = "xl list | grep \"%s\" | grep \"sc\"" % name 8 | domid = cosmos.domid(name) 9 | ret, output = commands.getstatusoutput(cmd) 10 | time.sleep(1.) 11 | print output 12 | if len(output) > 0: 13 | return domid 14 | return 0 15 | 16 | #click_script = open("/root/cosmos/etc/click/elements/idle.click").read(); 17 | click_script = open("/root/cosmos/etc/click/pingresponder.click").read(); 18 | domids = [] 19 | creation_time = [] 20 | attach_time = [] 21 | start_time = [] 22 | flags = 0; 23 | 24 | # Initializes a context for cosmos with verbose enabled. 25 | # consists of a bitmask which 26 | # 0x01 = enable verbose 27 | # 0x10 = enable autoattach in clickos_start 28 | cosmos.ctx(flags) 29 | 30 | for i in range(int(sys.argv[1])): 31 | name = "test%d" % i 32 | # Create the domain 33 | #domid = cosmos.create(xen_config); 34 | 35 | # Create the domain with and 36 | # plus default options 37 | start = time.time() 38 | domid = cosmos.create_default(name, "/root/click/clickos/build/click_os_x86_64") 39 | stop = time.time() 40 | creation_time.append(stop - start); 41 | 42 | # Network attach for vm with 43 | start = time.time() 44 | cosmos.network_attach(domid, "11:22:33:44:55:66", 0, "") 45 | stop = time.time() 46 | attach_time.append(stop - start); 47 | domids.append(domid) 48 | #print "VALE Port: %s" % cosmos.vport(domid, 0) 49 | 50 | for i in range(int(sys.argv[1])): 51 | domid = domids[i] 52 | print "Click : %s" % click_script 53 | start = time.time() 54 | # Start the domain 55 | cosmos.start(domid, "script", click_script); 56 | stop = time.time() 57 | start_time.append(stop - start); 58 | print "Alive? " 59 | print "\033[32mYes\033[0m" if not isvmalive(name) else "\033[31mNo\033[0m"; 60 | 61 | raw_input() 62 | 63 | for i in range(int(sys.argv[1])): 64 | id = domids[i] 65 | # Destroy the domain 66 | if cosmos.destroy(id) < 0: 67 | print "Domain invalid" 68 | 69 | print "Creation time: %f" % creation_time[i] 70 | print "Attach time: %f" % attach_time[i] 71 | print "Start time: %f" % start_time[i] 72 | 73 | 74 | # Frees the context 75 | cosmos.free() 76 | --------------------------------------------------------------------------------